Устранение неполадок и решение проблем OOM для потребителей dubbo с оптимизацией производительности

Java EE

1. Описание проблемы

Шлюз устройства внезапно столкнулся с большим количеством задержек, контейнер постоянно перезагружался, а в журнале появилась ошибка переполнения памяти "java heap space". После проверки данных мониторинга apm было обнаружено, что полный gc был частым и ответ рт был очень медленным. добавлен

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/opt/oom/heapdump

параметры JVM и подключите файл контейнера к файлу хоста, легко поймать файл дампа. Также представьте текущую архитектуру развертывания, как показано на рисунке ниже. Шлюз и служба домена взаимодействуют через структуру dubbo. Поскольку служба публикации информации является архитектурой промежуточной платформы, в дополнение к использованию шлюза устройств облачного класса она также необходимо предоставлять услуги другим системным платформам. Объем вызовов относительно высок, поэтому количество экземпляров составляет около 15, в то время как шлюз устройств имеет только 6 экземпляров.

2. Анализ проблемы

2.1 Анализ ошибки переполнения памяти

Распространенные ошибки переполнения памяти: исчерпана собственная память (невозможно создать новый собственный поток)/постоянная генерация или недостаточно метапространства (PermGenSpace)/недостаточно памяти в куче (пространство в куче Java)/превышен предел накладных расходов GC ( Превышен лимит накладных расходов сборщика мусора), и существует много различных причин для выдачи OutOfMemoryError. Для постоянной генерации и обычной кучи утечка памяти является частой причиной OutOfMemoryError. Инструменты анализа кучи могут помочь нам найти основную причину утечки.

После анализа файла дампа с помощью JProfiler обнаружено, что больший из них имеет две строки поля по 11 МБ.Содержимое строк является текстовым содержимым поля рассылки.Предварительное суждение состоит в том, что содержимое результата, возвращаемого Dubbo после вызова Базовая микрослужба почтовой рассылки заполнена памятью. Глядя на журнал apm микрослужбы публикации информации в то время, было обнаружено, что время ожидания многих транзакций MySQL истекло, и все они были операторами SQL для получения содержимого ресурсов, что еще раз подтвердило предположение.

2.2 Анализ процесса обзвона потребителей

Прочитав информацию о стеке выше, все очень удивились, почему такое распределение стека? Какое это имеет отношение к фреймворку Dubbo? Процесс приложения использует платформу Dubbo для связи с поставщиком удаленных услуг, а используемая модель ввода-вывода показана на рисунке ниже. Когда процесс приложения записывает данные в сокет, ему сначала нужно подать заявку на буфер записи в приложении, а затем записать данные в буфер записи, а затем выполнение приложения переключится с пользовательского состояния на основное состояние. , и программа состояния ядра переключит приложение в состояние ядра.Данные в буфере записи копируются в кэш записи на уровне операционной системы. Когда процесс приложения считывает данные, ему необходимо скопировать данные из буфера чтения на уровне операционной системы в буфер чтения на уровне приложения. Как правило, буферы на уровне приложения применяются из пространства кучи, что требует копирования данных во время передачи данных между пользовательским режимом и основным режимом. Это связано с тем, что состояние ядра не может напрямую обращаться к памяти кучи приложения и должно быть преобразовано в прямую память.У вас может быть такое базовое понимание, что если в сети передается большой объем данных и их нужно обрабатывать прикладному процессу, то легко свернуть прикладной процесс (OOM).

                         

Давайте проанализируем полный процесс запроса RPC на стороне потребителей Dubbo, как показано на рисунке ниже. Бизнес отправляет запрос RPC, а затем записывает его в канал сокета через NettyChannel. Когда поставщик услуг обрабатывает запрос, он напишет результат Для установленного сокета. В канале Netty Network Library прослушивает эти сетевые события IO и уведомить процесс приложения для чтения данных связи в канале, декодируйте и десериализуют и, наконец, возвращает результат к верхнему слою.

Собственно, вот любопытно, почему объекты Hessian2Input будут занимать столько памяти? Во-первых, скажите, что вы соблюдаете принципы протокола Binary-Rpc кадра, как правило, с помощью последовательности отправителя в качестве инструмента Гессе для преобразования объекта потока двоичных данных, используя получатель получает последовательный поток данных в повторное использование инструмента подобъектов. Hessian увидеть простые варианты использования из следующего примера, основное использование Hessian2Oput / Hessian2Input для достижения. Во фрейме Dubbo это очень сложно, это связано с анализом потока данных IO внутри асинхронной сети, может быть интересно увидеть процесс разрешения ObjectInput / ObjectOutput. 

//返回结果类定义
public class Resource {
     Integer type;
     String content;
     .......
}

//Hessian序列化与反序列化调用
ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(os);
output.writeObject(new Resource("test", "test"));
output.close();

ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray());
Hessian2Input input = new Hessian2Input(in);
System.out.println(input.readObject());

Конкретный флаг синтаксического анализа кодирования гессиана определяется в HessianConstants.Во время процесса декодирования гессианаСначала прочитайте определение типа возвращаемого результата, а затем проанализируйте каждый тип поля и значение поля один за другим..

При парсинге поля типа String используется метод Hessian2Input#readString, одна из логик которого заключается в добавлении всех прочитанных в сетевом потоке символов в объект StringBuilder в Hessian2Input, что эквивалентно StringBuilder в качестве буфера для приема строк. , поэтому будет два больших объекта StringBuilder.

3. Решение проблем

На самом деле, это очень простой принцип,Поставщик услуг возвращает большой объект или данные привели к потребителю OOM. После общения с соответствующими коллегами я знаю, что это возвращенное содержимое является содержимым некоторых публикаций с информацией о статьях.По историческим причинам они хранятся непосредственно в базе данных, что привело к возврату большого количества текстового содержимого, когда опубликованное содержимое Получено. В то время это большое текстовое содержимое было срочно преобразовано. Создайте файл и загрузите его в облачное хранилище. Сторона устройства получает URL-адрес ресурса, а затем загружает его и отображает, что решает проблему OOM на стороне потребителя.

4. Резюме

Эта статья представляет собой онлайн-кейс Dubbo, наступившего на яму.Инструмент анализа памяти используется для анализа файлов после OOM в производственной среде, и полностью анализируются основная причина и принцип процесса запроса фреймворка Dubbo. В нем также обобщаются причины и решения часто встречающихся проблем OOM с памятью, что удобно для быстрого выявления проблемы в будущем и дает более глубокое понимание памяти, используемой моделью ввода-вывода Java. Благодаря анализу исходного кода фреймворка Dubbo я всегда оставался на когнитивном уровне расширения функций реестра/прокси/кластера.После анализа и исследования этой проблемы у меня также есть логика Exchange/Transpot/Serialize. о сетевой связи, кодировании и декодировании.

использованная литература

zhuanlan.zhihu.com/p/49916939

nuggets.capable/post/684490…

GitHub.com/Чен Юсан/блог/…

Woo Woo Woo.cn Blog On.com/Director Ang Lee 001 / Боится ...

blog.CSDN.net/hacker_consulting fee/…