Как мы боролись за масштабируемость Docsvision (Эпизод 2 — масштабирование BPM)
Если средства масштабирование сервера приложения (описанные в предыдущей статье) мы получили «на сдачу» от использования правильных архитектурных решений, и до сих пор не испытываем особых проблем с вопросами масштабирования этого слоя системы, то вторая задача — масштабирование сервиса управления бизнес процессами далась нам совсем не просто. И я решил посвятить этому отдельную небольшую статью.
Вообще говоря, вопросы производительности и непосредственно связанные с ними задачи масштабирования системы управления процессами являются узким местом при внедрении любой системы Workflow или полноценной BPM-системы. С этим сталкивались все, кто их внедрял. Причина этому в природе данного типа автоматизации.
· Во–первых, создание процессов радикально отличается от обычного программирования — это визуальное программирование — low-code. Пользоваться им несложно, а подходящих для него задач очень много. И если не обеспечить жесткую дисциплину внедрения процессов они могут начать размножаться неконтролируемо.
· Во-вторых, средства Workflow автоматизации очень удобны для разного рода сервисных функций (мониторинга, нотификации и пр.) и разных серверных расширений, что еще умножает число процессов, которые должна обслуживать подсистема управления процессами;
· В-третьих, специфика разработки Workflow решений позволяет «нарисовать» процесс, который будет создавать неоправданно высокую нагрузку на сервер. Low-code разработчики, как правило не обладают высокой квалификацией, а для внедрения таких решений не имеется готовых методик тестирования и переноса решений в промышленную среду, таких как DevOps. Поэтому весьма высок риск, что на Production сервере окажется очень «прожорливое» к ресурсам решение.
· Ну и наконец, в процесс могут быть встроены скрипты, которые могут еще больше увеличить нагрузку на сервер.
Когда мы начинали писать собственную BPM систему, мы не представляли всего объема задач, но масштаб проблем просматривался. А так как высшую математику нам преподавали прилично, а некоторые из нас даже обладали кандидатскими степенями, то и про теорию массового обслуживания мы знали. И надеялись на то, что там найдутся алгоритмы, которые позволят предупредить потенциальные проблемы. Однако, довольно быстро стало понятно, что готовой модели оптимизации загрузки сервиса при таком количестве неизвестных, нам ни найти, ни тем более самостоятельно построить не удастся.
Собственно, все оптимизационные модели теории массового обслуживания базируются на предположении о более или менее равномерных потоках однотипных заданий для системы при известной вероятностной модели потребности в ресурсах (что-то должно быть известно о вероятностях наступления тех или иных типов запросов на обслуживание). Естественно ничего подобного в отношении реальной развивающейся BPM-системы сказать нельзя. Типы загрузки сервиса самые разнообразные от простейших функций ветвления процесса, до сложных вычислительных скриптов и функций интеграции. Предсказать вероятность появления той или иной функции совершенно невозможно, к тому же характер нагрузки постоянно меняется и постепенно увеличивается. В общем на академические методы оптимизации надеяться не приходилось.
Так что пришлось реализовывать механизмы оптимизации серверных мощностей эмпирически, путем проб и ошибок. Итоговый алгоритм работы сервиса управления процессами получился достаточно сложным с большим количеством параметров настройки, здесь я его описывать не буду. Там есть и многопоточная обработка процессов; и управление приоритетами типов процессов; и управление периодом поиска процессов, ожидающих обработки; и возможность подбора оптимального по размеру пула параллельно обрабатываемых процессов; и управление квантом времени на обработку одного процесса; и встроенные механизмы расчета этого кванта исходя из различных критериев; и возможность ограничить время на выполнение одной функции конкретного типа; и учет времени уже выделенного на обработку конкретного экземпляра процесса; и возможность разделение сессий подключения и компонентов шлюза между отдельными экземплярами процесса и т. д.
Отдельной важной вехой (в версии 5.0), радикально повлиявшей на производительность, стала реализация событийной модели в шлюзах. До этого момента все ожидания тех или иных действий пользователя или изменения объектов, обрабатываемых в процессе, реализовались функциями мониторинга по расписанию. А так как 98% времени процессы ждут исполнения тех или иных «ручных операций» то львиная доля всех вычислительных ресурсов уходила на проверку факта их завершения.
Все это, конечно, подробно описано в документации платформы. Скажу только, что для сложившейся структуры процессов и при наличии достаточной компетенции, вы сможете подобрать оптимальное соотношение параметров настройки, чтобы выжать из аппаратных средств максимум и оптимально распределить их между отдельными экземплярами процессов. Но, несмотря на все наши ухищрения, подсистема бизнес-процессов все равно оставалась узким местом в производительности системы и нам пришлось реализовать возможность кластеризации и этого сервиса системы, для того чтобы была возможность постепенно наращивать его мощность, не заменяя дорогостоящее оборудование целиком.
Сейчас в системе может быть установлено неограниченное количество физических или виртуальных серверов, выполняющих функции обработки бизнес процессов. Для каждого сервиса, входящего в кластер, указывается доля обрабатываемых процессов, что позволяет сбалансировать нагрузку в зависимости, к примеру, от характеристик сервера. Например, если для одного сервиса указана доля 3, а второго — 4, то количество обрабатываемых каждым сервисом процессов будет соотноситься как 3:4. В случае если один из сервисов не запущен, обработку «его» доли процессов ведут другие активные сервисы.
Однако, далеко не всякую нагрузку можно эффективно масштабировать средствами кластеризации. На определённых типах нагрузки (неудачно написанных процессах), кластеризация Workflow приносила только повышение нагрузки на сервер приложений и БД, что приводило к общему снижению производительности системы. Например, при массовом использовании сложных поисковых запросов в цикле автоматической потоковой обработки входящего потока документов. Каждый поисковый запрос создает большую нагрузку на сервер, и, если наш кластер распараллеливает выполнение подобных процессов, в итоге это может привести к неработоспособности всей системы. Условно говоря: нет смысла кластеризовать обработку большого количества процессов с бесконечными циклами.
Именно поэтому и появилась такое большое количество вариантов настройки, позволяющих сбалансировать обработку логики процессов, ограничивая их возможность по монопольному захвату вычислительных ресурсов.
Но это всего только второй эпизод нашей саги… ждите следующих выпусков.