Зачем шине 1С нужна отказоустойчивость
Эта статья посвящена шине 1С и тому, как обеспечить ее отказоустойчивость.
Мы давным-давно, в самом начале, были бета-тестерами шины. Запустили ее и смотрели в первую очередь на то, что она может и с какой скоростью способна это делать. Результат нас устроил, и мы начали готовиться к внедрению в продакшен.
Компания у нас достаточно большая, поэтому существуют требования к отказоустойчивости и непрерывности работы. На архитектурных комитетах возник вопрос о том, что шина неотказоустойчива. Если с ней что-то происходит, все останавливается.
Нам нужно было решить, как сделать так, чтобы шина, а точнее процесс, который ее использует, не останавливался.
Причины остановки интеграционных процессов
Сначала разберем, по каким причинам могут происходить остановки и сбои.

Первый и самый простой случай: мы отправляем сообщение, которое по какой-то причине не может быть обработано принимающей стороной.
Второй и третий случаи, по сути, связаны между собой. Нам может потребоваться обновить шину: остановить ее, а затем запустить заново, что занимает какое-то время. Либо нужно провести определенные манипуляции с хостом, на котором развернута шина.
Последний случай – так называемый «эффект экскаватора», когда в какой-то момент просто теряется сеть.
Чтобы понять, как решать эти проблемы, нужно учитывать специфику работы шины.
Delivery Acknowledgement (ACK)

На изображении представлена классическая схема: база 1С, шина, база 1С. Одна база отправляет сообщение, другая его принимает. Все было бы хорошо, но шина работает асинхронно.
Если шина становится недоступна, первая база продолжает отправлять сообщения. Принцип асинхронности заключается в том, что мы не ждем ответа об успешной обработке сообщения. Мы ждем только подтверждения его успешной отправки в шину. В результате первая база не знает, что в итоге происходит на стороне получателя.
Одно из решений – подтверждать доставку и обработку сообщения с помощью отдельного тикета. Получив и успешно обработав сообщение, принимающая сторона отправляет ответ. Этот ответ может прийти через 20 или 30 минут.
Если шина сломалась, мы не получаем тикет и можем переотправить сообщение после того, как шина заработает.
У этого способа есть и преимущества, и недостатки.
Первый недостаток – дополнительные транзакции. Тикет все равно является отдельной транзакцией. Программисту нужно провести определенную работу, а в системе появляется небольшая дополнительная нагрузка.
Второй недостаток – простой во время недоступности шины. Мы сможем переотправить сообщение, но, если шина недоступна, например, 30 минут, все это время бизнес-процесс не работает.
При этом тикет-система все равно необходима. Без нее невозможно гарантировать, что потерянное во время сбоя сообщение позднее будет переотправлено.
Active–Passive High Availability
Следующий этап – развертывание второго экземпляра шины.

Процесс интеграции – это объект метаданных в 1С, который активно взаимодействует с шиной. Кредами этого процесса можно управлять не только интерактивно. Программно можно указывать адрес шины и секрет.
Предположим, первая шина работает. Каким-то образом – о способах определения доступности поговорим позднее – мы узнаем, что она стала недоступна. При этом нам известен адрес второй шины, которая уже развернута и просто ждет. Она является копией первой шины.
После обнаружения сбоя все сообщения начинают идти через второй экземпляр. Такая схема позволяет избежать простоя: первую шину можно остановить для обновления, пока вторая продолжает работать.
Но здесь есть один нюанс. В первой шине, которая остановилась из-за сбоя или была отключена нами, могло остаться сообщение. Оно не дойдет до получателя.
Именно поэтому нужна тикет-система. Если подтверждение обработки не пришло, сообщение впоследствии будет переотправлено.
Однако активно-пассивная схема тоже не является панацеей.

