Каждый вечер, в час закрытия смен, кассы розничной сети начинали «залипать». Не падать — именно залипать: операции, которые днём летали, вечером шли рывками, кассиры нервничали, закрытие растягивалось. Сеть немаленькая — около 200 касс в трёх странах, — и у всех участников было готовое объяснение: «вечером все закрываются одновременно — это блокировки».
Объяснение красивое, логичное и подтверждаемое жизненным опытом каждого, кто работал с 1С под нагрузкой. У него был только один недостаток: оно оказалось неверным. Это статья-детектив о том, как мы искали вечернего душителя касс, почему главный подозреваемый оказался невиновен и при чём здесь настройки сервера СУБД, оставшиеся заводскими с эпохи четырёхъядерных процессоров.
Почему все всегда думают на блокировки
«Вечером тормозит — значит, блокировки» — это рефлекс, и рефлекс не беспочвенный. Закрытие смены — действительно конкурентная операция: одновременные записи в одни регистры, длинные транзакции, пересечения по товарам. Каждый администратор 1С видел в своей жизни настоящие вечерние блокировки, и опыт подсказывает: ищи, кто кого ждёт.
Опасность рефлекса в том, что он подменяет диагностику. Команда начинает «бороться с блокировками»: переписывать проведение, дробить транзакции, крутить управляемые блокировки — а вечер за вечером ничего не меняется, потому что лечат не ту болезнь.
Аудит: главный подозреваемый невиновен
Мы начали с того, с чего надо начинать любую охоту на вечерний пик: не с гипотез, а с замеров. Сняли картину ожиданий на сервере СУБД именно в часы пика — кто чего ждёт, сколько и почему.
Результат обескуражил заказчика: блокировок в пик — ноль. Не «мало», не «в пределах нормы» — ноль значимых ожиданий на блокировках. Сессии не ждали друг друга. Они ждали кое-чего другого: свободных потоков процессора.
Картина ожиданий показывала классические признаки перегретого параллелизма: доминирующие ожидания обмена между потоками параллельных планов и — главное — очередь запросов, которым не хватило рабочих потоков. Две трети запросов в пик просто стояли в очереди за ресурсом, которого формально было в избытке: на сервере 48 ядер.
Механика удушения: как 48 ядер становятся узким местом
Чтобы понять, как сервер с 48 ядрами может задыхаться от нехватки потоков, нужно посмотреть на две настройки, которые в этой системе никто никогда не менял:
cost threshold for parallelism = 5— порог «стоимости» запроса, после которого оптимизатор строит параллельный план. Значение 5 — заводское, и оно откалибровано под железо конца девяностых. По современным меркам «стоимость 5» — это лёгкий запрос: типичный отчётик, средней руки выборка. С таким порогом параллельным становится почти всё.MAXDOP = 0— максимальная степень параллелизма «без ограничений»: каждый параллельный запрос вправе разбежаться по всем ядрам сервера. Все 48.
Теперь сложим. Вечером сотни касс одновременно порождают поток запросов. Почти каждый из них (порог-то — 5) получает параллельный план. Почти каждый параллельный план (MAXDOP = 0) претендует на десятки потоков. Пул рабочих потоков сервера — конечный. Итог: лёгкие запросы, которым хватило бы одного ядра на долю секунды, выстраиваются в очередь за десятками потоков, которые им не нужны.
Это и есть вечерний душитель: не конкуренция за данные, а конкуренция за потоки, устроенная самим сервером из лучших побуждений. Днём, при меньшей плотности запросов, система прощала эти настройки. Вечером — переставала.
Отдельная серия: сосед по инстансу
У детектива был и второй сезон. SQL-сервер в этой инфраструктуре — общий: на одном инстансе живут десятки баз разных систем. В разгар работ весь сервер начал задыхаться уже не по вечерам, а среди дня. Виновник нашёлся быстро: отчёт из соседней базы — 24 параллельных потока, 4 часа 18 минут исполнения. Один запрос удерживал половину процессорных ресурсов сервера четыре часа подряд — при заводских настройках параллелизма он имел на это полное право.
Мораль для всех, кто живёт на общем инстансе: настройки параллелизма — общесерверные. Их выбирают не под одну базу, а под общежитие целиком, и «сосед с тяжёлым отчётом» — это ваш сосед, даже если база не ваша.
Лечение: две настройки, ноль перезапусков
Терапия заняла меньше времени, чем диагностика:
cost threshold for parallelism: 5 → 50. Лёгкие и средние запросы перестали получать параллельные планы — им и не нужно: одно ядро справляется быстрее, чем церемония раздачи работы десяткам потоков. Параллелизм остался тяжёлым отчётам и регламентным операциям — тем, кому он действительно помогает.MAXDOP: 0 → 8. Даже тяжёлый запрос теперь ограничен восемью потоками — достаточно для ускорения, безопасно для соседей.
Обе настройки применяются динамически, без перезапуска сервера и без остановки работы — с заранее согласованным планом отката (вернуть старые значения — те же секунды). Конкретные числа не догма: 50 и 8 — разумная отправная точка для нагруженной 1С на многоядерном сервере, но правильные значения подбираются по картине ожиданий вашей системы, а не копируются из статей. Включая эту.
Результат
Вечерние «залипания» касс прекратились в тот же вечер. Очередь за потоками рассосалась: лёгкие запросы исполняются на одном ядре и не толкаются, тяжёлые получают свои восемь потоков и не захватывают сервер. Жалобы кассиров — привычный вечерний фон проекта — закончились.
Отдельное удовольствие — реакция команды заказчика, которая готовилась к долгой войне с блокировками: перепроектированию проведения, переговорам о технологических окнах, месяцам работ. Вместо этого — две настройки и вечер наблюдений.
Чек-лист: блокировки или параллелизм?
Если у вас «вечером всё тормозит», прежде чем объявлять войну блокировкам:
- Начните с картины ожиданий в час пика — стандартными средствами мониторинга СУБД. Диагноз до лечения: смотрите, чего именно ждут сессии.
- Ждут блокировок? Тогда классика: искать долгие транзакции и горячие объекты. Это отдельная дисциплина — и отдельная статья.
- Ждут потоков и обмена между потоками? Проверьте
cost threshold for parallelismиMAXDOP. Заводские 5 и 0 на многоядерном сервере — мина, которая маскируется под «вечерние блокировки» десятилетиями. - Общий инстанс? Помните: параллелизм настраивается на весь сервер, и самый тяжёлый запрос соседа — тоже ваша проблема.
- Меняете настройки — фиксируйте базовую линию до и картину после. Изменения динамические и обратимые, но «стало лучше» должно быть измерением, а не ощущением.
- Не копируйте чужие значения вслепую — подбирайте по своей картине ожиданий. Отправная точка и метод важнее конкретных чисел.
Вместо эпилога
Эта история — про цену готовых объяснений. «Вечером тормозит — значит, блокировки» звучало настолько убедительно, что система годами жила с диагнозом, который никто не проверял. А проверка стоила один час снятия ожиданий в пик.
Формальные признаки врут, готовые объяснения врут ещё увереннее. Измеряйте — особенно тогда, когда все вокруг уже «знают», в чём дело. Именно в этот момент проверка дешевле всего и нужнее всего.
Если у вас похожая картина — вечерние деградации, «блокировки», которые никто не видел живьём, общий инстанс с соседями — начните с пункта 1 чек-листа. А своими историями про заводские настройки, дожившие до продакшена, делитесь в комментариях: подозреваю, наша — далеко не рекордная.
Вступайте в нашу телеграмм-группу Инфостарт