стандартный паттерн миринда что это
Проект Miranda NG получает приз «дикие указатели» (часть первая)
О проверке Miranda NG
Проект Miranda NG — это преемник популярного мультипротокольного IM-клиента для Windows, Miranda IM.
Вообще, изначально я не собирался проверять Miranda NG. Нам просто нужно несколько активно развивающихся проектов, чтобы тестировать новую фичу PVS-Studio. Можно использовать специальную базу, в которой хранится информация о сообщениях, которые не надо выдавать. Подробнее про это рассказано здесь. Идея в следующем. Иногда сложно внедрить статический анализ в большой проект, так как выдаётся слишком много предупреждений и непонятно, что с ними делать и кому это поручить. Но хочется начать получать пользу от статического анализа уже сейчас. Поэтому для начала можно скрыть все предупреждения и рассматривать только новые, которые появляются в процессе написания нового кода или рефакторинга. А уж потом, когда есть силы и желание, можно потихоньку править ошибки в старом коде.
Одним из активно развивающихся проектов оказался Miranda NG. Но когда я посмотрел, что выдал PVS-Studio при первом запуске, я понял, что у меня есть материал на новую статью.
Итак, давайте посмотрим, что нашел статический анализатор кода PVS-Studio в исходных кодах Miranda NG.
Для проверки Miranda NG из репозитория был взят Trunk. Хочу отметить, что я смотрел отчёт анализатора весьма поверхностно и наверняка многое упустил. Я пробежался только по диагностикам общего назначения 1 и 2-ого уровня. Третий уровень я даже не стал смотреть. Мне и первых двух хватило с избытком.
Часть первая. Указатели и работа с памятью
Разыменовывание нулевого указателя
Предупреждение PVS-Studio: V522 Dereferencing of the null pointer ‘cont’ might take place. EmLanProto mlan.cpp 342
Здесь все просто. Раз указатель равен NULL, то давайте его разыменуем и посмотрим, что весёлого из этого получится.
В начале используем указатель, потом проверяем
Таких ошибок в Miranda NG тьма тьмущая, как и в любом приложении. Обычно такой код работает, так как в функцию приходит ненулевой указатель. А вот если нулевой, то функции к этому не готовы.
Предупреждение PVS-Studio: V595 The ‘dat’ pointer was utilized before it was verified against nullptr. Check lines: 428, 430. TabSRMM buttonsbar.cpp 428
Если в функцию BB_InitDlgButtons() передать NULL, то проверка будет сделана слишком поздно. Анализатор выдал на код проекта Miranda NG ещё 164 таких предупреждения. Нет смысла приводить их в статье. Вот все они списком: MirandaNG-595.txt.
Потенциально неинициализированный указатель
Предупреждение PVS-Studio: V614 Potentially uninitialized pointer ‘url’ used. IEView ieview.cpp 1117
Если условие if (SUCCEEDED(. )) не выполняется, то переменная ‘url’ остаётся неинициализированной и функция должна вернуть непонятно что. Но не всё так просто. Код содержит ещё одну ошибку. Неправильно поставлена закрывающаяся скобка. В результате макрос SUCCEEDED применяется к выражению типа ‘bool’, что не имеет смысла.
Второй баг компенсирует первый. Посмотрим, что такое макрос SUCCEEDED:
Выражение типа ‘bool’ равно 0 или 1. В свою очередь, 0 или 1 всегда >= 0. Получается, что макрос SUCCEEDED всегда возвращает истину и переменная ‘url’ всегда инициализируется.
Только что мы воочию увидели красивый пример, когда один баг компенсирует другой. Если исправить условие, проявит баг с неинициализированной переменной.
Если иcправить 2 ошибки, то код будет выглядеть так:
Анализатор подозревает неладное ещё в 20 местах. Вот они: MirandaNG-614.txt.
Путаница между размером массива и количеством элементов
Количество элементов в массиве и размер массива в байтах — две разные сущности. Однако, если быть недостаточно внимательным, их вполне можно перепутать. Проект Miranda NG демонстрирует множество способов, как может выглядеть такая путаница.
Больше всего вреда нанёс макрос SIZEOF:
Этот макрос вычисляет количество элементов в массиве. Но, видимо, кто-то из программистов считает, что это аналог оператора sizeof(). Правда, не понятно, зачем он тогда использует макрос, а не стандартный sizeof(). Так что есть и другой вариант — кто-то не знает, как использовать функцию memcpy().
Предупреждение PVS-Studio: V512 A call of the ‘memcpy’ function will lead to underflow of the buffer ‘s_list’. Sessions utils.cpp 288
Функция memcpy() скопирует только часть массива, так как третий аргумент задаёт размер массива в байтах.
Точно так же неправильно макрос SIZEOF() используется ещё в 8 местах: MirandaNG-512-1.txt.
Следующая беда. Часто программисты забывают поправить вызовы memset()/memcpy() когда внедряют в программу Unicode:
А вот пример частичного копирования строки:
Предупреждение PVS-Studio: V512 A call of the ‘memcpy’ function will lead to underflow of the buffer ‘L«mailto:»’. TabSRMM msgdialog.cpp 2085
Будет скопирована только часть строки. Каждый символ строки занимает 2 байта. Значит скопировать надо 14 байт, а не 7.
Предупреждение PVS_Studio: V512 A call of the ‘memset’ function will lead to underflow of the buffer ‘logfonts’. TabSRMM msglog.cpp 134
Кто-то поспешил и смешал в кучу размер объекта и их количество. Прибавлять двойку нужно до умножения. Корректный код:
В следующем примере хотели, как лучше, использовали sizeof(), но вновь запутались с размерами. Получили значение больше, чем нужно.
Предупреждение PVS-Studio: V620 It’s unusual that the expression of sizeof(T)*N kind is being summed with the pointer to T type. Scriver input.cpp 387
Переменная ‘tr.lpstrText’ указывает на строку, состоящую из символов типа wchat_t. Если хочется пропустить 7 символов, то нужно просто прибавить 7. Не нужно умножать на sizeof(wchar_t).
Такая же ошибка здесь: ctrl_edit.cpp 351
К сожалению, это ещё не конец. Ещё можно ошибиться так:
Предупреждение PVS-Studio: V641 The size of the allocated memory buffer is not a multiple of the element size. KeyboardNotify options.cpp 718
Забыли умножить на sizeof(TCHAR). В этом же файле можно увидеть ещё 2 ошибки в строках 819 и 1076.
И последний фрагмент кода на тему количества элементов:
Предупреждения PVS-Studio: V635 Consider inspecting the expression. The length should probably be multiplied by the sizeof(wchar_t). KeyboardNotify main.cpp 543
Ещё стоит дописать умножение на sizeof(TCHAR) здесь: options.cpp 1177, options.cpp 1204.
С размерами разобрались, перейдём к другим способам выстрелить себе в ногу указателем.
Выход за границу массива
V512 A call of the ‘strcat’ function will lead to overflow of the buffer ‘fn’. NimContact files.cpp 290
Строка «_timer» не влезает в массив ‘fn’. Хотя в строке всего 6 символов, нужно не забывать про терминальный 0. Теоретически здесь имеет место неопределённое поведение. На практике получится, что будет задет массив ‘tmp’. В нулевой элемент массива ‘tmp’ будет записан ‘0’.
Следующий пример ещё печальней. Здесь испортится HANDLE какой-то иконки:
Предупреждение PVS-Studio: V512 A call of the ‘strcpy’ function will lead to overflow of the buffer ‘cap.caps’. New_GPG main.cpp 2246
Вновь не учтён терминальный 0. Возможно, здесь уместнее было бы воспользоваться функцией memcpy().
Великая и ужасная функция strncat()
Многие слышали про опасность функции strcat() и используют на их взгляд более безопасную strncat(). Вот только редко кто умеет обращаться с этой функцией правильно. Она намного опаснее, чем может показаться. Дело в том, что третий аргумент задаёт не максимальную длину буфера, а сколько в буфере осталось свободного места.
Вот такой код совершенно некорректен:
Предупреждение PVS-Studio: V645 The ‘strncat’ function call could lead to the ‘buff’ buffer overflow. The bounds should not contain the size of the buffer, but a number of characters it can hold. Miranda fontoptions.cpp 162
Если, ‘buff’ занят на половину, то такой код не обратит на это внимание и позволит добавить ещё 1000 символов. И таким образом произойдет выход за границу массива. Причем очень существенный. С таким же успехом можно было просто писать strcat().
В Miranda NG есть ещё 48 мест где так неправильно используется strncat(). Вот они: MirandaNG-645-1.txt.
Кстати, эти места в коде можно рассматривать как потенциальные уязвимости.
В оправдание программистов из Miranda NG, стоит отметить, что некоторые всё таки читали описание функции strncat(). Они пишут так:
Предупреждение PVS-Studio: V645 The ‘strncat’ function call could lead to the ‘filename’ buffer overflow. The bounds should not contain the size of the buffer, but a number of characters it can hold. GG filetransfer.cpp 273
К сожалению, это опять неправильно. По крайней мере так можно испортить 1 байт за пределами массива. И я думаю, вы уже догадались, что причина в злосчастном терминальном нуле. Он не учтён.
Поясним эту ошибку на простом примере:
В буфере уже нет места для новых символов. В нём находится 4 символа и терминальный ноль. Выражение «5 — strlen(buf)» равно 1. Функция strncpy() скопирует символ «E» в последний элемент массива ‘buf’. Терминальный 0 будет записан уже за пределами буфера.
Остальные 34 места кода собраны здесь: MirandaNG-645-2.txt.
Эротика с использованием new[] и delete
Кто-то систематически забывает писать квадратные скобки для оператора delete:
Предупреждение PVS-Studio: V611 The memory was allocated using ‘new T[]’ operator but was released using the ‘delete’ operator. Consider inspecting this code. It’s probably better to use ‘delete [] workingDir;’. IEView ieview_main.cpp 68
Впрочем, такие ошибки часто обходятся без видимых последствии. Именно поэтому я отнёс их к разделу «эротика». Более жесткое зрелище ожидает ниже.
Разврат с использованием new, malloc, delete и free
Путаются способы выделения и освобождения памяти:
Предупреждение PVS-Studio: V611 The memory was allocated using ‘new’ operator but was released using the ‘free’ function. Consider inspecting operation logics behind the ‘piWidths’ variable. MirandaG15 clcdlabel.cpp 209
Бессмысленные проверки
В случае нехватки памяти обыкновенный оператор ‘new’ генерирует исключение. Поэтому нет смысла проверять указатель, который вернул оператор ‘new’ на равенство нулю.
Обычно лишняя проверка безобидна. Однако, иногда встречается вот такой код:
Предупреждение PVS-Studio: V668 There is no sense in testing the ‘ar’ pointer against null, as the memory was allocated using the ‘new’ operator. The exception will be generated in the case of memory allocation error. ICQ icq_avatar.cpp 608
В случае ошибки следует освободить мьютекс. Но этого не произойдёт. В случае ошибки создания объекта события будут развиваться совсем не так, как планирует программист.
Предлагаю разработчикам проверить следующие 83 аналогичных предупреждений анализатора: MirandaNG-668.txt.
Путаница между SIZEOF() и _tcslen()
Предупреждение PVS-Studio: V514 Dividing sizeof a pointer ‘sizeof (dbv.ptszVal)’ by another value. There is a probability of logical error presence. TranslitSwitcher layoutproc.cpp 827
Здесь написано что-то странное. Макрос SIZEOF() применяется к указателю, что не имеет никакого смысла. Есть подозрения, что хотели подсчитать длину строки. Тогда для этого следует использовать функцию _tcslen().
Порча vptr
Предупреждение PVS-Studio: V598 The ‘memset’ function is used to nullify the fields of ‘CBaseCtrl’ class. Virtual method table will be damaged by this. UInfoEx ctrl_base.cpp 77
Программист поленился и для обнуления полей класса воспользовался функцией ZeroMemory(). Он не учёл, что этот класс содержит указатель на таблицу виртуальных методов. В базовом классе многие методы объявлены как виртуальные. Порча указателя на таблицу виртуальных методов приведёт к неопределённому поведению при работе с объектом, инициализированным таким кустарным методом.
Время жизни объектов
Предупреждение PVS-Studio: V506 Pointer to local variable ‘psr’ is stored outside the scope of this variable. Such a pointer will become invalid. Miranda findadd.cpp 777
Объект ‘psr’ перестанет существовать, когда произойдёт выход из else-ветви. Однако, указатель на этот объект был сохранён и будет в дальнейшем использоваться. Пример настоящего «дикого указателя». К чему приведёт работа с ним — неизвестно.
Ещё один аналогичный пример:
Предупреждение PVS-Studio: V507 Pointer to local array ‘str’ is stored outside the scope of this array. Such a pointer will become invalid. Miranda genmenu.cpp 973
Текст распечатывается во временный массив, который тут же уничтожается. Однако, указатель на этот массив будет использован где-то в другой части программы.
Удивительно, как такие программы вообще работают. Ещё 9 мест, где обитают дикие указатели: MirandaNG-506-507.txt.
Мучения 64-битных указателей
Я не изучал 64-битные диагностики. Посмотрел только предупреждения с номером V220. Почти каждое такое предупреждение — самая настоящая ошибка.
Пример некорректного кода с точки зрения 64-битности:
Куда-то нужно передать 64-битный указатель. Для этого, его нужно превратить в тип LPARAM. Однако, вместо этого указатель насильственно превращают в 32-битный тип LONG. И только потом он будет автоматически расширен до LONG_PTR. Эта ошибка пришла из 32-битных времён, когда типы LONG и LPARAM совпадали. Теперь это не так. Будут испорчены старшие 32 бита в 64-битном указателе.
Такие баги неприятны тем, что очень неохотно проявляют себя. Будет везти, пока память выделяется в младших адресах памяти.
Вот ещё 20 мест, где портятся 64-битные указатели: MirandaNG-220.txt.
Неочищенные приватные данные
Предупреждение PVS-Studio: V597 The compiler could delete the ‘memset’ function call, which is used to flush ‘kappa’ buffer. The RtlSecureZeroMemory() function should be used to erase the private data. Cryptlib cast.cpp 293
В Release версии компилятор удалит вызов функции memset(). Почему так, можно узнать из описания диагностики.
Не затрутся приватные данные ещё в 6 местах: MirandaNG-597.txt.
Разное
Есть ещё пара предупреждений анализатора, которые я свалю в одну кучу.
Предупреждение PVS-Studio: V512 A call of the ‘memset’ function will lead to underflow of the buffer ‘Data’. Weather weather_ini.cpp 250
Выражение ‘sizeof(Data)’ возвращает размер указателя, а не WIDATA. Будет обнулена только часть объекта. Правильно будет написать: sizeof(*Data).
Предупреждение PVS-Studio: V713 The pointer ftcd was utilized in the logical expression before it was verified against nullptr in the same logical expression. Sametime files.cpp 423
В условии цикла указатель ‘ftcd’ в начале разыменовывается, а только потом проверяется. Видимо, выражение стоит переписать так:
Заключение
Работа с указателями и памятью — не единственное, из чего состоят программы на Си++. В следующей статье мы рассмотрим другие разновидности ошибок, обнаруженных в Miranda NG. Их поменьше, но всё равно достаточно много.
Эта статья на английском
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Miranda NG Project to Get the «Wild Pointers» Award (Part 1).
Акция Mirinda «Пусть мир скажет WOW!» – выиграйте 20 000 рублей для сервиса Vpodarok!
Акция завершилась 29.08.2021
Акция Mirinda «Пусть мир скажет WOW!» проводится с 14 июня по 29 августа 2021 года. Покупайте напиток Mirinda, находите коды под крышечками, регистрируйте коды на официальном сайте акции mirinda.ru, получите модный виртуальный лук, а также выиграйте сертификаты для разных сервисов, билеты в кино или брендированную футболку.
Как принять участие в акции Mirinda
Вы можете участвовать, начиная с 14 лет. Однако, если вам еще нет 18 лет, на это действие потребуется согласие со стороны родителей или опекунов, которые их заменяют. Правильный порядок действий выглядит следующим образом:
Чем больше кодов, тем лучше. Однако не подавайте более 5 заявок в день. Дело в том, что про правилам акции Mirinda 6 и последующие заявки будут удалятся. Лучше перенесите регистрацию на другой день. Храните чеки, а также крышечки с кодами.
Творческий конкурс
После регистрации на сайте вы сможете воспользоваться виртуальными луками и принять участие в творческом конкурсе акции Mirinda. Для этого нужно:
Участники этого творческого конкурса могут претендовать на получение дополнительного приза.
Что можно выиграть в акции Mirinda
Ежедневные призы:
Еженедельные призы:
Ежемесячные призы:
Призы за творческий конкурс:
Стандартный паттерн миринда что это
Для участия в Акции Участнику необходимо выполнить следующие действия:
Общий срок проведения Акции, включая период выдачи призов Победителям: период с «14» июня 2021г. по «30» октября 2021 г. (включительно).
Период совершения покупки: с «14» июня 2021г. по «29» августа 2021г. (включительно);
Период регистрации Кодов (далее – «Период регистрации Кодов»): с 12 часов 00 минут 00 секунд «14» июня 2021г. по 23 часа 59 минут 59 секунд (включительно) «29» августа 2021г. (по московскому времени).
Период выдачи призов Победителям Акции: с «01» июля 2021г. по «30» октября 2021 г. (включительно)
В Акции участвует следующая продукция в промо-упаковке (промо-этикетка и крышки с Кодами под ними):
Оператор 1: Оператором Акции, то есть юридическим лицом, созданным в соответствии с законодательством Российской Федерации, заключившим договор с Организатором Акции на проведение Акции в его интересах и по его поручению, является ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЛЕТО» (юридический адрес: 127015, Москва г, Новодмитровская Б. ул, дом № 14, строение 4, этаж 2, пом. IV, ком. 4З, ИНН 7715750935, КПП 771501001, ОГРН 1097746128039.
Обязанности Оператора 1: Работа промо сайта https://mirinda.ru, первичный сбор данных Участников Акции, контроль и реализация проведения Акции в целом, включая выдачу Главного приза Победителю Акции, исполнение функции налогового агента.
Оператор 2: Оператором Акции, то есть юридическим лицом, созданным в соответствии с законодательством Российской Федерации, заключившим договор с Организатором Акции на проведение Акции в его интересах и по его поручению, является ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ИНТЕРНЕТ-АГЕНТСТВО ДАЛЕЕ» (юридический адрес: 19270, г. Москва, Бутырская, 77, ИНН 7704642617, КПП 770401001, ОГРН 5077746435080.
Оператор 3: Оператором Акции, то есть юридическим лицом, созданным в соответствии с законодательством Российской Федерации, заключившим договор с Организатором Акции на проведение Акции в его интересах и по его поручению, является ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «АЙ СИ ЭН ИКС» (юридический адрес: 121059, г. Москва, ул. Киевская, д. 7, подъезд 7, этаж 5, помещение литер В, комнаты 40,4, ИНН 7720248752, КПП773001001, ОГРН 1037700169627.
Обязанности Оператора 3: Отправка писем-уведомлений участникам Акции.
Оператор 4: Оператором Акции, то есть юридическим лицом, созданным в соответствии с законодательством Российской Федерации, заключившим договор с Организатором Акции на проведение Акции в его интересах и по его поручению, является ИНДИВИДУАЛЬНЫЙ ПРЕДПРИНИМАТЕЛЬ ГАФАРОВ ВЛАДИСЛАВ КОНСТАНТИНОВИЧ (Юридический адрес: 144009, Московская область, г. Электросталь, ул. Юбилейная, д. 13, кв. 143. ОГРНИП 314505332200012. ИНН 505311232102.
Обязанности Оператора 4: Ответы на вопросы пользователей в Чат-боте Акции. Как я могу зарегистрировать код? Зарегистрировать Код, расположенный под крышкой продукции, можно на Сайте или в Чат-бот ВКонтакте и Telegram путем ввода Кода в соответствующем окне. Где и как я могу получить свой приз?
Призы стоимостью менее 4 000 (четырех тысяч) рублей в виде электронного кода или сертификата отображаются в разделе «Личный кабинет» на Сайте или диалогах Чат-бот ВКонтакте и Telegram. Моментом вручения Приза в виде электронного кода или сертификата признается факт проверки Кода Участника, за который он получил Приз, и этого отображения электронного кода или сертификата в разделе Личный кабинет на Сайте. После чего Участник принимает на себя риск утери кода или сертификата, в том числе, в связи с допуском третьих лиц к Социальной сети.
Для получения Призов стоимостью свыше 4000 (четырех тысяч) рублей Участник, признанный Победителем, в течение 5-и (пяти) календарных дней с момента отображение выигрыша в разделе «Личный кабинет » на Сайте или диалогах в Чат-боте ВКонтакте и Telegram обязан направить на электронный адрес support@mirinda.ru следующую информацию:
Участники Акции должны обеспечить возможность предоставления Оператору подлинников указанных выше документов / материалов для сверки с предоставленными ранее копиями таких документов / материалов.
Нужно ли сохранять чек? Нет Сколько призов я могу получить?
Один Участник Акции за весь период проведения Акции может получить следующее максимальное количество Призов Акции:
Для того, чтобы принять участие в Творческом конкурсе необходимо:
Скорее всего, с твоего аккаунта была замечена повышенная активность, поэтому он был заблокирован для дальнейшего участия в Акции.
Топ-5 архитектурных паттернов для распределённых систем
Распределённые приложения — главный элемент современной индустрии разработки ПО. Они имеют решающее значение для облачных сервисов хранения данных и позволяют веб-приложениям с огромной аудиторией оставаться реактивными. Для того чтобы эффективно проектировать эти системы, программисты используют фундаментальные блоки — паттерны распределённых систем.
Мы рассмотрим пять архитектур распределённых систем, их плюсы, минусы и области применения.
Что такое паттерн распределённой системы?
Паттерны проектирования — это проверенные способы создания систем, каждый из которых подходит для определённого случая. Паттерны абстрактны и не опираются на конкретную реализацию. Большинство паттернов разрабатываются и обновляются множеством разработчиков на протяжении многих лет. Поэтому они зачастую очень эффективны на старте разработки.
Паттерны — это строительные блоки, которые позволяют программистам использовать существующие знания вместо того, чтобы начинать с нуля строительство каждой системы. Кроме того они имеют набор стандартных моделей, которые помогают другим разработчикам понять, как их проекты могут взаимодействовать с данной системой.
Паттерны распределённых систем описывают взаимодействие различных узлов системы и то, как они обрабатывают задачи и виды процессов для различных задач.
Эти паттерны широко используются в архитектуре крупномасштабных облачных вычислений и систем масштабируемых микросервисов.
Типы паттернов распределённых систем
Большинство паттернов распределённых систем попадает в одну из трёх категорий, в зависимости от функциональности с которой они работают:
1. Разделение ответственности на команды и запросы (CQRS)
Этот паттерн предполагает разделение операций чтения и записи для увеличения масштабируемости и безопасности системы. Он использует команды для записи данных в постоянное хранилище (они ничего не возвращают) и запросы для обнаружения и получения данных (не могут изменять данные).
Команды и запросы обрабатываются центром управления, который получает запросы от пользователей. Затем центр получает данные и выполняет необходимые изменения, сохраняет их и уведомляет сервис выполняющий чтение. Этот сервис обновляет модель чтения и показывает изменения пользователю.
Область применения
CQRS отлично подходит для приложений, интенсивно использующих данные, например систем управления базами данных SQL или NoSQL. Также паттерн используется для архитектур микросервисов с большим объемом данных. Он прекрасно подходит для приложений, сохраняющих состояние благодаря разделению на писателя и читателя.
2. Двухфазная фиксация (2PC)
2PC похож на CQRS использованием транзакций и центра управления, но здесь разделение производится на основании того, на какой стадии находится транзакция. Есть две фазы: фаза подготовки (в которой центр управления сообщает службам подготовить данные) и фаза фиксации (которая сигнализирует службе отправить подготовленные данные).
Все сервисы в 2PC по умолчанию заблокированы и не могут отправлять данные. После завершения подготовки координатор по одному разблокирует сервисы и запрашивает их данные. Если сервис не готов подтвердить данные, координатор переходит к другому сервису. Когда все подготовленные данные отправлены сервисы остаются разблокированными и ожидают задачи от координатора.
2PC гарантирует, что одновременно может работать только одна служба, что делает процесс более устойчивым и последовательным, чем CQRS.
Область применения
2PC лучше всего подходит для распределенных систем, имеющих дело с транзакциями, которые отдают предпочтение точности, а не эффективности использования ресурсов. Он устойчив к ошибкам и позволяет легко отследить ошибки даже в больших объёмах информации.
3. Saga
Saga — это асинхронный паттерн не использующий центр управления. Сервисы здесь сами взаимодействуют между собой. Эта особенность позволяет избавиться от недостатков упомянутых выше паттернов.
Для связи между сервисами в Saga используется шина событий. Шина передаёт запросы между службами, и каждая участвующая служба создает локальную транзакцию. Затем участвующие службы выдают событие для получения другими службами. Все другие службы прослушивают события. Первая служба, получившая событие, выполнит необходимое действие. Если этой службе не удается выполнить действие, оно отправляется в другие службы.
Эта структура похожа на 2PC тем, что службы циклически запускаются, если кто-то не может выполнить задачу. Тем не менее, Saga не использует центр управления, чтобы лучше управлять потоком и уменьшить количество требуемой обратной связи.
Область применения
Этот паттерн распределённой системы хорошо подходит для задач, которым требуется масштабируемая беcсерверная архитектура, способная обрабатывать много запросов одновременно. AWS использует подобные решения в AWS Step Functions и AWS Lambda, и других продуктах.
4. Реплицированные сервисы с распределением нагрузки (RLBS)
RLBS — это самый простой и часто используемый шаблон проектирования. На базовом уровне он состоит из нескольких идентичных сервисов, которые общаются с центральным распределителем. Каждый сервис способен выполнять задачи и перезапускать их в случае неудачи. Распределитель получает запросы от конечного пользователя и разделяет их между сервисами, используя round-robin или более сложный алгоритм.
Дублирующие службы обеспечивают высокую доступность приложения для запросов пользователей и могут перераспределять работу в случае сбоя одного экземпляра службы.
RLBS часто используется с Azure Kubernetes, которая представляет собой технологию оркестровки контейнеров с открытым исходным кодом, разработанную Microsoft, которая предлагает автоматическое масштабирование служб в зависимости от воркфлоу.
Область применения
RLBS отлично подходит для систем, с которыми пользователи взаимодействуют напрямую. Нагрузка на эти системы в течение дня изменяется, поэтому требуется низкая задержка, например Netflix или Amazon Prime.
5. Шардинг
Альтернативой репликации является создание отдельных сервисов, каждый из которых выполняет определённый тип запросов. Это называется шардингом, потому что вы разделяете запрос на несколько неодинаковых частей. Например, у вас может быть отдельный сервис, который принимает кэширующиеся запросы, а другой сервис будет отвечать за запросы с высоким приоритетом. Распределитель нагрузки обрабатывает каждый запрос и передаёт его в подходящий сервис.
Шардинг сервисов обычно используется для создания сервисов с поддержкой состояния, потому что объём состояния часто слишком большой для одного stateless контейнера. Шардинг позволяет масштабировать отдельные элементы под размер состояния.
Шардинг также позволяет быстрее обрабатывать высокоприоритетные запросы. Сегменты, предназначенные для запросов с высоким приоритетом, всегда доступны для обработки таких запросов в момент их поступления и не требуют размещения запроса в очереди.
Область применения
Шардинг сервисов хорош в тех случаях, когда ваша система работает с предсказуемой несбалансированной нагрузкой для разных запросов, а некоторые запросы имеют приоритет.
Что дальше?
В статье были рассмотрены лишь несколько паттернов распределённых систем. Вот ещё несколько шаблонов проектирования для изучения: