1. Предпосылки
По историческим причинам в настоящее время существует служба, предназначенная для обработки сообщений mq.У облачного сервиса Alibaba robotmq, используемого mq, есть SDK версии 1.2.6 (2016 г.). С развитием бизнеса потребителей на приложение становится все больше, приближается к 200+, из-за чего экз, где находится приложение, имеет высокую нагрузку в течение длительного времени и частые срабатывания сигнализации.
2. Анализ явлений
Нагрузка на сервер ecs, на котором расположено приложение, долгое время была высокой (на ecs есть только один сервис), но использование ресурсов, таких как процессор, ввод-вывод и память, низкое. следующий рисунок:
ECS配置:4核8G
物理cpu个数=4
单个物理CPU中核(core)的个数=1
单核多处理器
С точки зрения загрузки системы эффект многоядерного процессора аналогичен эффекту многопроцессорного.При рассмотрении нагрузки системы разделите загрузку системы на общее количество ядер.При условии, что нагрузка каждого ядра не превышает 1,0. , это означает нормальную работу.
Обычно, когда n-ядерный ЦП загружается Примените вышеуказанные правила:
Сначала обратите внимание на load_15m и load_5m, нагрузка в основном поддерживается между 3-5, что указывает на то, что долгосрочная нагрузка в системе поддерживается на высоком уровне.
Снова взглянув на load_1m, можно увидеть, что флуктуация очень велика, и она намного больше, чем количество ядер ЦП за многие периоды времени.
Занятый в краткосрочной перспективе и нервный в среднесрочной и долгосрочной перспективе, это, вероятно, будет началом заторов. Выяснить причину высокой нагрузки Судя по использованию ЦП, памяти и ввода-вывода на приведенном выше рисунке, эти три значения невелики.
Использование ЦП низкое, а нагрузка высокая, что исключает возможность высокой нагрузки, вызванной недостатком ресурсов ЦП. Затем используйте vmstat для просмотра общего рабочего состояния процесса, памяти, ввода-вывода и других систем, как показано ниже: Общее направление исследования: частые прерывания и переключение потоков (поскольку на этом ecs всего один java-сервис, в основном исследуем процесс) Через vmstate можно просмотреть только общее переключение контекста ЦП, а информацию о переключении контекста на уровне потока можно просмотреть с помощью команды pidstat.
pidstat -wt 1 (на рисунке ниже показаны данные 9s, всего 36w раз, в среднем 4w раз в секунду) Подтвердите источник этих потоков Java и проверьте количество потоков в процессе приложения.
кошка /proc/17207/статус Направление расследования: Сначала проверьте основную причину, то есть количество переключений контекста некоторых потоков слишком велико.
Получите информацию о стеке процесса в Интернете, а затем найдите идентификатор потока, время переключения которого достигает 100+/секунду, преобразуйте идентификатор потока в шестнадцатеричный формат и получите его в журнале стека. На приведенном выше рисунке вы можете увидеть статус процесса TIME_WAITING, код проблемы, com.alibaba.ons.open.trace.core.dispatch.impl.AsyncArrayDispatcher и проверить несколько других потоков с частым переключением контекста.Информация о стеке в основном то же. Затем проверьте проблему слишком большого количества потоков и проанализируйте информацию о стеке, чтобы обнаружить большое количество потоков ConsumeMessageThread (сначала игнорируются потоки связи, мониторинга, сердцебиения и другие потоки). По имени потока поиск в исходном коде RocketMQ может в основном найти следующую часть кода. Посмотрите на конфигурацию message-consumer для количества основных потоков и максимального количества потоков и обнаружите, что на уровне кода нет специальной конфигурации, поэтому используется системное значение по умолчанию, то есть следующий рисунок Пока что причину чрезмерного количества потоков можно примерно локализовать: Поскольку количество потоков-потребителей (ConsumeThreadNums) не указано, количество основных потоков системы по умолчанию равно 20, а максимальное количество потоков равно 64. При инициализации каждого потребителя создается пул потоков с количеством основных потоков, равным 20. будет создано, то есть велика вероятность, что у каждого потребителя будет 20 потоков, потоки потребляют сообщения,
В результате количество потоков резко возрастает (20*число потребителей), но обнаруживается, что большинство этих потоков-потребителей находятся в состоянии сна/ожидания, что мало влияет на переключение контекста. Количество переключений контекста потока слишком велико. Устранение неполадок на уровне кода:
Этот код нельзя искать в исходном коде RocketMQ. Приложение использует Alibaba Cloud SDK.Поищите в SDK, проверьте контекст и вызовите ссылку, и вы обнаружите, что этот код принадлежит модулю возврата трека. В сочетании с кодом для анализа процесса модуля возврата дорожки (AsyncArrayDispatcher) итог выглядит следующим образом: Найдите код в журнале стека потоков в исходном коде SDK следующим образом: Из этого кода и информации о стеке мы видим, что проблема возникает в traceContextQueue.poll(5, TimeUnit.MILLISECONDS); где traceContextQueue — ограниченная блокирующая очередь. При опросе, если очередь пуста, она будет блокироваться на определенное время. time, поэтому поток будет заблокирован на определенное время.Частое переключение между run и time_wait. Что касается того, почему poll(5, TimeUnit.MILLISECONDS) используется вместо take(), я лично думаю, что это может быть связано с сокращением количества операций ввода-вывода в сети. одиночный трек? Очередь трассировки traceContextQueue использует ArrayBlockingQueue, ограниченную очередь блокировки, внутри используется массив для хранения элементов, а параллельный доступ достигается за счет блокировок, а элементы также располагаются по принципу FIFO. Поскольку каждый потребитель открывает только один поток распределения треков, в этой части нет конкуренции. Рассмотрим принцип реализации блокировки ArrayBlockingQueue. Из приведенной выше части кода видно, что блокировка наконец-то реализована методом park, unsafe.park — нативным методом Метод park заблокирует текущий поток, и метод вернется только при выполнении одного из следующих четырех условий. На данный момент причины переключения системных потоков и частых прерываний сводятся к следующему: Сочетая вышеперечисленные причины, провести целенаправленную оптимизацию
В-третьих, найдите
tips:系统load高,不代表cpu资源不足。Load高只是代表需要运行的队列累计过多。但队列中的任务实际可能是耗cpu的,也可能是耗i/0及其他因素的
CPU寄存器,是CPU内置的容量小、但速度极快的内存。程序计数器,则是用来存储CPU正在执行的指令的位置,或者即将执行的下一条指令的位置。
他们都是CPU在运行任何任务前,必须依赖的环境,因此也被叫做CPU上下文。
CPU上下文切换,就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文,到这些寄存器和程序计数器,
最后再跳转到程序计数器所指的新位置,运行新任务。
В-четвертых, анализ кода
ps:由于线程池队列用的LinkedBlockingQueue无界队列,LinkedBlockingQueue的容量默认大小是Integer.Max,在任务没有填满这个容量之前不会创建新的工作线程,因此最大线程数没有任何作用。
poll()方法会返回队列的第一个元素,并删除;如果队列为空,则返回null,并不会阻塞当前线程;出队的逻辑调用的是 dequeue()方法,此外,它还有一个重载的方法,poll(long timeout, TimeUnit unit),如果队列为空,则会等待一段时间
所谓的公平是指阻塞的线程,按照阻塞的先后顺序访问队列,非公平是指当队列可用的时候,阻塞的线程都可以有争夺线程访问的资格,有可能先阻塞的线程最后才能访问队列。
V. План оптимизации