Например, мы используем RabbitMQ, интегрируемся с другими системами, поднимаем две шины и настраиваем их так, чтобы обе слушали одну очередь. Когда в очередь RabbitMQ попадает сообщение, его читают две шины с одинаковыми кредами. Какая шина первой заберет сообщение, та и пропустит его через себя.
При этом первая шина подключена к 1С, а вторая не подключена и ждет, когда первая сломается. В результате во второй шине начинают копиться недоставленные сообщения.
Активно-пассивная схема защищает от падения хоста: второй экземпляр шины уже существует и готов к работе. Она также позволяет проводить обслуживание и обновление – первая шина отключается, а вторая продолжает работать.
Но остаются задержка при переключении и риск потерянных сообщений, как в примере с RabbitMQ. Кроме того, приходится держать запущенными два экземпляра. Первый работает, а второй простаивает, хотя ему все равно нужны вычислительные ресурсы.
Active–Active High Availability
Эту проблему можно решить с помощью активной отказоустойчивой системы.

В самой конфигурации 1С можно создать дубль процесса интеграции. Если процессов несколько, дублируются все.
Первый процесс интеграции настраивается на первую шину, а второй – на вторую. В этом случае неважно, из какой шины придет сообщение: база 1С сможет его обработать.
Если один из экземпляров шины ломается, процесс интеграции, который был с ним связан, программно переопределяется и подключается ко второй, работающей шине.
В результате два процесса интеграции начинают слушать одну и ту же шину. Это технически возможно и реализуемо, никаких особых сложностей здесь не возникает.
Нагрузка на оставшуюся шину увеличивается. При этом в обычном рабочем режиме мы, по сути, получаем пропускную способность x2, потому что одновременно работают оба экземпляра.
Но нужно помнить, что одно или два сообщения, которые передавались непосредственно в момент падения шины, все равно могут потеряться. Поэтому подтверждение обработки сообщений остается обязательным.

В случае с RabbitMQ обе шины читают одну и ту же очередь, и все сообщения поступают в одну базу через оба экземпляра шины. Здесь никаких проблем не возникает: схема нормально работает.
Availability Control
Следующий вопрос – как определить, доступна ли шина.

Классический вариант – проверить специальный адрес: hostname и используемый по умолчанию порт. Через heartbeat можно получить ответ «ОК» либо увидеть, что шина запускается или недоступна.
Таким образом можно определять состояние экземпляра, но это не панацея. Лучше использовать немного другой механизм.
В саму шину можно отправлять небольшой тикет. Для этого создается служебный процесс интеграции, который отправляет тикет в отдельный сервис. Если шина отвечает, значит, все хорошо. Если ответа нет, что-то сломалось.
Дело в том, что сам экземпляр шины может быть доступен, а конкретный процесс при этом выключен. Heartbeat отвечает, что все в порядке, но реальные сообщения не ходят.
Служебный тикет позволяет проверить, что доступен весь экземпляр, запущен сервис и работают регламентные задания.
Возможна и другая ситуация: шина работает, процесс запущен, но установлена блокировка регламентных заданий. В результате сообщения перестают доходить. С помощью служебного тикета это тоже можно обнаружить.
Если блокировка не связана с запланированным техническим обслуживанием, такое состояние является сбоем, на который система может отреагировать автоматически.
Служебные тикеты обязательно нужно отправлять с Lifetime, то есть со временем жизни.
Предположим, один из экземпляров недоступен в течение суток. Все это время 1С отправляет сообщения: «Ты доступна? Ты доступна? Ты доступна?» В результате накапливаются тысячи сообщений. Когда шина оживает, она начинает тысячу раз отвечать: «Да, теперь я доступна».
Это изменяет профиль нагрузки и создает совершенно ненужную работу. Поэтому достаточно задать Lifetime в 20–30 секунд.
Итоговая схема
В итоге первоначальная проблема решается следующим образом.
Первое – наличие тикет-системы. Ее можно реализовать без развертывания дополнительных хостов: немного программирования и архитектурной работы уже дают возможность определять, все ли нормально работает и были ли сообщения действительно обработаны.
Второе – развертывание двух экземпляров шины и двух процессов интеграции.
В штатном режиме каждый процесс интеграции работает со своей шиной. Если одна из шин ломается или останавливается, система программно определяет, какой экземпляр недоступен, и направляет оба процесса интеграции на работающую шину.

