Наблюдая за развитием линеек современных процессоров, серверных мощностей, только невнимательный читатель не может отметить существенное замедление, если не сказать приостановку роста «количества гигагерц». Также существенно замедлился рост производительности каждого из ядер процессора. Однако, количество этих ядер, а также степень параллельности их использования все возрастает. Не вдаваясь в технические подробности, можно прямо говорить о том, что для того, чтобы использовать современные серверные мощности, сочетающие в себе ферму из нескольких многопроцессорных юнитов, нужно научиться распараллеливать свои задачи. Нужно учиться выполнять их в несколько потоков.
С другой стороны, задачи автоматизации, особенно на платформе «1С», в последние годы ровно этого и требуют: растет количество пользователей в системах (в современных проектах их количество измеряется тысячами), все больше компаний уделяет внимание созданию собственных частных облачных инфраструктур или переходу в публичные облака. Так, наша компания уже сейчас поддерживает системы, с количеством одновременно работающих пользователей более 1 000.
Нам очень часто клиенты задают вопросы, ориентированные на пиковую производительность того или иного компонента системы, например: «Почему у меня при расчете себестоимости загружено только одно ядро у сервера приложений, а загрузка SQL сервера совсем невысока?». Ответ на этот вопрос прост — система выполняет однопоточный алгоритм, который не может выполняться на нескольких процессорах одновременно. Какой выход из этой ситуации — ручное распараллеливание процесса, использование фоновых заданий, как отдельных соединений с системой, разбиение длинных процессов на стадии и применение конвеерного способа обработки данных.
В данной статье, мы бы хотели рассмотреть пример повышения масштабируемости и эффективной загрузки оборудования с помощью распараллеливания и построения конвеерной схемы обработки данных.
Итак, дано: внешняя система, построенная на стандартной СУБД (не принципиально какой) выдает данные через хранимую процедуру, содержащие информацию о документах, которые нам нужно загрузить в «1С:УПП» и провести. Документы преимущественно касаются торговых операций: «Поступление товаров и услуг», «Реализация товаров и услуг», «Отчет о розничных продажах». Объем документов большой и требуется обеспечить пропускную способность системы не менее 100 000 документов в сутки с регулируемой мощностью загрузки.
Схематично, последовательность шагов подобной схемы можно изобразить следующим образом:
Однако, реализация однопоточного алгоритма, работающего по данной схеме привела к неудовлетворительной производительности. Скорость загрузки не превышала 20 000 документов в сутки и при этом загрузка оборудования не превышала 10 %.
Давайте попробуем распараллелить этот механизм.
Выделим несколько потоков, которые могут выполнятся изолированно друг от друга и немного детализируем каждый из блоков.
На первый взгляд, такое разделение может помочь, однако стоит оценить длительность каждого из этапов, для того, чтобы определять стоит ли заниматься их паралеллизацией. Итак, по нашим оценкам получилось следующее:
- Этап загрузки из СУБД и сохранения данных в промежуточные регистры (без формирования документов) ~ 7 % времени.
- Этап формирования документов и проведения по стандартным регистрам ~ 85 % времени.
- Этап проведения по доп. Регистрам — 8 % времени.
Напрашивается, очевидный вывод. Имеет смысл выполнять все эти состояния конвеерным способом и не распараллеливать первый и последний этапы загрузки. Тогда схема загрузки будет выглядеть следующим образом:
Остается самое интересное: как сделать так, чтобы параллельно работающие потоки не блокировали друг друга. А то и того хуже, не провоцировали deadlock'ов. Дальнейшие рассуждения будем проводить исходя из предположения, что система у нас работает в режиме «Управляемых блокировок» и документы не вызывают взаимоблокировок при проведении одинаковых документов.
Каждый отдельный поток проведения будет иметь следующие параметры:
- организация,
- тип документа,
- подразделение,
- склад,
- день.
В рамках подобного набора измерений все движения по регистрам будут выполняться последовательно, не накладывая пересекающихся блокировок.
Для того, чтобы вся наша система заработала, нам нужно управляющее фоновое задание, которое будет анализировать состояние промежуточного регистра, выбирать из него пакеты документов к созданию и загрузке и стартовать новое количество фоновых заданий согласно текущим настройкам системы.
Применение подобного подхода позволило повысить на практическом предприятии скорость загрузки товарных документов до 100 000 документов в сутки при параллельной работе порядка 300 пользователей в УПП на 30 одновременно работающих фоновых заданиях.
Подводя итоги вышесказанному, можно сделать прямой вывод — параллелизация высоконагруженных участков работы системы, разумный подход при подборе накладываемых блокировок — вот основные ключи к повышению производительности системы.