TL; DR;
99,9% van de webdevelopersgeloof dat het correct gebruik van een RDBMS, samen met transacties, hun toepassingen beschermt tegen slechte data en ernstige datafouten. Ze hebben SCHRIJNEND ONGERECHT.
Ik las met grote belangstelling het uitstekende artikel van Kyle Kingsbury over het consistentiemodel van Mongo op https://aphyr.com/posts/322-call-me-maybe-mongodb-stale-reads
Dit is duidelijk een zeer scherpzinnige man die zijn ding kent. Hij doet het werk en alles aan dit artikel is inzichtelijk en goed samengesteld.
Wat ik echter verbazingwekkend vond, waren de reacties en wat ze vertellen over de gemiddelde professionele ontwikkelaar:
Ontwikkelaars denken dat het gebruik van een RDBMS hun data veilig maakt en ze hebben volkomen ongelijk
Ik kan je niet vertellen hoe vaak ik in discussie ben gegaan met 'professionele' ontwikkelaars en vooral domme systeembeheerders die echt geloven dat, door eenvoudigweg het woord RDBMS te zeggen, een kip drie keer rond je hoofd te draaien en verbinding te maken met de magische eenhoorn van DBs, hun data veilig en betrouwbaar zal zijn, je weet al, ... (iets iets over) ... banktransacties en al die (nonsens) klets over transacties en fsync. En een heleboel andere dingen die geen enkele ontwikkelaar die ik ooit heb ontmoet echt begrijpt of heeft overwogen in de context van een HTTP-toepassing (tip: stateless).
Voor ik verderga, wil ik een uitdaging uitbrengen:
- Stuur me je GitHub-naam
- Laat me een MySQL- of PostgreSQL-toepassing kiezen die je hebt geschreven (zodat je het niet kunt voorbereiden)
- En ik zal binnen één dag codepaden vinden die zowel read-uncommitted als dirty-reads leveren in je app
- Als er geen zijn, betaal ik je $1000 dollar
- Als er enige zijn, mag ik elke foto van jou die ik kies als bijlage aan dit artikel posten. Photoshop is toegestaan.
Vind me @ /contact of /team/ara-t-howard. Nu verder...
Raad eens ontwikkelaar: wat is er mis met deze code:
@db.transaction do
if no_user_exists_with_conditions?
@user = make_that_user_exists_with_those_conditions!
deliver_an_activation_email_to!(@user)
end
end
Laat me iets aardschokkends aan je onthullen:
DEZE CODE IS TOTAAL KAPOT OP ELKE BELANGRIJKE RDBMS, EN VIRTUEEL ELKE
TOEPASSING IN DE WERELD
Ik verzeker je dat de e-mail twee keer wordt verzonden.
Het uitleggen van transacties valt buiten het bereik van dit artikel, maar laat me je voorstellen aan 'phantom reads'
http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Phantom_reads
In de bovenstaande code kan een tweede, gelijktijdige transactie het volgende veroorzaken:
@db.transaction do
if no_user_exists_with_conditions?
# ondertussen heeft een 2e transactie een dubbele gebruiker gemaakt...
# het volgende zal slagen in __beide__ transacties
@user = make_that_user_exists_with_those_conditions!
# beide transacties zullen de e-mail verzenden
deliver_an_activation_email_to!(@user)
end
end
# een van de transacties zal mislukken om te committen en met een *BOEM* te ontploffen, maar dan is het
# te laat: de e-mail is tweemaal verzonden en de fout is gemaakt
Ik weet, ik weet, je kunt het niet geloven. Maar dat is alleen omdat je nooit je hebt bekommerd om de RTFM te lezen als het gaat om wat 'transactie' betekent. Begin hier:
http://www.postgresql.org/docs/9.1/static/transaction-iso.html
Let op dat kleine tabel. Laat me het voor je vertalen:
-
Omdat jij niet elke enkele reeks van lees&schrijf in een transactie hebt verpakt, en soms gewoon code tegen je ORM-objecten gooit, lijdt u onder de 'schrikwekkende' realiteit van 'read-uncommitted' genoemd in het artikel
-
Omdat jij vertrouwt op het standaardisolatieniveau, lijdt u aan zowel non-repeatable-reads als phantom reads. (Weet jij zelfs wat het standaard isolatieniveau voor je db is en wat dat betekent????)
-
Omdat jij je transactieniveau niet hebt ingesteld op 'serialiseerbaar', gelooft u ten onrechte dat uw database snel en veilig is. Je hebt ten onrechte op de database vertrouwd om data-integriteit te bieden als een abstractie die geen kritisch denken en toepassingscode vereist die ten minste 10 keer beter is dan de jouwe. Je hebt alle angstaanjagende functies uit het artikel van Kyle in je RDBMS-apps - en, niet alleen weet je dit niet, je bent vrijwel zeker dat je data 'veilig' is
En ik vraag je dan welke een slechtere technische keuze is:
-
Kies een op standaarden gebaseerd hulpmiddel dat iedereen zeer zeker van is dat ze begrijpen en weten hoe ze het veilig kunnen gebruiken, maar waarvan in de algemene toepassing bijna nooit wordt gegarandeerd wat ze denken dat het belooft, en verder is het breed bekritiseerd als ambigu en onnauwkeurige semantiek te hebben?
-
Of om toe te geven wat altijd waar is geweest: dat databases op zichzelf geen abstracties kunnen bieden die betekenen dat niet-extreem-slimme ontwikkelaars geen triviale dingen kunnen verzuilen. En dat data-integriteit een domeinspecifiek concept is dat op de toepassingslaag moet worden geïmplementeerd, waarbij slechts een klein deel van die integriteit wordt ondersteund door de keuze van de database.
ps. Ik heb gewerkt aan grote financiële, realtime en HA-systemen die zowel Mongo als PostgreSQL gebruiken. Het is verdomd moeilijk op beide manieren.
pss. Ik probeerde te reageren op je blog, Kyle, maar de reacties bliezen op ;-)