TL; DR;
99.9% розробників веб-додатків вважають, що правильне використання СУБД і транзакцій захищає їхні додатки від поганих даних і серйозних помилок якості даних. Вони ЦІЛКОМ НЕПРАВІ.
Я з великим інтересом прочитав чудову статтю Кайла Кінгсбері про модель консистенції Mongo на https://aphyr.com/posts/322-call-me-maybe-mongodb-stale-reads
Очевидно, що цей хлопець дуже розумний і знає, про що говорить. Він робить справу, і все в цій статті є цікавим і добре складеним.
Але мене здивували коментарі та те, що вони розповідають про середнього професійного розробника:
Розробники вважають, що використання СУБД робить їхні дані безпечними, і вони абсолютно неправі
Я не можу сказати, скільки разів я вступав у суперечки з "професійними" розробниками та особливо з дурними сисадмінами, які справді вірять, що, просто кажучи слово СУБД, обертаючи курку три рази навколо голови та підключаючись до магічного єдинорога баз даних, їхні дані будуть безпечні та цілі, як ви знаєте, ... (щось-щось про) ... банківські транзакції та все той (нсенс) розмов про транзакції та fsync. І ціла купа іншого, про що жоден розробник, якого я коли-небудь зустрічав, насправді не розуміє чи не розглядав у контексті HTTP-додатку (підказка: безстановий).
Перш ніж продовжити, я викидаю виклик:
- Надішліть мені свій обліковий запис GitHub
- Дозвольте мені вибрати додаток, який працює на MySQL або PostgreSQL, який ви написали (щоб ви не могли його підготувати)
- І я знайду шляхи коду, які забезпечують як читання непідтверджених, так і брудних читань у вашому додатку протягом 1 дня
- Якщо їх немає, я заплачу вам $1000 доларів
- Якщо буде хоча б одне, я зможу опублікувати будь-яке зображення, яке я оберу, як додаток до цієї статті. Дозволяється Photoshop.
Знайдіть мене на /contact або /team/ara-t-howard. Тепер продовжуймо...
Розгадай мені, розробнику: що не так з цим шляхом коду:
@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
Дозвольте мені розповісти вам щось, що зруйнує ваш світ:
ЦЕЙ КОД ЗОВСІМ ЗЛАМАНИЙ НА ВСІХ ОСНОВНИХ СУБД, ТА ПРАКТИЧНО ВСІХ
ДОДАТКАХ, У СВІТІ
Я запевняю вас, що лист піде двічі.
Пояснення транзакцій виходить за межі цієї статті, але дозвольте мені представити вам "фантомні читання"
http://uk.wikipedia.org/wiki/Isolation_%28database_systems%29#Phantom_reads
У вищенаведеному коді друга паралельна транзакція може спричинити наступне:
@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
# одна з транзакцій не вдасться та вибухне, але до того часу,
# буде запізніло: лист буде відправлено двічі, а помилка вже відбулася
Я знаю, ви не можете в це повірити. Але це лише тому, що ви ніколи не потрудилися прочитати інструкцію щодо того, що означає "транзакція". Почніть тут:
http://www.postgresql.org/docs/9.1/static/transaction-iso.html
Зверніть увагу на цю маленьку таблицю. Дозвольте мені перекласти її для вас:
-
Тому що ви не маєте жодної послідовності читань та записів, оберненої в транзакцію, і іноді просто кидаєте код проти ваших ORM-об'єктів безпосередньо, ви страждаєте від "жахливої" реальності "читань непідтверджених", згаданої в статті
-
Тому що ви покладаєтеся на рівень ізоляції за замовчуванням, ви страждаєте як від неповторюваних читань, так і від фантомних читань. (Чи ви навіть знаєте, яким є рівень ізоляції за замовчуванням для вашої бази даних і що це означає????)
-
Тому що ви не встановили рівень транзакцій на "послідовний", ви помилково вважаєте, що ваша база даних швидка та безпечна. Ви покладалися на базу даних для забезпечення цілісності даних як на абстракцію, яка не вимагає критичного мислення та програмного коду, який принаймні в 10 разів кращий за ваш. Ви маєте всі жахливі функції зі статті Кайла у ваших додатках, підтримуваних СУБД - і, не тільки ви не знаєте про це, ви впевнені, що ваші дані "безпечні"
І тому я запитую вас, яке інженерне рішення гірше:
-
Виберіть стандартний інструмент, у впевненості якому всі впевнені, що вони розуміють і знають, як безпечно використовувати, але в звичайному використанні практично ніколи не гарантує те, що, як вважається, обіцяє, і, крім того, широко критикується за двозначні та неточні семантичні ознаки ?
-
Чи прийняти те, що завжди було правдою: що самі по собі бази даних не можуть надати абстракції, які означають, що не надзвичайно розумні розробники не можуть легко все зіпсувати. Та що цілісність даних - це специфічна для домену концепція, яка повинна бути реалізована на рівні додатку, а лише невелика частина цієї цілісності покращується вибором бази даних.
п.с. Я працював над великомасштабними фінансовими, реальночасовими та високодоступними системами, які використовують як Mongo, так і PostgreSQL. Це overly складно в будь-якому випадку.
п.п.с. Я намагався прокоментувати ваш блог, Кайл, але коментарі вибухнули ;-)