Шина 1С поддерживает не только асинхронные запросы и работу через MQ, Kafka, RabbitMQ и другие подобные инструменты. Она также может принимать HTTP-запросы.
Если развернуто два экземпляра, HTTP-запросы масштабируются достаточно просто. Перед шинами ставится балансировщик – например, HAProxy, Nginx или другое решение. Он также определяет доступность экземпляров и распределяет между ними сообщения.
Мониторинг шины 1С
Отказоустойчивую систему необходимо постоянно контролировать.
Нужно следить за самой инфраструктурой, то есть за хостом, а также за встроенным функционалом шины. Однако штатного мониторинга, который предоставляет шина, нам для запуска в продакшене оказалось недостаточно.

На моей практике используются три основных варианта мониторинга. Кто-то использует все три, кто-то только один – возможны разные комбинации.
Uptime Kuma – достаточно легковесная, неплохая и мощная система мониторинга. Взаимодействовать с ней через API немного сложно, но для небольшой инфраструктуры ее вполне можно эксплуатировать.
Zabbix – старый добрый инструмент, который знают практически все. О нем подробно говорить не нужно.
Более современный стек – системы для работы с временными рядами: VictoriaMetrics, Prometheus и другие решения. Как правило, их данные визуализируются в Grafana.
С помощью этих инструментов в первую очередь можно мониторить доступность хоста. Это может быть обычный ping, если он не закрыт.
Также проверяется доступность порта. Если экземпляр запущен, порт занят и прослушивается.
Отдельно контролируется статус службы – службы Windows или Linux. Например, VictoriaMetrics может по умолчанию передавать в метриках статусы запущенных служб.
Также настраивается и контролируется health check.
Штатный мониторинг
Разработчики шины реализовали современный формат OpenMetrics.

Получить штатные метрики можно по адресу, в котором указываются имя сервера, порт, applications, имя созданного приложения, затем service runtime и metrics.
После обращения к этому адресу возвращается полный список предопределенных метрик, которые шина 1С предоставляет из коробки. В него входят счетчики сообщений, ошибок и недоставленных сообщений.
Разработчики также предусмотрели возможность создания пользовательских метрик. Например, можно отслеживать участников, размер передаваемых сообщений – не только их количество, но и объем.
Можно анализировать заголовки. Если через один процесс интеграции передается несколько типов сообщений, например заказы, реализации и другие объекты, их можно разделять и считать отдельно.
Свой мониторинг
Штатных возможностей нам оказалось недостаточно, поэтому мы сделали собственный мониторинг.

На изображении представлены скриншоты из веб-интерфейса шины, а не из платформы 1С.
В шине можно реализовать классический регистр сведений и записывать в него необходимые данные. Также можно создать собственный HTTP-сервис – поднять endpoint, доступный по адресу, в котором указываются hostname, используемый порт, application, имя базы и имя приложения. Дальнейшая часть API определяется разработчиком.
Мы создали сервис InfoMetrics, через который передаются дополнительные метрики в формате OpenMetrics.
Причину разработки такого сервиса хорошо видно при сравнении штатного и пользовательского мониторинга.

В штатном мониторинге отображаются имя сервиса интеграции, например ПроАпдекс:: MultyESB::Основной::monitoring, имя канала – ch_mon_1c_to_esb – и общее количество сообщений: 3 238.
Мы видим, что через канал прошло 3 238 сообщений. Но в канале участвуют две стороны, а штатная метрика не показывает распределение между ними.
Есть вероятность, что один участник отправил все 3 238 сообщений, а получатель не получил ни одного. Возможен и другой вариант: отправитель и получатель отработали нормально. По одному общему счетчику этого определить нельзя.

В собственном мониторинге мы добавили измерение по участнику и видим разделение. Например, 1 619 сообщений отправлено и 1 619 получено. В сумме получается то же значение – 3 238, но теперь можно проверить, действительно ли количество отправленных сообщений равно количеству полученных.
Так мы получаем дополнительные разрезы аналитики. Можно создавать практически любые бизнес-метрики, отправлять их из 1С в шину, передавать в Prometheus и визуализировать в Grafana.
Подводный камень №4
Отдельно нужно остановиться на очень серьезном подводном камне, который лично у меня выпил много крови.

