Одноразовая производственная практика оптимизации ЦП 100% устранения неполадок

Java JVM
Одноразовая производственная практика оптимизации ЦП 100% устранения неполадок

предисловие

В конце года это было действительно неравномерно, и недавно я получил предупреждение о работе и техническом обслуживании: это означает, что некоторые серверы находятся под очень высокой нагрузкой, давайте локализовать проблему.

Сильно думаю, что делать, и несколько дней назад намеренно увеличил нагрузку на некоторые сервера(Да, начальник попросил меня написать БАГ!), но, к счастью, разные среды не влияют друг на друга.

проблема позиционирования

Узнав о проблеме, я сначала пошел на сервер, чтобы посмотреть, и обнаружил, что работает только наше Java-приложение. Так что используйте сначалаpsКоманда получила заявкуPID.

затем используйтеtop -Hp pidОтобразите потоки этого процесса. Введите заглавную букву P, чтобы отсортировать потоки пропорционально их использованию ЦП, что приведет к следующим результатам.

Конечно, у некоторых потоков была очень высокая загрузка ЦП.

Для того, чтобы облегчить позиционирование проблемы, я сразу воспользовалсяjstack pid > pid.logстек потоковdumpв файл журнала.

Я выбрал случайный из 100% тем вышеpid=194283Запрос в снимке потока после преобразования в шестнадцатеричный формат (2f6eb):

Поскольку идентификаторы потоков в моментальных снимках потоков хранятся в шестнадцатеричном формате.

нашел этоDisruptorСтекOOM:Сильнее чем у Disruptor тоже есть переполнение памяти?

Не ожидал, что вылезу снова.

Чтобы более интуитивно просматривать информацию о состоянии потока, я загружаю информацию о снимке на платформу для специального анализа.

fastthread.io/

В одном из меню показаны все потоки, которые потребляют процессор, я присмотрелся и обнаружил, что они почти такие же, как стек выше.

то есть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, что может эффективно снизить загрузку ЦП (также приемлемо для бизнеса).
  • Второй шаг — разделить приложение (одно из приведенных выше симуляций).DisruptorQueue), одно приложение обрабатывает один тип бизнеса, а затем развертывается отдельно, чтобы их можно было изолировать друг от друга, не влияя друг на друга.

Конечно, есть и другие оптимизации, потому что это тоже старая система, на этот раз поток дампа фактически обнаружил, что было создано 800+ потоков.

Способ создания пула потоков заключается в том, что количество основных потоков и максимальное количество потоков совпадают, что приводит к тому, что некоторые простаивающие потоки не перерабатываются, что приводит к большому бессмысленному потреблению ресурсов.

Поэтому мы также будем корректировать способ создания пулов потоков в соответствии с бизнесом, уменьшать количество потоков и максимально эффективно использовать все.

Демонстрационный код для этой статьи загружен на GitHub:

GitHub.com/crossover J я…

Ваши лайки и репост - лучшая поддержка для меня