предисловие
В конце года это было действительно неравномерно, и недавно я получил предупреждение о работе и техническом обслуживании: это означает, что некоторые серверы находятся под очень высокой нагрузкой, давайте локализовать проблему.
Сильно думаю, что делать, и несколько дней назад намеренно увеличил нагрузку на некоторые сервера(Да, начальник попросил меня написать БАГ!), но, к счастью, разные среды не влияют друг на друга.
проблема позиционирования
Узнав о проблеме, я сначала пошел на сервер, чтобы посмотреть, и обнаружил, что работает только наше Java-приложение. Так что используйте сначалаps
Команда получила заявкуPID
.
затем используйтеtop -Hp pid
Отобразите потоки этого процесса. Введите заглавную букву P, чтобы отсортировать потоки пропорционально их использованию ЦП, что приведет к следующим результатам.
Конечно, у некоторых потоков была очень высокая загрузка ЦП.
Для того, чтобы облегчить позиционирование проблемы, я сразу воспользовалсяjstack pid > pid.log
стек потоковdump
в файл журнала.
Я выбрал случайный из 100% тем вышеpid=194283
Запрос в снимке потока после преобразования в шестнадцатеричный формат (2f6eb):
Поскольку идентификаторы потоков в моментальных снимках потоков хранятся в шестнадцатеричном формате.
нашел этоDisruptor
СтекOOM:Сильнее чем у Disruptor тоже есть переполнение памяти?
Не ожидал, что вылезу снова.
Чтобы более интуитивно просматривать информацию о состоянии потока, я загружаю информацию о снимке на платформу для специального анализа.
В одном из меню показаны все потоки, которые потребляют процессор, я присмотрелся и обнаружил, что они почти такие же, как стек выше.
то естьDisruptor
Стек очередей, все выполняются одновременноjava.lang.Thread.yield
функция.
хорошо известныйyield
Функция позволит текущему потоку уступитьCPU
ресурсов, а затем позволить другим потокам конкурировать.
Судя по снимку треда только что, установлено, чтоRUNNABLE
статус и выполняютсяyield
Существует около 30 потоков функции.
Поэтому изначально оценивается, что выполняется большое количество потоков.yield
После того, как функции конкурируют друг с другом, увеличивается загрузка ЦП, а за счет обнаружения и использования стекаDisruptor
Связанный.
Решать проблему
Затем я проверил код и обнаружил, что 2 используются внутри в соответствии с каждым бизнес-сценарием.Disruptor
Очередь на развязку.
Предполагая, что теперь существует 7 типов бизнеса, это эквивалентно созданию2*7=14
КусокDisruptor
Очереди, и каждая очередь имеет одного потребителя, то есть всего 14 потребителей (больше в производстве).
В то же время обнаружено, что настроенная политика ожидания потребленияYieldingWaitStrategy
Эта стратегия ожидания уступает ЦП.
код показывает, как показано ниже:
На первый взгляд, это во многом связано со стратегией ожидания.
локальное моделирование
Для проверки я создал 15 локальноDisruptor
Очередь также отслеживает использование ЦП в сочетании с мониторингом.
15 созданоDisruptor
Очереди, и каждая очередь использует пул потоков для связиDisruptor队列
Внутри отправляются фрагменты данных мощностью 100 Вт.
Программа-потребитель просто печатает его.
Поработав некоторое время, я обнаружил, что загрузка ЦП действительно высока.
в то же времяdump
Феномен обнаружения и производства потоков также логичен: все потребляющие потоки находятся в работе.RUNNABLE
статус, оба выполняются одновременноyield
.
по запросуDisruptor
В официальной документации найдено:
YieldingWaitStrategy — это стратегия, которая полностью выжимает процессор, используя
自旋 + yield
способ повысить производительность. Эта стратегия рекомендуется, когда количество потоков-потребителей (потоков обработчика событий) меньше, чем количество ядер ЦП.
Также ознакомьтесь с другими стратегиями ожиданияBlockingWaitStrategy
(Это также политика по умолчанию), в ней используется механизм блокировки, а коэффициент использования ЦП невелик.
Итак, при тех же условиях, что и раньше, измените стратегию ожидания наBlockingWaitStrategy
.
По сравнению с ЦП только сейчас, будет обнаружено, что скорость использования будет значительно снижена позже; в то же время, после дампа потоков, будет обнаружено, что большинство потоков находятся в состоянии ожидания.
оптимизированное решение
Кажется, что стратегия ожидания заменяетсяBlockingWaitStrategy
может замедлить использование процессора,
Но учтите, что официальныйYieldingWaitStrategy
В описании сказано:
Эта стратегия рекомендуется, когда количество потоков-потребителей (потоков обработчика событий) меньше, чем количество ядер ЦП.
В существующих сценариях использования очевидно, что количество потребляющих потоков значительно превышает количество основных ЦП, потому что мое использование — этоDisruptor
Очередь — это один потребитель, поэтому я настраиваю очередь только на 1 и повторяю попытку (стратегия по-прежнемуYieldingWaitStrategy
).
Поработав минуту, я обнаружил, что загрузка ЦП была относительно стабильной и невысокой.
Суммировать
Таким образом, после расследования мы можем прийти к выводу, что для кардинального решения этой проблемы нам необходимо разделить наш существующий бизнес, теперь N бизнесов обрабатываются в одном приложении одновременно, и каждый бизнес будет использовать несколькоDisruptor
очередь.
Поскольку он работает на сервере, ресурсы ЦП являются общими, что приведет к высокой загрузке ЦП.
Итак, наша корректировка выглядит следующим образом:
- Чтобы быстро решить эту проблему, сначала замените стратегию ожидания на
BlockingWaitStrategy
, что может эффективно снизить загрузку ЦП (также приемлемо для бизнеса). - Второй шаг — разделить приложение (одно из приведенных выше симуляций).
Disruptor
Queue), одно приложение обрабатывает один тип бизнеса, а затем развертывается отдельно, чтобы их можно было изолировать друг от друга, не влияя друг на друга.
Конечно, есть и другие оптимизации, потому что это тоже старая система, на этот раз поток дампа фактически обнаружил, что было создано 800+ потоков.
Способ создания пула потоков заключается в том, что количество основных потоков и максимальное количество потоков совпадают, что приводит к тому, что некоторые простаивающие потоки не перерабатываются, что приводит к большому бессмысленному потреблению ресурсов.
Поэтому мы также будем корректировать способ создания пулов потоков в соответствии с бизнесом, уменьшать количество потоков и максимально эффективно использовать все.
Демонстрационный код для этой статьи загружен на GitHub:
Ваши лайки и репост - лучшая поддержка для меня