Распараллеливание вычислений в Queue-based-брокерах
Начало см. выше.
Пожалуй, я начну с совета:
Этот совет особенно ценен в случае, когда время обработки событий сильно варьируется, поскольку это та нагрузка, к которой Queue-based-брокеры особенно хорошо приспособлены. Как только обработчик заканчивает обработку очередного сообщения, брокер передает ему новое. Обработчики работают non-stop, исключая простои, увеличивая пропускную способность и по-максимуму утилизируя выделенные ресурсы.
Можно сделать мини-вывод, что Queue-based-брокеры отлично подходят:
🕚 для задач с малопредсказуемой продолжительностью выполнения;
🕚 когда гораздо важней как можно быстрей выполнить весь объем задач.
Примеры идеальных задач для Queue-based-брокеров:
🕚 задача формирование отчета по запросу-фильтру пользователя;
🕚 поиск и анализ ссылок в документе;
🕚 сборка мусора - удаление ненужных данных и т.п.
В свою очередь Log-based-брокеры хорошо подходят для потоковой обработки событий, когда важен порядок следования и обработки, нужен лог событий и возможность запуска повторной обработки.
На этом эпопею с брокерами считаю законченной. 😃
#conf
Начало см. выше.
Пожалуй, я начну с совета:
Для увеличения параллелизма МОЖНО отказаться от Log-based-брокера в пользу Queue-based, ЕСЛИ не важен порядок обработки событий, И ЕСЛИ не нужен лог событий.
Этот совет особенно ценен в случае, когда время обработки событий сильно варьируется, поскольку это та нагрузка, к которой Queue-based-брокеры особенно хорошо приспособлены. Как только обработчик заканчивает обработку очередного сообщения, брокер передает ему новое. Обработчики работают non-stop, исключая простои, увеличивая пропускную способность и по-максимуму утилизируя выделенные ресурсы.
Можно сделать мини-вывод, что Queue-based-брокеры отлично подходят:
Примеры идеальных задач для Queue-based-брокеров:
В свою очередь Log-based-брокеры хорошо подходят для потоковой обработки событий, когда важен порядок следования и обработки, нужен лог событий и возможность запуска повторной обработки.
На этом эпопею с брокерами считаю законченной. 😃
#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
Приём №5: Локальность данных
Пожалуй, это один из основных принципов обработки данных в распределенных системах. Самое простое определение звучит так: держите данные ближе к месту их обработки. Этот приём направлен на оптимизацию вычислений, чтобы основное время уходило на полезную работу. Такой подход особенно оправдан при частом и одновременном обращении к некоторой части данных.
Я предлагаю присмотреться к частному случаю этого принципа, т.к. обычно он более прост в реализации и, как правило, накладывает меньше архитектурных ограничений.
Существует множество способов реализации этого приёма, выбор зависит от решаемой задачи, доступного времени и средств. Примеры реализации:
🕚 Локальный (файловый) кэш/индекс редко меняющихся данных. Сюда же можно отнести алгоритм "Hash Join". В большинстве случаев значительно ускоряет обработку, но требует усилий по поддержанию кэша/индекса в актуальном состоянии.
🕚 Использование общей области памяти (shared memory) или общего диска. Также значительно ускоряет обработку, но в какой-то степени увеличивает связность между взаимодействующими компонентами, добавляет зависимость от технологии взаимодействия. "Читатель" знает, куда, что и как пишет "писатель", и наоборот. Помимо этого, взаимодействующие компоненты могут не ужиться на одной машине (разные требования к окружению, ресурсам, масштабированию и т.п.); общий диск может оказаться сетевым, что еще хуже скажется на производительности.
❗️ Теперь про жесткие архитектурные ограничения. Если рассматривать принцип локальности данных в целом, способ его реализации может существенным образом повлиять на всё решение. Поэтому важно проанализировать все достоинства и недостатки каждого варианта. В качестве иллюстрации можно рассмотреть следующие примеры.
🕚 Модель хранения данных - это тоже способ локализации данных. Например, key-value, column-family, индексы, да даже файловая система. Мы выбираем ту модель, которая наиболее удобна для большинства сценариев приложения. И я думаю, что многие сталкивались с ситуацией, когда модель хранения не отвечает существующим требованиям. Это способствует появлению неуклюжей и запутанной логики в коде.
🕚 Использование денормализации данных или даже документно-ориентированных хранилищ (например, MongoDB). Если необходимые данные распределены по множеству таблиц, потребуются достаточные усилия, чтобы собрать их вместе. Это создаст нагрузку на дисковую и сетевую инфраструктуру, увеличит время обработки. С другой стороны, мы получим избыточность данных и, если мы будем использовать только малую часть большого документа, это может негативно отразиться на сценариях чтения и записи.
🕚 Использование локальной файловой системы для генерации отчета вместо того, чтобы генерировать его в оперативной памяти или сразу производить запись в BLOB-хранилище. Преимущества очевидны - минимальное потребление памяти, сокращение количества сетевых обращений. Недостатки - места на локальном диске может не хватить; приложение должно позаботиться об удалении временных файлов.
🕚 Алгоритм "Partitioned Hash Join" - партиционирование разных потоков данных по одному ключу, чтобы иметь возможность эффективно объединять потоки на стороне обработчика. Этот подход применим только в случае, когда партиции могут быть помещены в оперативную память.
Итого
❗️ Локализация данных позволяет добиться значительных или даже прорывных успехов в сокращении времени обработки. Это очень сильный приём, но в этом же кроется и его слабость, т.к. за мощную оптимизацию приходится платить. И если на сегодняшний день эта цена может показаться не такой большой, то завтра, когда поменяются требования к системе, это может стать серьезным препятствием, чтобы двигаться дальше.
Докидывайте свои кейсы и случаи, как ускорялись, и как подобные решения проявились в дальнейшем. 😉
Данный пост поясняет тезисы моего доклада с конференции TeachLeadConf 2024.
#conf
Пожалуй, это один из основных принципов обработки данных в распределенных системах. Самое простое определение звучит так: держите данные ближе к месту их обработки. Этот приём направлен на оптимизацию вычислений, чтобы основное время уходило на полезную работу. Такой подход особенно оправдан при частом и одновременном обращении к некоторой части данных.
Я предлагаю присмотреться к частному случаю этого принципа, т.к. обычно он более прост в реализации и, как правило, накладывает меньше архитектурных ограничений.
Данные ДОЛЖНЫ находиться в месте их использования, ЕСЛИ они изменяются редко.
Существует множество способов реализации этого приёма, выбор зависит от решаемой задачи, доступного времени и средств. Примеры реализации:
Итого
Докидывайте свои кейсы и случаи, как ускорялись, и как подобные решения проявились в дальнейшем. 😉
Данный пост поясняет тезисы моего доклада с конференции TeachLeadConf 2024.
#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
Прошло полтора года, как я участвую в проекте "Виртуальная лаборатория: информатика и программирование". Это учебный модуль информационного портала "Московской Электронной Школы" (МЭШ), где ученики могут проходить курсы по информатике и программированию, выполнять различные тематические задания, в том числе решать задачи по программированию. Нам присылают код, который мы должны выполнить многократно, используя набор тестов предопределенный автором задачи. И каким бы подозрительным не был код, выполнить мы его обязаны в любом случае. Таково функциональное требование заказчика.
На проект я зашел в тот момент, когда нам объявили, что через три месяца на базе нашего модуля необходимо начать проводить олимпиады по программированию, а нагрузка в связи с этим возрастет в несколько десятков раз. То, с чем пришлось столкнуться, я рассказывал на UWDC 2024, а уже после этого я подготовил более проработанный доклад на TeachLeadConf 2024.
Я намеренно обходил моменты, связанные с особенностью прикладной области этого проекта. Не каждому интересно то, как мы компилируем и исполняем код, который нам прислали школьники. 👨🏻🎓 Однако, несмотря на кажущуюся простоту, эта задача, действительно, оказалась нелегкой. Что нам только не присылают, как только не пытаются нас "сломать" и "положить". И некоторым это удавалось сделать, за что пытливым умам можно выразить отдельный респект.🔥 Однако за последний год это удалось сделать только один раз, после чего мы исправили уязвимость. 😃
Начиная с UWDC 2024 ко мне обращались люди и интересовались деталями того, как именно мы справляемся с подобными вызовами. Пока лишь могу сказать, что у нас многоуровневая защита - комплекс мер, и детали этого трудно раскрыть в одном коротком посте. Поскольку интерес к этой теме сохраняется, я постараюсь раскрыть детали и особенности того, как безопасно исполнять чужой код/программы/скрипты.
А у вас была необходимость в запуске подозрительного кода?Подозреваю, что для QA любой код выглядит подозрительно. 😃
#untrusted_code #summary
На проект я зашел в тот момент, когда нам объявили, что через три месяца на базе нашего модуля необходимо начать проводить олимпиады по программированию, а нагрузка в связи с этим возрастет в несколько десятков раз. То, с чем пришлось столкнуться, я рассказывал на UWDC 2024, а уже после этого я подготовил более проработанный доклад на TeachLeadConf 2024.
Я намеренно обходил моменты, связанные с особенностью прикладной области этого проекта. Не каждому интересно то, как мы компилируем и исполняем код, который нам прислали школьники. 👨🏻🎓 Однако, несмотря на кажущуюся простоту, эта задача, действительно, оказалась нелегкой. Что нам только не присылают, как только не пытаются нас "сломать" и "положить". И некоторым это удавалось сделать, за что пытливым умам можно выразить отдельный респект.
Начиная с UWDC 2024 ко мне обращались люди и интересовались деталями того, как именно мы справляемся с подобными вызовами. Пока лишь могу сказать, что у нас многоуровневая защита - комплекс мер, и детали этого трудно раскрыть в одном коротком посте. Поскольку интерес к этой теме сохраняется, я постараюсь раскрыть детали и особенности того, как безопасно исполнять чужой код/программы/скрипты.
А у вас была необходимость в запуске подозрительного кода?
#untrusted_code #summary
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2❤1
Фэйл с RabbitMQ и Kubernetes API
Сегодня будет немного личная история, но с моралью в конце. На самом деле заголовок не совсем точный, но на момент, когда произошел описываемый казус, всё выглядело именно так. 😃
Ранее я давал пояснения, почему Kafka плохо подходит для случаев, когда время обработки однотипных сообщений существенно варьируется. По этой причине мы сделали выбор в пользу Queue-based-брокера и начали миграцию с Kafka на RabbitMQ. Поскольку для нас не была важна история событий, а работа с очередью была инкапсулирована в рамках соответствующего порта, технический переход на RabbitMQ прошел быстро и безболезненно. Самое интересное нас ждало впереди.
Спустя какое-то время после релиза мы начали замечать, что некоторые обработчики стали отваливаться с ошибкой Delivery Acknowledgement Timeout. Если коротко, то данная ошибка происходит в том случае, если сообщение, взятое из очереди, не получило подтверждения обработки спустя длительное время (по умолчанию 30 минут). В этом случае сообщение возвращается обратно в очередь брокера, соединение со старым обработчиком разрывается, и происходит переназначение обработчика сообщения.
Всё выглядело очень странно, и мы никак не могли добиться воспроизведения злосчастного бага. Код обработчика не менялся очень давно, поэтому все подозрения пали на RabbitMQ. Сначала мы перепроверили Helm Chart нашего кластера RabbitMQ; параллельно с этим перепотрошили все настройки RabbitMQ-клиента. В итоге сделали более тонкую и точную конфигурацию, которая соответствовала всем справочным рекомендациям по работе с RabbitMQ. Не скажу, что всё было напрасно, но ситуацию это не исправило. 😭
В тот момент, когда я начал замечать косые взгляды и намеки в стиле: «A вот с Kafka у нас всё работало, пока ты не пришёл со своим RabbitMQ!» — я понял, что дело не в брокере, а в самом обработчике. Я сделал концептуально правильный выбор, он полностью соответствовал нашим текущим потребностям, и в этом не было никаких сомнений. А раз дело в обработчике, значит, нужно искать виновника зависаний. Поскольку я хорошо знал алгоритм обработки, я практически сразу понял, с чем это может быть связано... 🎯
Сегодня будет немного личная история, но с моралью в конце. На самом деле заголовок не совсем точный, но на момент, когда произошел описываемый казус, всё выглядело именно так. 😃
Ранее я давал пояснения, почему Kafka плохо подходит для случаев, когда время обработки однотипных сообщений существенно варьируется. По этой причине мы сделали выбор в пользу Queue-based-брокера и начали миграцию с Kafka на RabbitMQ. Поскольку для нас не была важна история событий, а работа с очередью была инкапсулирована в рамках соответствующего порта, технический переход на RabbitMQ прошел быстро и безболезненно. Самое интересное нас ждало впереди.
Спустя какое-то время после релиза мы начали замечать, что некоторые обработчики стали отваливаться с ошибкой Delivery Acknowledgement Timeout. Если коротко, то данная ошибка происходит в том случае, если сообщение, взятое из очереди, не получило подтверждения обработки спустя длительное время (по умолчанию 30 минут). В этом случае сообщение возвращается обратно в очередь брокера, соединение со старым обработчиком разрывается, и происходит переназначение обработчика сообщения.
Всё выглядело очень странно, и мы никак не могли добиться воспроизведения злосчастного бага. Код обработчика не менялся очень давно, поэтому все подозрения пали на RabbitMQ. Сначала мы перепроверили Helm Chart нашего кластера RabbitMQ; параллельно с этим перепотрошили все настройки RabbitMQ-клиента. В итоге сделали более тонкую и точную конфигурацию, которая соответствовала всем справочным рекомендациям по работе с RabbitMQ. Не скажу, что всё было напрасно, но ситуацию это не исправило. 😭
В тот момент, когда я начал замечать косые взгляды и намеки в стиле: «A вот с Kafka у нас всё работало, пока ты не пришёл со своим RabbitMQ!» — я понял, что дело не в брокере, а в самом обработчике. Я сделал концептуально правильный выбор, он полностью соответствовал нашим текущим потребностям, и в этом не было никаких сомнений. А раз дело в обработчике, значит, нужно искать виновника зависаний. Поскольку я хорошо знал алгоритм обработки, я практически сразу понял, с чем это может быть связано... 🎯
🔥2👍1
Фэйл с RabbitMQ и Kubernetes API (продолжение)
Во время обработки происходит обращение к Kubernetes API (такова специфика нашей прикладной задачи). И вот на этом шаге всё и зависало, поскольку не был установлен таймаут ожидания результатов вызова. 🙉 Дело в том, что для вызова Kubernetes API мы используем fabric8io/kubernetes-client, у которого, как выяснилось, по умолчанию был установлен некоторый Rate Limit. 🙊 Превышение этого лимита приводило к зависанию при обращении к Kubernetes API. В результате проблема была решена добавлением таймаута ожидания результатов, подбором и установкой подходящих значений для Rate Limit, выносом этих настроек в конфигурационный файл приложения.
По итогу я был рад не столько тому, что нашёл и исправил проблему, сколько тому, что моё архитектурное решение было правильным, а возникшая ситуация подтвердила это ещё раз. В Kafka всё работало, и проблема не проявлялась только потому, что она не приспособлена к ситуациям, когда время обработки может варьироваться. В итоге пропускная способность системы на базе Kafka была ниже, мы никогда не упирались в Rate Limit для Kubernetes API и даже не знали о существовании этой проблемы. С переходом на RabbitMQ пропускная способность увеличилась, проблема материализовалась, опустившись на тот уровень, где она всегда и была, а мы стали упираться в Rate Limit.
❗️ Из этой истории можно извлечь, как минимум, два урока.
1️⃣ Если в коде приложения есть синхронные обращения к сторонним службам, то всегда нужно контролировать время ожидания (timeout). Также не забывать и про другие шаблоны устойчивости, а именно: не злоупотреблять шаблоном "Повтор" (Retry), в нужные моменты использовать "Предохранитель" (Circuit Breaker), и понимать, что "Ограничитель скорости" (Rate Limiter) может быть установлен с двух сторон (на клиенте и сервере). Однажды я не уделил этому должного внимания, спровоцировав неприятности в дальнейшем.
2️⃣ Не нужно сомневаться в том, как на концептуальном уровне работают инструменты, в частности брокеры. Если что-то идет не так, проблема может быть в развертывании, но, скорей всего, в коде приложения. Нужно убедиться, что настройки клиентского драйвера выполнены в соответствии с рекомендациями; не осталось ни одной настройки по умолчанию, в которых у вас есть сомнения. Я начал поиски проблемы не с того и поплатился временем.
Делитесь своими фэйлами, будем учиться на ошибках друг друга. 😃
Во время обработки происходит обращение к Kubernetes API (такова специфика нашей прикладной задачи). И вот на этом шаге всё и зависало, поскольку не был установлен таймаут ожидания результатов вызова. 🙉 Дело в том, что для вызова Kubernetes API мы используем fabric8io/kubernetes-client, у которого, как выяснилось, по умолчанию был установлен некоторый Rate Limit. 🙊 Превышение этого лимита приводило к зависанию при обращении к Kubernetes API. В результате проблема была решена добавлением таймаута ожидания результатов, подбором и установкой подходящих значений для Rate Limit, выносом этих настроек в конфигурационный файл приложения.
По итогу я был рад не столько тому, что нашёл и исправил проблему, сколько тому, что моё архитектурное решение было правильным, а возникшая ситуация подтвердила это ещё раз. В Kafka всё работало, и проблема не проявлялась только потому, что она не приспособлена к ситуациям, когда время обработки может варьироваться. В итоге пропускная способность системы на базе Kafka была ниже, мы никогда не упирались в Rate Limit для Kubernetes API и даже не знали о существовании этой проблемы. С переходом на RabbitMQ пропускная способность увеличилась, проблема материализовалась, опустившись на тот уровень, где она всегда и была, а мы стали упираться в Rate Limit.
Делитесь своими фэйлами, будем учиться на ошибках друг друга. 😃
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1😁1
Надёжность, прочность, устойчивость
При обсуждении свойств программной системы мы часто оперируем такими терминами, как надежность, прочность и устойчивость, не проводя четких различий между ними. Однако, при формулировании требований эти понятия следует рассматривать отдельно. Если вы думаете, что это не столь важно, то инженеры NASA, которые занимаются проектированием систем жизнеобеспечения, так не считают.🚀 Как мне кажется, данный опыт вполне применим и при проектировании программных систем.
1️⃣ Надёжность (Reliability) - вероятность того, что система не выйдет из строя в течении определенного периода времени и при определенных условиях эксплуатации. Иначе говоря, в заданных условиях эксплуатации система стабильна и отвечает проектным требованиям.
2️⃣ Прочность (Robustness) - способность системы работать удовлетворительно или даже в соответствии с заявленными требованиями, несмотря на воздействия, выходящие за рамки предопределенных условий эксплуатации, но при этом являющимися возможными. Прочность рассматривается в контексте предвидимых проблем.
3️⃣ Устойчивость (Resilience) - способность системы быстро восстанавливаться или адаптироваться к непредвиденным происшествиям или изменениям, которые нарушают базовые проектные предположения. Устойчивость рассматривается в контексте непредвиденных или маловероятных проблем.
Таким образом, надежность, прочность и устойчивость определяют поведение системы на трех уровнях сложности условий эксплуатации. Сначала в заданной среде; затем в среде с вероятными проблемами; наконец, во враждебной, деструктивной среде.
Предполагается, что по мере развития системы уточняются условия её эксплуатации, модель оперативного окружения становится более точной и реалистичной. Мы сталкиваемся с непредвиденными проблемами, понимаем причины их возникновения, а затем решаем эти проблемы, переводя их в статус известных. Таким образом, совершенствование системы заключается в движении от уровня устойчивости к уровню надежности. Когда мы понимаем, что возникшая непредвиденная ситуация является нормой, которую мы не учли на ранних стадиях проектирования, мы уточняем требования к прочности или даже надежности.
Всегда ли необходимо заботиться об устойчивости? Зависит от рисков, которые несет бизнес при возникновении таких ситуаций. Последствия могут включать временны́е, репутационные, финансовые риски или даже создавать угрозу жизни людей. С одной стороны, совсем игнорировать уровень непредвиденных ошибок, упрощая модель системы, конечно, было бы глупо. С другой, попытка учесть всевозможные ситуации для большинства программных систем, является неоправданным усложнением.
К посту прикрепляю оригинал статьи "Going Beyond Reliability to Robustness and Resilience in Space Life Support Systems", Harry W. Jones, 2021.⬇️
По итогу хочу всем пожелать в Новом 2025 году надежности, прочности и устойчивости! А если будут возникать непредвиденные ситуации, то пусть они будут только приятными. 🎉🎄☃️
#arch
При обсуждении свойств программной системы мы часто оперируем такими терминами, как надежность, прочность и устойчивость, не проводя четких различий между ними. Однако, при формулировании требований эти понятия следует рассматривать отдельно. Если вы думаете, что это не столь важно, то инженеры NASA, которые занимаются проектированием систем жизнеобеспечения, так не считают.
Таким образом, надежность, прочность и устойчивость определяют поведение системы на трех уровнях сложности условий эксплуатации. Сначала в заданной среде; затем в среде с вероятными проблемами; наконец, во враждебной, деструктивной среде.
Предполагается, что по мере развития системы уточняются условия её эксплуатации, модель оперативного окружения становится более точной и реалистичной. Мы сталкиваемся с непредвиденными проблемами, понимаем причины их возникновения, а затем решаем эти проблемы, переводя их в статус известных. Таким образом, совершенствование системы заключается в движении от уровня устойчивости к уровню надежности. Когда мы понимаем, что возникшая непредвиденная ситуация является нормой, которую мы не учли на ранних стадиях проектирования, мы уточняем требования к прочности или даже надежности.
Всегда ли необходимо заботиться об устойчивости? Зависит от рисков, которые несет бизнес при возникновении таких ситуаций. Последствия могут включать временны́е, репутационные, финансовые риски или даже создавать угрозу жизни людей. С одной стороны, совсем игнорировать уровень непредвиденных ошибок, упрощая модель системы, конечно, было бы глупо. С другой, попытка учесть всевозможные ситуации для большинства программных систем, является неоправданным усложнением.
К посту прикрепляю оригинал статьи "Going Beyond Reliability to Robustness and Resilience in Space Life Support Systems", Harry W. Jones, 2021.
По итогу хочу всем пожелать в Новом 2025 году надежности, прочности и устойчивости! А если будут возникать непредвиденные ситуации, то пусть они будут только приятными. 🎉🎄☃️
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🎄4🔥3☃1👍1
140 Reliability, robustness, and resilience FINAL.pdf
359.2 KB
"Going Beyond Reliability to Robustness and Resilience in Space Life Support Systems", Harry W. Jones, 2021.
👍4
Наконец, могу поделиться ссылкой на видеозапись 📱 моего доклада "Кратно ускоряем потоки данных. Практичные архитектурные приёмы", тезисы которого я анонсировал ранее.
P.s. К сожалению, пока только YouTube. Позже обещали выложить в RuTube и VK.
#conf
P.s. К сожалению, пока только YouTube. Позже обещали выложить в RuTube и VK.
#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Кратно ускоряем потоки данных. Практичные архитектурные приёмы / Александр Межов
Приглашаем на самую крупную мультиформатную конференцию для тимлидов и руководителей не только из IT — TeamLead Conf 2025, которая пройдет 10 и 11 ноября 2025 в Москве.
Подробнее о конференции: https://clck.ru/3NUaBv
________
Самая крупная мультиформатная…
Подробнее о конференции: https://clck.ru/3NUaBv
________
Самая крупная мультиформатная…
🔥6👍4👏1
Гарантированная отправка сообщений
На конференции TeachLeadConf после доклада мне был задан вопрос про гарантию отправки сообщений в брокер. Если коротко, то вопрос можно сформулировать так: "Как гарантировать отправку сообщений, сохранив их порядок?" Оригинальная формулировка была не столь понятна для меня, поэтому пришлось ответить позже в закрытом чате конференции. Поскольку вопрос достаточно популярный, я решил дать более развернутый и публичный ответ.
К вопросам обеспечения гарантий доставки и сохранения порядка я бы добавил еще исключение дубликатов и/или обеспечение идемпотентной обработки. Эти требования являются критичными для широкого спектра задач. Например, в финансовой сфере помещение денег на счет и их снятие в дальнейшем сильно отличается от снятия с последующим помещением, не говоря о том, что эти операции не должны быть задублированы по ошибке.
Не нужно думать, что в современных распределенных системах все эти проблемы может решить какой-то особенный инструмент или способ отправки сообщений. Данную задачу нужно решать в комплексе - на уровне способа отправки и на уровне самого приложения. Причём, на мой взгляд, вопросов к самому приложению в этом плане должно быть гораздо больше, чем к возможному инструментарию.
Полный ответ оформил в виде статьи на Дзен, т.к. для поста в Telegram слишком много текста. Туда же прикрепил свои ранние публикации из канала. Как говорится, заходите в гости, подписывайтесь и будьте в курсе дел. 😃 Думаю, что подобные long-reads буду в том числе оставлять там. ✍🏻
#tech #dev
На конференции TeachLeadConf после доклада мне был задан вопрос про гарантию отправки сообщений в брокер. Если коротко, то вопрос можно сформулировать так: "Как гарантировать отправку сообщений, сохранив их порядок?" Оригинальная формулировка была не столь понятна для меня, поэтому пришлось ответить позже в закрытом чате конференции. Поскольку вопрос достаточно популярный, я решил дать более развернутый и публичный ответ.
К вопросам обеспечения гарантий доставки и сохранения порядка я бы добавил еще исключение дубликатов и/или обеспечение идемпотентной обработки. Эти требования являются критичными для широкого спектра задач. Например, в финансовой сфере помещение денег на счет и их снятие в дальнейшем сильно отличается от снятия с последующим помещением, не говоря о том, что эти операции не должны быть задублированы по ошибке.
Не нужно думать, что в современных распределенных системах все эти проблемы может решить какой-то особенный инструмент или способ отправки сообщений. Данную задачу нужно решать в комплексе - на уровне способа отправки и на уровне самого приложения. Причём, на мой взгляд, вопросов к самому приложению в этом плане должно быть гораздо больше, чем к возможному инструментарию.
Полный ответ оформил в виде статьи на Дзен, т.к. для поста в Telegram слишком много текста. Туда же прикрепил свои ранние публикации из канала. Как говорится, заходите в гости, подписывайтесь и будьте в курсе дел. 😃 Думаю, что подобные long-reads буду в том числе оставлять там. ✍🏻
#tech #dev
👍5🔥2⚡1
Борьба с зомби-процессами
Ранее я обещал, что постараюсь раскрыть тему безопасного исполнения ненадежного кода. Сегодня будет первая статья из цикла "Как безопасно исполнять ненадежный код" #untrusted_code Надеюсь, что будет интересно. 😃
В Linux каждый процесс знает о своих потомках и должен самостоятельно о них заботиться. Например, если код приложения создает дочерний процесс вызовом системной функции
Когда процесс завершается, он переходит в статус "зомби"🧟 (zombie, defunct), а ОС формирует сигнал
В общем случае зомби-процессы сигнализируют об ошибках ПО, для этого их и придумали. В справках пишут, что зомби-процессы не потребляют ресурсы (RAM/CPU), но, находясь на учете у ОС, расходуют PIDs. Таким образом, рано или поздно может произойти нехватка PIDs. Это значит, что вы не сможете запустить новый процесс или поток! ☠️
Самый простой способ создать зомби - убить родительский процесс раньше дочернего. В этом случае ОС назначает сироте нового родителя - опекуна. По дизайну Linux им становится процесс с PID=1, который называют init-процессом. В обязанности init-процесса в том числе входит грязная работа - делать то, что не сделали безответственные родители - дожидаться завершения "зомби" и таким образом удалять их из системных таблиц ядра ОС.
Как правило, в большинстве Docker-образов init-процессом является
Кстати, на базе этой особенности построена очень простая, но крайне агрессивная атака, называемая Fork bomb (по имени системной функции). Вот вариант ее реализации на C++ - процесс клонирует сам себя в бесконечном цикле:
Если запустить такой процесс без подготовки, поможет только рестарт. Но даже если получится принудительно завершить все вредоносные процессы, в системных таблицах ядра ОС останется куча зомби-процессов и лимит PIDs будет на гране истощения.
Но что, если мы знаем, что запускаем ненадежный код? Например, реализация какого-нибудь GitLab делает это постоянно, выполняя CI на базе наших скриптов. Для GitLab пользовательские скрипты являются ненадежным кодом, и такие процессы могут быть завершены некорректно или принудительно. В таком приложении наличие зомби-процессов в системе - это норма. Тогда как бороться с зомби и утечкой PIDs?
❗️ Решение заключается в подмене init-процесс на такой, который будет удалять зомби сразу, как только они появляются. Делать ничего не нужно, т.к. всё уже сделано за нас. ⚡️ Проект называется tini. Использовать легко: в Dockerfile нужно указать
В дополнение могу порекомендовать книгу "Linux System Programming" (Robert Love). В ней очень кратко и понятно описывается внутреннее устройство Linux и то, как правильно работать с функциями ОС.
#tech #dev #devops #untrusted_code
Ранее я обещал, что постараюсь раскрыть тему безопасного исполнения ненадежного кода. Сегодня будет первая статья из цикла "Как безопасно исполнять ненадежный код" #untrusted_code Надеюсь, что будет интересно. 😃
В Linux каждый процесс знает о своих потомках и должен самостоятельно о них заботиться. Например, если код приложения создает дочерний процесс вызовом системной функции
fork(), то он должен дождаться его завершения через вызов функции waitpid(). Вполне логично, ведь "родитель" должен заботиться о своих детях. :)int pid = fork();
if (pid > 0) {
// Parent logic
waitpid(pid);
} else {
// Children logic
}
Когда процесс завершается, он переходит в статус "зомби"
SIGCHLD для всех процессов, которые ожидали его завершения с помощью функции waitpid(). Вместе с этим waitpid() заканчивает работу и возвращает управление, а зомби уничтожается - удаляется из системных таблиц ядра ОС. Если никто не ждет дочерний процесс, он продолжает бесконечно висеть в статусе "зомби", находясь на учете у ОС.В общем случае зомби-процессы сигнализируют об ошибках ПО, для этого их и придумали. В справках пишут, что зомби-процессы не потребляют ресурсы (RAM/CPU), но, находясь на учете у ОС, расходуют PIDs. Таким образом, рано или поздно может произойти нехватка PIDs. Это значит, что вы не сможете запустить новый процесс или поток! ☠️
Самый простой способ создать зомби - убить родительский процесс раньше дочернего. В этом случае ОС назначает сироте нового родителя - опекуна. По дизайну Linux им становится процесс с PID=1, который называют init-процессом. В обязанности init-процесса в том числе входит грязная работа - делать то, что не сделали безответственные родители - дожидаться завершения "зомби" и таким образом удалять их из системных таблиц ядра ОС.
Как правило, в большинстве Docker-образов init-процессом является
sh. Так повелось, что sh специально "игнорирует" наличие зомби и не освобождает PIDs. Это сделано для того, чтобы системные администраторы могли увидеть проблему, например, выполнив команду ps, в выводе которой зомби-процессы отображаются как <defunct>. Таким образом, зомби будут висеть в системе бесконечно, до рестарта системы. Игнорирование этой проблемы ведет к утечке PIDs, которая при наличии в ОС лимита на их количество приводит к невозможности запуска новых процессов и потоков. Следовательно, к серьезным проблемам функционирования сервера.Кстати, на базе этой особенности построена очень простая, но крайне агрессивная атака, называемая Fork bomb (по имени системной функции). Вот вариант ее реализации на C++ - процесс клонирует сам себя в бесконечном цикле:
#include <unistd.h>
int main() {
while (1) fork();
}
Если запустить такой процесс без подготовки, поможет только рестарт. Но даже если получится принудительно завершить все вредоносные процессы, в системных таблицах ядра ОС останется куча зомби-процессов и лимит PIDs будет на гране истощения.
Но что, если мы знаем, что запускаем ненадежный код? Например, реализация какого-нибудь GitLab делает это постоянно, выполняя CI на базе наших скриптов. Для GitLab пользовательские скрипты являются ненадежным кодом, и такие процессы могут быть завершены некорректно или принудительно. В таком приложении наличие зомби-процессов в системе - это норма. Тогда как бороться с зомби и утечкой PIDs?
tini в качестве ENTRYPOINT.В дополнение могу порекомендовать книгу "Linux System Programming" (Robert Love). В ней очень кратко и понятно описывается внутреннее устройство Linux и то, как правильно работать с функциями ОС.
#tech #dev #devops #untrusted_code
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3⚡2
Принцип прочности
В продолжении разговора о надежности, прочности и устойчивости. Недавно наткнулся на принцип, о существовании которого не знал, но много раз применял его на практике. Точней сказать, я не знал, что это целый принцип. 😃
Представляю вашему вниманию "Принцип прочности" (Robustness principle), он же "Закон Постела" (Postel's law). Джон Постел - один из основных соавторов современных сетевых протоколов. В ранней спецификации TCP он сформулировал этот принцип так:
Давайте на примерах разберемся с условиями применимости данного принципа. Для себя я выделяю два случая, когда стоит присмотреться к подобному решению.
1️⃣ Интеграция со сторонними системами. С одной стороны, вызывая внешний сервис, лучше четко следовать его спецификации. В случае отклонения от спецификации в лучшем случае можно получить ошибку, в худшем - неоднозначный результат. Например, если не передали значение какого-то атрибута, то внешний сервис может установить для этого атрибута значение по умолчанию или каким-то неочевидным образом изменить логику обработки запроса. С другой стороны, нет никакой надежды, что внешние сервисы будут пользоваться нашим, четко следуя нашей спецификации. В связи с этим можно смягчить требования к формату входящих запросов. Например, используя значения по умолчанию для отсутствующих атрибутов или игнорируя неизвестные атрибуты. Аналогично, вызывая внешний сервис и получая в ответе больше атрибутов, чем ожидалось, можно игнорировать всё ненужное.
2️⃣ Расширение функциональности. Например, случай расширения модели данных. Очевидно, что клиенты, рассчитывающие на старую версию сервиса, не будут передавать новых значений. Также очевидно, что при переходе на новую версию системы без ее остановки в один момент времени будут существовать и старые, и новые клиенты. Если недостающие данные можно заполнить какими-то значениями по умолчанию, и это не приведет к негативным последствиям, такое решение может быть хорошим компромиссом, как минимум на время обновления системы.
❗️ Пожалуй, главный недостаток рассматриваемого подхода в том, что он может долго скрывать неблагонадежных участников взаимодействия. Если кто-то отклоняется от спецификации, а кто-то этому потворствует, умалчивая подобные факты, с течением времени может сформироваться целый пласт проблем. Критики также отмечают, что это также может приводить к проблемам безопасности в системе.
А как вы использовали этот подход в своей практике? Насколько этот опыт был позитивным или негативным? 😉
#arch
В продолжении разговора о надежности, прочности и устойчивости. Недавно наткнулся на принцип, о существовании которого не знал, но много раз применял его на практике. Точней сказать, я не знал, что это целый принцип. 😃
Представляю вашему вниманию "Принцип прочности" (Robustness principle), он же "Закон Постела" (Postel's law). Джон Постел - один из основных соавторов современных сетевых протоколов. В ранней спецификации TCP он сформулировал этот принцип так:
Будь консервативен в своих действиях, но либерален к действиям других. Будь консервативен в том, что отправляешь, и либерален к тому, что принимаешь.
Давайте на примерах разберемся с условиями применимости данного принципа. Для себя я выделяю два случая, когда стоит присмотреться к подобному решению.
А как вы использовали этот подход в своей практике? Насколько этот опыт был позитивным или негативным? 😉
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍3
Что не так с PostgreSQL
Если вы никогда не задумывались о том, что не так с PostgreSQL, скорей всего, у вас всё так и можно спокойно жить дальше.Но это не точно. 😃
PostgreSQL - это высокопроизводительная монолитная реляционная база данных, предоставляющая гарантии ACID при выполнении транзакций. PostgreSQL - отличный инструмент для подавляющего большинства задач, имеет обширный функционал, инструментарий и множество расширений. Это настолько проверенное и универсальное решение, что многие выбирают PostgreSQL почти не глядя. Однако крайне не рекомендую делать выбор вслепую, поэтому предлагаю рассмотреть основные и подтвержденные проблемы PostgreSQL, а также возможные способы их решения.
🔴 Отсутствие автоматического горизонтального масштабирования. Из коробки такой функциональности нет; шардирование реализовано как частный случай партиционирования; вся ответственность за распределение данных ложится на плечи разработчиков. Расширение Citus (GitHub) частично решает проблему с масштабированием, однако нужно понимать, что оно не делает из PostgreSQL полноценную распределенную реляционную базу с гарантиями ACID при выполнении транзакций. Иначе говоря, Citus обеспечивает только согласованность в конечном счёте, следовательно, в общем случае не подходит для OLTP-задач; либо подходит, но в рамках одного шарда; и хорошо подходит для "складов данных" (data warehouses).
🔴 Низкие гарантии отказоустойчивости. При выходе из строя мастера гарантирован простой в работе системы и риск потери согласованности данных. Очень часто для построения высокодоступного (HA, High Availability) кластера PostgreSQL используют Patroni (GitHub). Экземпляры Patroni работают как sidecars для узлов PostgreSQL, которые координируют свои действия через указанное распределенное хранилище конфигураций (etcd, ZooKeeper и т.п.). Patroni отслеживает доступность узлов кластера, управляет их работой и конфигурацией, определяет узел мастера, производит выбор нового мастера из существующих реплик в случае недоступности старого.
🔴 Простои при обновлении на новую версию. Частично решить проблему может логическая репликация, но она имеет ряд ограничений, в том числе не умеет переносить изменения схемы данных (DDL) и сразу же останавливается, если такое вдруг произойдет. Также нужно иметь в виду, что тот же Patroni использует только физическую репликацию.
🔴 Раздувание базы данных (bloat). Со временем файлы данных "раздуваются", занимая больше места на диске, чем могли бы. Эта проблема присуща не только PostgreSQL и связана с версионированием изменений данных. Для новых изменений резервируется дополнительное пространство на диске, а место, занимаемое старыми и неактуальными версиями, не освобождается. Для минимизации последствий рекомендуется контролировать уровень bloat и настроить автоматическую очистку. В крайних случаях можно использовать команды VACUUM, CLUSTER или REINDEX, но они создают блокировки, что может сказаться на работоспособности приложения. Если блокировки недопустимы, можно посмотреть в сторону расширений типа pg_repack.
Подводя небольшой итог, можно выделить случаи, когда PostgreSQL не подойдет:
✖️ Предвидится большой размер базы данных
✖️ Необходимо горизонтальное масштабирование
✖️ Необходимы высокие гарантии отказоустойчивости
✖️ Недопустимы простои в работе базы данных
Если всё вышеперечисленное к вам не относится или не является серьезной проблемой, тогда вы вне зоны риска и можно продолжать использовать PostgreSQL или рассматривать его в качестве кандидата для выбора.
❗️ Что важно сказать в конце. Никакие теоретические выкладки, обзоры, анализы или бенчмарки не учитывают ваши потребности и возможности. Поэтому при выборе хранилища нужно принимать во внимание не только ту информацию, которая находится в общем доступе, но и проводить свои собственные эксперименты, тесты и расчеты, оценивать возможные риски и заранее искать и отрабатывать варианты их устранения.
#db #devops
Если вы никогда не задумывались о том, что не так с PostgreSQL, скорей всего, у вас всё так и можно спокойно жить дальше.
PostgreSQL - это высокопроизводительная монолитная реляционная база данных, предоставляющая гарантии ACID при выполнении транзакций. PostgreSQL - отличный инструмент для подавляющего большинства задач, имеет обширный функционал, инструментарий и множество расширений. Это настолько проверенное и универсальное решение, что многие выбирают PostgreSQL почти не глядя. Однако крайне не рекомендую делать выбор вслепую, поэтому предлагаю рассмотреть основные и подтвержденные проблемы PostgreSQL, а также возможные способы их решения.
Подводя небольшой итог, можно выделить случаи, когда PostgreSQL не подойдет:
Если всё вышеперечисленное к вам не относится или не является серьезной проблемой, тогда вы вне зоны риска и можно продолжать использовать PostgreSQL или рассматривать его в качестве кандидата для выбора.
#db #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3⚡1🤔1
ACID, AID или AD (1/3)
В свете растущей популярности распределенных систем часто видим упоминание таких слов, как согласованность и изоляция. В контексте работы с данными считается, что эталоном согласованности и изоляции являются проверенные годами реляционные базы данных, а в распределенных системах с этим всё очень плохо, ведь там нет транзакций, поэтому приходится придумывать что-то своё, сильно усложняя прикладной код, а в результате всё равно получается что-то не очень надёжное. Давайте разбираться.🚀
Самое главное преимущество транзакций - это упрощение программной модели приложения, осуществляющего доступ к данным. Транзакции позволяют представить последовательность операций чтения и записи как одну изолированную логическую операцию. Концептуально это значит, что все операции должны быть выполнены как одна по принципу "всё или ничего". Либо все действия выполняются успешно, либо производится отмена произведённых изменений. В первом случае речь про фиксацию изменений (commit), во втором - про откат (rollback, abort).
Таким образом, упрощение программной модели обеспечивается предоставлением гарантий, что в случае ошибки ничего не произойдет, следовательно, можно безопасно повторить все действия. Пожалуй, это одна из самых лучших иллюстраций инкапсуляции и разделения ответственности: транзакция предоставляет гарантии сохранности, обрабатывая всевозможные ошибки, а код приложения сосредоточен на реализации бизнес-логики.
В чём же заключаются гарантии сохранности? Я думаю, что многие знают акроним🔭
#arch #db
В свете растущей популярности распределенных систем часто видим упоминание таких слов, как согласованность и изоляция. В контексте работы с данными считается, что эталоном согласованности и изоляции являются проверенные годами реляционные базы данных, а в распределенных системах с этим всё очень плохо, ведь там нет транзакций, поэтому приходится придумывать что-то своё, сильно усложняя прикладной код, а в результате всё равно получается что-то не очень надёжное. Давайте разбираться.
Самое главное преимущество транзакций - это упрощение программной модели приложения, осуществляющего доступ к данным. Транзакции позволяют представить последовательность операций чтения и записи как одну изолированную логическую операцию. Концептуально это значит, что все операции должны быть выполнены как одна по принципу "всё или ничего". Либо все действия выполняются успешно, либо производится отмена произведённых изменений. В первом случае речь про фиксацию изменений (commit), во втором - про откат (rollback, abort).
Таким образом, упрощение программной модели обеспечивается предоставлением гарантий, что в случае ошибки ничего не произойдет, следовательно, можно безопасно повторить все действия. Пожалуй, это одна из самых лучших иллюстраций инкапсуляции и разделения ответственности: транзакция предоставляет гарантии сохранности, обрабатывая всевозможные ошибки, а код приложения сосредоточен на реализации бизнес-логики.
В чём же заключаются гарантии сохранности? Я думаю, что многие знают акроним
ACID, тем не менее предлагаю пройтись по этой теме еще раз и посмотреть на неё под другим углом. #arch #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥3⚡1
ACID, AID или AD (2/3)
Предполагается, что транзакция должна обеспечивать следующие четыре свойства.
🕚 Atomicity (атомарность). Все операции транзакции представляют собой одну логическую операцию, которая должна быть выполнена только успешно, а в случае любой ошибки все произведенные действия должны быть отменены (abort). Мартин Клеппманн в своей знаменитой книге Designing Data-Intensive Application сетует на перегруженность термина "атомарность" и говорит, что термин "отменяемость" (abortability) был бы более точным.
🕚 Consistency (согласованность). Если данные находились в согласованном состоянии до выполнения транзакции, они должны остаться согласованными и после неё. Однако что считать согласованностью? Да, база данных может предоставлять некоторые механизмы обеспечения согласованности в виде ограничений (constraints), например, контроль внешних ключей, уникальности, полноты данных, их формата, размера и т.п. Однако, только приложение может определить, какие данные корректны, а какие нет, а база данных отвечает лишь за их сохранение. Кто вас остановит от записи некорректных данных в базу?! Таким образом, здесь можно говорить лишь о согласованности файлов базы данных, поскольку применяются изменения только успешных транзакций. При таком подходе я бы предложил назвать это свойство целостностью. Клеппманн также указывает, что исторически буква
🕚 Isolation (изолированность). Параллельно выполняемые транзакции изолированы друг от друга таким образом, что результат их выполнения должен быть идентичен тому, который получился бы при их последовательном (serial) выполнении. Однако на практике такой уровень изоляции (serializable) используется крайне редко, поскольку может оказывать негативное влияние на производительность приложения. Более того, разные базы данных по-разному реализуют это свойство, ослабляя в некоторых случаях уровень изоляции в угоду производительности.
🕚 Durability (долговечность). Если транзакция завершилась успешно, все произведенные изменения не должны быть забыты. В монолитных базах данных долговечность реализуется записью данных на постоянный носитель информации (HDD/SSD); в распределенных - репликацией, то есть копированием данных на несколько узлов - реплик. Прежде, чем транзакция завершится успешно, база данных должна дождаться успешной записи всех изменений на диск или окончания репликации. Даже несмотря на это, нетрудно догадаться, что некоторые вещи не зависят от базы данных и идеальной долговечности не существует. Отключение питания, нарушение температурного режима, аппаратные сбои, деградация секторов накопителя, ошибки на уровне файловой системы - всё это не редкость. Наряду с этим, использование асинхронной репликации может стать причиной потери изменений. Таким образом, никаких гарантий нет, есть только техники снижения рисков: репликация и резервное копирование.
В итоге в лучшем случае транзакции могут обеспечить лишь три свойства:
Многие так привыкли к абсолюту ACID, что подобные выводы могут показаться неожиданными. 🦄 Причем они справедливы для любой реализации транзакций. Разница лишь в том, что для транзакционных (реляционных) баз данных это не совсем очевидно, а для распределенных систем - это норма. Например, процесс согласования данных на основе распределенных транзакций (2PC) или повествований (Saga) изначально подразумевает отсутствие изоляции и предполагает применение контрмер, которые нивелируют этот недостаток.
#arch #db
Предполагается, что транзакция должна обеспечивать следующие четыре свойства.
C была добавлена лишь для создания акронима, и это не то свойство, которое может гарантировать база.В итоге в лучшем случае транзакции могут обеспечить лишь три свойства:
AID, т.к. согласованность может быть обеспечена только на прикладном уровне. А с учетом того, что чаще всего используются ослабленные уровни изоляции, остаются лишь два свойства: AD, причем со множеством уже сделанных оговорок. 🤷🏻♂️😃Многие так привыкли к абсолюту ACID, что подобные выводы могут показаться неожиданными. 🦄 Причем они справедливы для любой реализации транзакций. Разница лишь в том, что для транзакционных (реляционных) баз данных это не совсем очевидно, а для распределенных систем - это норма. Например, процесс согласования данных на основе распределенных транзакций (2PC) или повествований (Saga) изначально подразумевает отсутствие изоляции и предполагает применение контрмер, которые нивелируют этот недостаток.
#arch #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8⚡1🔥1
ACID, AID или AD (3/3)
Поддержка ACID на уровне базы данных, безусловно, упрощает программную модель приложения, сдвигая акцент в сторону прикладной логики. За многие годы использования транзакционных (монолитных) баз они доказали свою надежность. Используя принцип KISS, мы должны следовать этим путём, если он для нас открыт, и только в противном случае искать более сложные решения. Однако мы должны помнить, что согласованность и изоляция - это то, о чём разработчик должен заботиться не меньше, чем база данных! К сожалению, иногда вижу, что про это забывают, прикрывая неудачные архитектурные решения транзакциями и ссылаясь на незыблемость реляционных баз. Из-за этого ошибки по причине нарушения согласованности и изоляции в монолитных системах встречаются не реже, чем в распределенных.
Подводя итоги, можно сказать, что ACID-транзакции - это лишь один из инструментов, используемый в архитектурном решении. Где-то он проще, поскольку поддерживается используемой базой данных, а где-то сложней, как например, в распределенных системах или при гетерогенном хранении данных. В последнем случае для упрощения прикладного кода мы используем специализированные фреймворки (для управления распределенными транзакциями или повествованиями).
Переходя от инструментов к архитектурным методам, в контексте согласованности и изоляции очень выгодную позицию занимает объектный подход и DDD, в котором предлагается концепция ограниченных контекстов, агрегата и необходимость соблюдения инвариантов. Похожих целей пытаются добиться при использовании шаблона Event Sourcing. Иначе говоря, основная цель - сделать так, чтобы программная модель обеспечивала жесткие рамки, направляющие разработчика писать корректный код. Пожалуй, последнее - это то, к чему мы все должны стремиться. 😜
***
Надеюсь, что было интересно и не скучно. 😃 А у вас есть интересные истории, когда даже транзакции не спасали от страшного? Или успешные истории, как и где можно жить без ACID?🪐 👾
#arch #db
Поддержка ACID на уровне базы данных, безусловно, упрощает программную модель приложения, сдвигая акцент в сторону прикладной логики. За многие годы использования транзакционных (монолитных) баз они доказали свою надежность. Используя принцип KISS, мы должны следовать этим путём, если он для нас открыт, и только в противном случае искать более сложные решения. Однако мы должны помнить, что согласованность и изоляция - это то, о чём разработчик должен заботиться не меньше, чем база данных! К сожалению, иногда вижу, что про это забывают, прикрывая неудачные архитектурные решения транзакциями и ссылаясь на незыблемость реляционных баз. Из-за этого ошибки по причине нарушения согласованности и изоляции в монолитных системах встречаются не реже, чем в распределенных.
Подводя итоги, можно сказать, что ACID-транзакции - это лишь один из инструментов, используемый в архитектурном решении. Где-то он проще, поскольку поддерживается используемой базой данных, а где-то сложней, как например, в распределенных системах или при гетерогенном хранении данных. В последнем случае для упрощения прикладного кода мы используем специализированные фреймворки (для управления распределенными транзакциями или повествованиями).
Переходя от инструментов к архитектурным методам, в контексте согласованности и изоляции очень выгодную позицию занимает объектный подход и DDD, в котором предлагается концепция ограниченных контекстов, агрегата и необходимость соблюдения инвариантов. Похожих целей пытаются добиться при использовании шаблона Event Sourcing. Иначе говоря, основная цель - сделать так, чтобы программная модель обеспечивала жесткие рамки, направляющие разработчика писать корректный код. Пожалуй, последнее - это то, к чему мы все должны стремиться. 😜
***
Надеюсь, что было интересно и не скучно. 😃 А у вас есть интересные истории, когда даже транзакции не спасали от страшного? Или успешные истории, как и где можно жить без ACID?
#arch #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3🤔1
Хочешь рисуй, не хочешь - вызывай REST
Решил завести нерегулярную рубрику "Утилиты" #tools, в которой буду делиться своими находками удобных и полезных инструментов. Если сталкивались с чем-то похожим, делитесь своими подборками в комментариях. 😉👇
⚔️ Excalidraw
Давно хотел найти простой и удобный векторный редактор, в котором можно делать неформальные диаграммы со стилизацией рисования от руки. Когда я набрел на Excalidraw, я был в восторге. Прекрасный инструмент с открытым исходным кодом, который превзошел все мои ожидания. Есть публичная библиотека готовых объектов; есть горячие клавиши; есть возможность сохранения в файл, экспорта в PNG/SVG. Наконец, есть возможность делиться ссылкой и рисовать что-то совместно - отличное средство во время переговоров, учитывая что по итогу у вас будет красивая и понятная картинка, которую не стыдно сохранить для истории.
🦬 httpYac
Иногда, когда я запускаю Postman и жду, жду, жду... Думаю, что вы меня поняли.😄 В эти моменты у меня возникает дикое желание найти ему простую замену, особенно когда не требуется вся его функциональность. В IntelliJ IDEA есть то, что мне бы идеально подошло для большинства случаев - HTTP Client, но он доступен только в Ultimate-редакции. В итоге я нашел прекрасную альтернативу в виде плагина для VSCode. Этот инструмент тоже с открытым исходным кодом, делает то, что мне нужно, предоставляет возможность шаблонизации URL и тела запроса. Пока я только обкатываю этого яка, но, судя по документации он может гораздо больше.
#tools
Решил завести нерегулярную рубрику "Утилиты" #tools, в которой буду делиться своими находками удобных и полезных инструментов. Если сталкивались с чем-то похожим, делитесь своими подборками в комментариях. 😉
⚔️ Excalidraw
Давно хотел найти простой и удобный векторный редактор, в котором можно делать неформальные диаграммы со стилизацией рисования от руки. Когда я набрел на Excalidraw, я был в восторге. Прекрасный инструмент с открытым исходным кодом, который превзошел все мои ожидания. Есть публичная библиотека готовых объектов; есть горячие клавиши; есть возможность сохранения в файл, экспорта в PNG/SVG. Наконец, есть возможность делиться ссылкой и рисовать что-то совместно - отличное средство во время переговоров, учитывая что по итогу у вас будет красивая и понятная картинка, которую не стыдно сохранить для истории.
🦬 httpYac
Иногда, когда я запускаю Postman и жду, жду, жду... Думаю, что вы меня поняли.
#tools
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍5⚡1
Calvin Protocol для распределенных транзакций
Многие знают про протокол двухфазной фиксации (2PC), но мало кто слышал про протокол Calvin. Честно говоря, до недавних пор я тоже относился к этому меньшинству, поэтому решил поделиться своей находкой с вами. Однако для начала предлагаю освежить память. 🥸😃
ℹ️ Распределенная транзакция - это транзакция, затрагивающая несколько ресурсов распределенной системы. Как и обычные транзакции в монолитных базах данных, распределенные действуют по принципу "всё или ничего". Тематика достаточно стара, хорошо проработана, отражена в стандарте X/Open XA (1991), который реализован на многих платформах. Таким образом, концепция распределенных транзакций появилась задолго до появления шумихи вокруг микросервисов, но сейчас особенно актуальна и рассматривается как возможный инструмент обеспечения согласованности данных.
ℹ️ Протокол двухфазной фиксации (2PC) часто рассматривается как синоним реализации распределенных транзакций. До недавних пор это было вполне справедливо, но на самом деле эти термины не являются синонимами. Главными преимуществами 2PC является его прикладная универсальность и относительная простота реализации. Главными недостатками 2PC являются длительные блокировки, неустойчивость к сбоям, отсутствие изоляции. Вместе с этим блокировки все-таки локальны по отношению к ресурсу и не мешают конкурентному выполнению транзакций (в отличие от Calvin) .
В 2012 была опубликована статья "Calvin: Fast Distributed Transactions for Partitioned Database Systems" с описанием нового подхода к реализации распределенных транзакций. В его основу положена идея формирования журнала транзакций и подачи его на вход исполнителю, вместо того чтобы позволить ему самому формировать журнал. (Под исполнителем понимается какой-то ресурс, например, реплика базы данных.) Такой подход позволяет уменьшить число сетевых взаимодействий, обеспечив высокую скорость выполнения распределенных транзакций.
Calvin обеспечивает порядок выполнения транзакций, назначая каждой порядковый номер. Иначе говоря, имеется виртуальная глобальная очередь, которая формируется до того, как исполнители начнут обрабатывать транзакции. Будучи упорядоченными, транзакции всегда получают необходимые блокировки в одном и том же порядке. Благодаря строгому и предопределенному порядку следований транзакций и блокировок гарантируется итоговая согласованность исполнителей.
Таким образом, можно обозначить следующие особенности подхода:
1️⃣ Один и тот же журнал можно подавать на вход любому количеству исполнителей.
2️⃣ Если исполнитель записал транзакцию в свой журнал, значит, эта транзакция выполнена.
3️⃣ Если одна транзакция останавливается в ожидании доступа к диску, все остальные транзакции тоже ждут!
🔥 Несомненным достоинством Calvin является практически неограниченная возможность горизонтального масштабирования с сохранением ACID-гарантий. Причём гарантии обеспечиваются даже в случаях, когда транзакция охватывает несколько распределенных партиций.
❗️ Между тем, система хорошо масштабируется только в том случае, если разные приложения работают с разными данными. При наличии записей, за которые идёт высокая конкуренция, возможен резкий рост накладных расходов на повторное планирование транзакций.
Резонный вопрос: есть ли практические реализации и опыт использования этого подхода? Да, есть. Например, разработчики Apache Cassandra разрабатывают совместимый продукт под названием Accord. Он должен позволить выполнять запросы к Cassandra, объединяя их в ACID-транзакции. Однако гораздо бо́льших успехов добились разработчики YDB, о чём можно почитать в их официальном блоге.
P.s. Жду от вас историй про опыт работы с распределёнными транзакциями или YDB. 😉👇
#db
Многие знают про протокол двухфазной фиксации (2PC), но мало кто слышал про протокол Calvin. Честно говоря, до недавних пор я тоже относился к этому меньшинству, поэтому решил поделиться своей находкой с вами. Однако для начала предлагаю освежить память. 🥸😃
В 2012 была опубликована статья "Calvin: Fast Distributed Transactions for Partitioned Database Systems" с описанием нового подхода к реализации распределенных транзакций. В его основу положена идея формирования журнала транзакций и подачи его на вход исполнителю, вместо того чтобы позволить ему самому формировать журнал. (Под исполнителем понимается какой-то ресурс, например, реплика базы данных.) Такой подход позволяет уменьшить число сетевых взаимодействий, обеспечив высокую скорость выполнения распределенных транзакций.
😀 Подход был назван не в честь производителя трусов, как можно было бы подумать изначально, а в честь французского богослова Жана Кальвина (Jean Calvin), считавшего, что все события человеческой жизни предопределены Богом. Ведь если журнал сформирован заранее, то и результат исполнения транзакций из этого журнала предопределён.
Calvin обеспечивает порядок выполнения транзакций, назначая каждой порядковый номер. Иначе говоря, имеется виртуальная глобальная очередь, которая формируется до того, как исполнители начнут обрабатывать транзакции. Будучи упорядоченными, транзакции всегда получают необходимые блокировки в одном и том же порядке. Благодаря строгому и предопределенному порядку следований транзакций и блокировок гарантируется итоговая согласованность исполнителей.
Таким образом, можно обозначить следующие особенности подхода:
Резонный вопрос: есть ли практические реализации и опыт использования этого подхода? Да, есть. Например, разработчики Apache Cassandra разрабатывают совместимый продукт под названием Accord. Он должен позволить выполнять запросы к Cassandra, объединяя их в ACID-транзакции. Однако гораздо бо́льших успехов добились разработчики YDB, о чём можно почитать в их официальном блоге.
P.s. Жду от вас историй про опыт работы с распределёнными транзакциями или YDB. 😉
#db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥5⚡1
Удаление конфиденциальных данных
Бывает так, что встречаешь описание интересного подхода или алгоритма, а потом про него забываешь, так как теория не была подкреплена практикой или прошло очень много времени. И вот когда наступает момент, где можно блеснуть своими знаниями, приходится тратить время, чтобы вспомнить детали. 😃 В очередной раз, когда я поймал себя на подобной мысли, я решил, что было бы неплохо делиться подобными находками. 🤔 #tip
Сегодня расскажу о способе моментального удаления конфиденциальных данных.
Контекст
При удалении агрегата может потребоваться удаление всех связанных с ним данных. При наличии физических связей, таких как внешние ключи в реляционных базах данных, подобное требование реализовать нетрудно. Однако связь между агрегатом и его данными может быть не такой прямолинейной, тогда задача существенно усложняется. Например, реквизиты пользователя оказались в каком-либо журнале или таблице для построения отчетной формы.
Так или иначе, удаление может стать непростой задачей, особенно если система заранее не была рассчитана на подобные операции. Сложность или невозможность удаления может быть вызвана следующими причинами:
🕚 Удаление запрещено на уровне бизнес-логики. Например, в системе есть журнал событий, который является отражением действий пользователя. При удалении учетной записи пользователя мы должны удалить его персональную информацию, если она содержалась в событиях, но не можем удалить сами события, поскольку это запрещено юридически.
🕚 Архитектурные ограничения. Чаще всего являются прямым следствием бизнес-требований. Например, разработчики решили, что для реализации большей части требований к системе идеально подходит шаблон Event Sourcing.
🕚 Очень много данных для очистки. Возможно, что в системе накопилось очень много данных, которые должны быть подвержены анализу с целью зачистки. В случае отсутствия специализированных индексов, которые бы ускоряли процесс поиска, он может оказаться неприемлемо долгим и ресурсоемким.
🕚 Сложность физического удаления. Для многих баз данных операции В общем, большинство баз спроектировано, чтобы хранить данные, а не удалять. 😃
Проблема
Большие сложности или невозможность произвести физическое удаление данных, связанных с каким-либо агрегатом системы.
Решение
Хранить секретные данные в зашифрованном виде с использованием симметричного шифрования. Ключ шифрования хранить вместе с агрегатом. При удалении агрегата, удалять и ключ шифрования. Без ключа шифрования зашифрованные данные, в сущности, удалены, так как не могут быть расшифрованы.
Плюсы
Данные "удаляются" моментально, сразу, как только будет удален ключ шифрования. В этом смысле подход напоминает логическое удаление и, кстати, может использоваться с ним совместно.
Минусы
Данные продолжают занимать место на диске. Возникает необходимость в шифровании/дешифровании при каждой записи/чтении.
***
P.s. Сталкивались ли вы с подобной проблемой на практике и как решали? 😉 Однажды наблюдал ситуацию утечки данных, и выяснилось, что база, которая в общем случае деперсонифицирована, в некоторых атрибутах содержала персональную информацию в открытом виде. Эти данные попали туда в ходе интеграции с другими системами, разработчики которой не задумались о необходимости ее шифрования или поиска более подходящего места для ее хранения.
Бывает так, что встречаешь описание интересного подхода или алгоритма, а потом про него забываешь, так как теория не была подкреплена практикой или прошло очень много времени. И вот когда наступает момент, где можно блеснуть своими знаниями, приходится тратить время, чтобы вспомнить детали. 😃 В очередной раз, когда я поймал себя на подобной мысли, я решил, что было бы неплохо делиться подобными находками. 🤔 #tip
Сегодня расскажу о способе моментального удаления конфиденциальных данных.
Контекст
При удалении агрегата может потребоваться удаление всех связанных с ним данных. При наличии физических связей, таких как внешние ключи в реляционных базах данных, подобное требование реализовать нетрудно. Однако связь между агрегатом и его данными может быть не такой прямолинейной, тогда задача существенно усложняется. Например, реквизиты пользователя оказались в каком-либо журнале или таблице для построения отчетной формы.
Так или иначе, удаление может стать непростой задачей, особенно если система заранее не была рассчитана на подобные операции. Сложность или невозможность удаления может быть вызвана следующими причинами:
UPDATE и DELETE проблематичны. Например, для MariaDB удаление - это настолько нетривиальная задача, что ее разработчики подготовили целую инструкцию - "Big DELETEs". Аналогичные проблемы имеются и у MySQL. В PostgreSQL частые удаления могут быть одной из причин раздувания базы. У Cassandra удаление может приводить к большой загрузке узлов во время компоновки. Проблема
Большие сложности или невозможность произвести физическое удаление данных, связанных с каким-либо агрегатом системы.
Решение
Хранить секретные данные в зашифрованном виде с использованием симметричного шифрования. Ключ шифрования хранить вместе с агрегатом. При удалении агрегата, удалять и ключ шифрования. Без ключа шифрования зашифрованные данные, в сущности, удалены, так как не могут быть расшифрованы.
Плюсы
Данные "удаляются" моментально, сразу, как только будет удален ключ шифрования. В этом смысле подход напоминает логическое удаление и, кстати, может использоваться с ним совместно.
Минусы
Данные продолжают занимать место на диске. Возникает необходимость в шифровании/дешифровании при каждой записи/чтении.
***
P.s. Сталкивались ли вы с подобной проблемой на практике и как решали? 😉 Однажды наблюдал ситуацию утечки данных, и выяснилось, что база, которая в общем случае деперсонифицирована, в некоторых атрибутах содержала персональную информацию в открытом виде. Эти данные попали туда в ходе интеграции с другими системами, разработчики которой не задумались о необходимости ее шифрования или поиска более подходящего места для ее хранения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥4⚡1
Проблемы изоляции транзакций (1/3)
Меня все никак не отпускает тема транзакций и изоляции. 😃 Сегодняшний пост будет подводкой к двум последующим. Возможно, будет немного "душно", но попрошу потерпеть.😄
〰️ 〰️ 〰️
Конкурентный доступ к данным - одна из основных проблем при реализации изоляции транзакций. Способ решения этой проблемы определяет ключевые характеристики базы данных, на которые мы опираемся при выборе подходящего хранилища для своих проектов. И так повелось, что со времен изобретения SQL-стандарта так и не появилось однозначного определения "уровней изоляции транзакций", благодаря чему у каждой базы данных своё представление относительно этого вопроса. А разбираться с этим многообразием приходится нам - пользователям этих продуктов. 🤷🏻♂️
Если посмотреть на определение ACID, то оно не предполагает какой-либо вариативности относительно изоляции транзакций. Тем не менее, реализация таких жестких требований напрямую отражается на пропускной способности. Вследствие этого в SQL-стандарте имеется термин "уровень изоляции транзакции", предполагающий "компромисс", на который может пойти разработчик в случае, если ему потребуется большая пропускная способность. Иначе говоря, нам предлагают улучшить производительность приложения за счет корректности данных, с которыми оно работает. 😬 Ясно, что на подобный компромисс нужно идти осознанно, понимая, что именно может пойти не так при выборе определенного уровня изоляции и устраивает ли нас это.
SQL-стандарт определяет всего три феномена (phenomena), т.е. три типа нежелательных последствий, возможных при снижении уровня изоляции: грязное чтение (dirty read), неповторяющееся чтение (non-repeatable read) и фантом (phantom). Эта слабая категоризация послужила причиной вольных трактовок при реализации уровней изоляции. Вскоре этот момент был подвержен критике, и список возможных последствий был расширен и конкретизирован путем ввода нового понятия - аномалия (anomaly). Аномалии конкретизируют действия, которые могут привести к феномену. Существует замечательный исследовательский проект Hermitage, в котором определена современная классификация аномалий и в разрезе них приведено сравнение одних и тех же уровней изоляции в разных популярных базах данных (Oracle, PostgreSQL, MySQL и др.).
В качестве иллюстрации можно рассмотреть феномен неповторяющегося чтения. Транзакция
Краткая запись этого феномена выглядит так:
#dev #db
Меня все никак не отпускает тема транзакций и изоляции. 😃 Сегодняшний пост будет подводкой к двум последующим. Возможно, будет немного "душно", но попрошу потерпеть.
Конкурентный доступ к данным - одна из основных проблем при реализации изоляции транзакций. Способ решения этой проблемы определяет ключевые характеристики базы данных, на которые мы опираемся при выборе подходящего хранилища для своих проектов. И так повелось, что со времен изобретения SQL-стандарта так и не появилось однозначного определения "уровней изоляции транзакций", благодаря чему у каждой базы данных своё представление относительно этого вопроса. А разбираться с этим многообразием приходится нам - пользователям этих продуктов. 🤷🏻♂️
Если посмотреть на определение ACID, то оно не предполагает какой-либо вариативности относительно изоляции транзакций. Тем не менее, реализация таких жестких требований напрямую отражается на пропускной способности. Вследствие этого в SQL-стандарте имеется термин "уровень изоляции транзакции", предполагающий "компромисс", на который может пойти разработчик в случае, если ему потребуется большая пропускная способность. Иначе говоря, нам предлагают улучшить производительность приложения за счет корректности данных, с которыми оно работает. 😬 Ясно, что на подобный компромисс нужно идти осознанно, понимая, что именно может пойти не так при выборе определенного уровня изоляции и устраивает ли нас это.
SQL-стандарт определяет всего три феномена (phenomena), т.е. три типа нежелательных последствий, возможных при снижении уровня изоляции: грязное чтение (dirty read), неповторяющееся чтение (non-repeatable read) и фантом (phantom). Эта слабая категоризация послужила причиной вольных трактовок при реализации уровней изоляции. Вскоре этот момент был подвержен критике, и список возможных последствий был расширен и конкретизирован путем ввода нового понятия - аномалия (anomaly). Аномалии конкретизируют действия, которые могут привести к феномену. Существует замечательный исследовательский проект Hermitage, в котором определена современная классификация аномалий и в разрезе них приведено сравнение одних и тех же уровней изоляции в разных популярных базах данных (Oracle, PostgreSQL, MySQL и др.).
В качестве иллюстрации можно рассмотреть феномен неповторяющегося чтения. Транзакция
T1 делает два последовательных чтения значения x: сначала считывает значение 10, затем 20. Так происходит, потому что значение x успели поменять в параллельно выполняющейся транзакции T2.T1: r[x=10].........r[x=20].
T2: ........w[x=20].........
Краткая запись этого феномена выглядит так:
r1[x=10],w2[x=20],r1[x=20]. Данный феномен возможен, например, в режиме Read Committed. Аномалия для этого режима изоляции выглядит так: r1[x=10],w2[x=20],c2,r1[x=20] (т.е. после записи вторая транзакция фиксируется - c2). Примерно в таком стиле происходит формализация аномалий и их тестирование в разных базах данных.#dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3⚡1
Проблемы изоляции транзакций (2/3)
Зная и понимая возможные аномалии, исключаем те из них, появление которых неприемлемо для нашего приложения, и таким образом выбираем подходящий уровень изоляции.
Рассмотрим классические уровни изоляции, которые есть в большинстве баз. 🧐
⭐️ Read Committed. Исключает грязное чтение и запись, т.е. транзакция может читать и изменять только зафиксированные изменения. Ключевой момент в том, что учитываются даже те изменения, которые были зафиксированы во время выполнения текущей транзакции. Обычно на уровне реализации грязную запись исключают за счет использования программных блокировок на уровне редактируемой строки (row-level lock); а грязное чтение - за счет хранения двух версий значения записи: последнее зафиксированное и еще не зафиксированное. Такой уровень изоляции установлен по умолчанию в PostgreSQL, MS SQL и Oracle. Допускает неповторяющееся чтение, потерю изменений (перезапись), искажение чтения/записи (read/write skew).
⭐️ ⭐️ Repeatable Read. Транзакция может читать только те изменения, которые были зафиксированы до ее начала. Обычно на уровне реализации грязную запись исключают за счет использования программных блокировок на уровне редактируемой строки (row-level lock); а грязное чтение - за счет хранения нескольких версий значения записи - алгоритм MVCC (Multi-Version Concurrency Control). Такой уровень изоляции установлен по умолчанию в MySQL и MariaDB. Допускает искажение чтения/записи (read/write skew), но в MySQL и MariaDB даже потерю изменений (перезапись). Идеально подходит для создания бэкапов или выполнения долгих read-only транзакций (например, сложные аналитические запросы).
⭐️ ⭐️ ⭐️ Serializable. Гарантирует, что даже при параллельном исполнении транзакций результат будет точно таким же, как если бы они исполнялись последовательно. Это определение полностью совпадает с определением изоляции в ACID. Позже этот уровень изоляции Daniel Abadi - один из соавторов протокола Calvin - назвал "идеальной изоляцией" (perfect isolation). Такой уровень изоляции установлен по умолчанию в CockroachDB и YDB. По определению он не должен допускать аномалий. (Примечательно, что в Oracle этот уровень изоляции на самом деле соответствует Repeatable Read.)
Можно подумать, что выбрав уровень Serializable, уйдут все проблемы. К сожалению, нет, если речь идет о распределенных базах данных. 😃 Там появляются дополнительные аномалии, большинство из которых связано с изменением порядка выполнения транзакций.
Например, последовательное выполнение трех транзакций
Решая эти проблемы, разработчики одних распределенных баз данных предпочитают скрыть от пользователя все эти сложности и особенности за привычными уровнями изоляции (CockroachDB, YugabyteDB, YDB); разработчики других, наоборот, изобретают свою классификацию уровней (CosmosDB), предоставляя максимальную гибкость в использовании.
#dev #db
Зная и понимая возможные аномалии, исключаем те из них, появление которых неприемлемо для нашего приложения, и таким образом выбираем подходящий уровень изоляции.
Рассмотрим классические уровни изоляции, которые есть в большинстве баз. 🧐
Можно подумать, что выбрав уровень Serializable, уйдут все проблемы. К сожалению, нет, если речь идет о распределенных базах данных. 😃 Там появляются дополнительные аномалии, большинство из которых связано с изменением порядка выполнения транзакций.
Например, последовательное выполнение трех транзакций
w1[x=1],w2[x=2],w3[x=3] может закончиться результатом x=2, поскольку реплика переупорядочила транзакции и в реальности выполнила w1,w3,w2. Такой исход вполне возможен, например, из-за рассинхронизации часов ⏰ на репликах в мультимастер-системах. Причем технически подобный исход будет считаться корректным, т.к. формальные требования упорядоченности транзакций (serializability) не нарушаются.Решая эти проблемы, разработчики одних распределенных баз данных предпочитают скрыть от пользователя все эти сложности и особенности за привычными уровнями изоляции (CockroachDB, YugabyteDB, YDB); разработчики других, наоборот, изобретают свою классификацию уровней (CosmosDB), предоставляя максимальную гибкость в использовании.
#dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2⚡1
Проблемы изоляции транзакций (3/3)
Надеюсь, что у меня получилось сформировать более целостную картину относительно уровней изоляции транзакций. 😉
Попытаюсь подвести итоги.
1️⃣ Выбирая уровень изоляции, помним про аномалии, оцениваем возможные риски и способы их минимизации.
2️⃣ Одни и те же уровни изоляции у всех реализованы по-разному, поэтому смотрим тесты Hermitage, обязательно пишем свои и читаем документацию.
3️⃣ Указываем уровень изоляции транзакции явно, помня, что большинство баз данных в целях улучшения производительности по умолчанию использует более слабые уровни изоляции.
4️⃣ Не допускаем конкурирующих транзакций с разным уровнем изоляции, иначе есть риск привести данные в несогласованное состояние.
5️⃣ Помним, что базы данных гарантируют техническую целостность данных, но не их согласованность с точки зрения бизнеса. Однако первое может значительно упростить реализацию второго.
〰️ 〰️ 〰️
Согласитесь, что жить с таким грузом очень тяжело!😄 Поэтому в следующий раз я планирую рассмотреть подходы и техники обеспечения согласованности данных с учетом всего вышесказанного. А пока предлагаю делиться своими феноменами и аномалиями. 😉👇
#dev #db
Надеюсь, что у меня получилось сформировать более целостную картину относительно уровней изоляции транзакций. 😉
Попытаюсь подвести итоги.
🗂 Пока готовил этот пост, открыл для себя проект Jepsen. Это фреймворк для тестирования распределенных систем на предмет согласованности и корректности работы в условиях сбоев. Инструмент является стандартом де-факто для проверки многих популярных распределённых систем и баз данных. Интересно, насколько реально/удобно использовать этот инструмент для тестирования прикладных проектов... 🤔
Согласитесь, что жить с таким грузом очень тяжело!
#dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3⚡1👍1