Если взять две базы 1С и указать в них одинаковые креды для подключения к одной и той же шине, сообщения начнут случайным образом уходить то в одну, то в другую базу.
Расследовать, куда делось сообщение, очень сложно. В логах 1С видно, что сообщение было передано определенному секрету и идентификатору, а получатель якобы его получил. При этом в самой базе-получателе обнаруживается, что не хватает примерно половины сообщений.
Найти, кто еще подключился под этими кредами, практически нереально. Приходится изучать логи, смотреть iptables и использовать другие инфраструктурные инструменты.
Мы реализовали мониторинг непосредственно в каждой базе 1С. База передает информацию о том, под какими кредами она работает и какой Connection String слушает.
Благодаря этому видно, кто является отправителем, а кто получателем.
Например, тестовая ESB может дважды подключаться под разными кредами. Это нормальное поведение, связанное с отказоустойчивостью.
Но если под одними и теми же кредами подключены разные базы, необходимо немедленно предпринимать действия.
Причины и решения

Одна из возможных причин – на Dev-контуре развернули копию продакшен-базы. Копия содержит все креды, поэтому Dev-контур начинает читать сообщения из продовой шины. В результате сообщения теряются.
Такие ситуации возникали и при переезде или смене платформы: базу перенесли, а старый экземпляр забыли выключить.
Еще один распространенный сценарий – копию базы разворачивают прямо на продакшене. Продакшен большой, Dev-контур маленький, а бухгалтеру, например, нужно развернуть отчетную базу по состоянию на предыдущий день. На Dev-контуре не хватает места, поэтому копию размещают рядом с основной базой, и она тоже начинает подключаться к шине.
Если в компании контуры разделены на сетевом уровне – например, существуют Production, Dev и другие среды, – стоит попросить специалистов по информационной безопасности ограничить доступ между ними.
Из Dev-контура не должно быть возможности подключаться к продовой шине. Необходимый порт должен быть полностью закрыт. Это значительно повышает безопасность системы.
Второй момент – уведомления. Система должна мониторить дублирующие подключения. Если такая ситуация возникла, необходимо срочно отправить сообщение на электронную почту, в Telegram, корпоративный мессенджер, через webhook или другим способом.
Через три-четыре часа, а тем более через три-четыре дня, последствия могут стать критичными для всей компании. Особенно это важно, например, для финтеха.
Существуют и более проактивные подходы. Шина может самостоятельно обнаружить, что к ней подключились два сервиса с одинаковыми кредами, сформировать сообщение и отправить одному из экземпляров команду: «Отключись и не слушай меня». База получает это сообщение, отключается от шины и одновременно отправляет уведомление.
В этом случае время реакции сокращается до одной-двух минут. Иначе сначала нужно получить уведомление, прочитать его, понять, что произошло, открыть консоль и только после этого начинать что-то делать.
Наиболее серьезная защита – проверка строки подключения. Когда разворачивается копия базы, ее строка подключения не соответствует эталонной. Это означает, что база была перемещена или является копией. В такой ситуации она не должна отправлять и получать сообщения. Главное – не позволить ей подключиться к шине.
Но здесь есть важный нюанс. К одной и той же базе можно подключаться разными способами: по IP-адресу, hostname или полному FQDN с доменом.
Если кластер имеет больше одного центрального сервера, количество возможных вариантов становится еще больше. Поэтому желательно определить и разрешить все допустимые варианты подключения.
Иначе может произойти следующая ситуация. Шина подключается с первого сервера, и все работает. Но затем фоновое задание, запускающее прослушивание шины, выполняется на втором сервере, который не внесен в список разрешенных.
Система определяет, что этот сервер не может работать с шиной, и перестает получать сообщения. В результате возникает непонятное поведение: в один момент сообщения приходят, а в другой – нет.
Механизм проверки строки подключения желательно реализовать, но при этом нужно помнить, что к одной и той же системе подключения могут выполняться разными способами.
*************
Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TEAM EVENT.
Вступайте в нашу телеграмм-группу Инфостарт

