Полнолинковая оптимизация интерфейса Java: как уменьшить продолжительность RT интерфейса

Java задняя часть база данных SQL

Справочная информация. Из-за большого количества сложных приложений в прошлом, приложение компании недавно было оптимизировано и преобразовано, и все интерфейсные RT должны быть ниже значения xxx.

1. Мониторинг

Вот и возникает проблема~ Сейчас приложения все забиты, средств мониторинга почти нет, и собрать логи по интерфейсу логов невозможно, так как же узнать, какие интерфейсы имеют длинные RT и нуждаются в оптимизации? Итак, первое, что мы делаем, это мониторим.

Инструмент мониторинга: пинпоинтер.

Есть несколько соображений по выбору пинпоинта:

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

2. Зависимости приложений, взаимосвязи вызовов очевидны с первого взгляда, а все процессы связаны через traceId для облегчения устранения неполадок. Это тоже очень важно.В распределенной системе запрос связи вызовов слишком сложен.Если отсутствует идентификация traceId, вам будет сложно найти связь вызова верхнего уровня запроса.

3. Интерфейс различных графиков мониторинга, в том числе, конечно, графиков RT, что удобно для быстрого поиска ссылок, которые необходимо оптимизировать.

Исходный код и руководство по пинпойнту см. на https://github.com/naver/pinpoint.

Мы можем в общих чертах взглянуть на страницу мониторинга pinpoint, как показано ниже.

Из рисунка можем получить:

Столбец ссылки на вызов показывает, что запрос фактически дважды выполняет SQL.

Столбец времени выполнения показывает, что первый раз занял 19 мс, а второй раз — 722 мс.

traceId — это уникальный идентификатор этого запроса, если нам нужно записать это значение в приложении, его также можно получить через соответствующий API.

Конечно, этот пример является очень простым запросом.Он также может отслеживать такие операции, как вызовы dubbo, HTTP-запросы, Redis, db и т. д., поэтому, пока приложение настраивает его, детали вызова, выполненного запросом будет ясно с первого взгляда, и это в пределах нашей досягаемости, вместо того, чтобы позволить ему развиваться.

2. Оптимизация

Теперь, когда цель определена нами, наш следующий шаг, конечно же, решить ее и оптимизировать. Я получил очень общий и практический опыт оптимизации в процессе оптимизации, особенно для начинающих, вы можете много на него ссылаться. Потому что это привычки и нормальная логика для тех, кто только начинает программировать, но это не значит, что она оптимальна.

1. Циклические SQL-операции

Такого рода ситуации очень просты для новичков, например, создание торгового ордера. Наши отношения мастер-ребенок таковы:

Тогда для создания заказа нужно сгенерировать 1 основной заказ и N подзаказов.В это время многие пишут так (код только представляет процесс выполнения):

insert(主单);
for(子单:子单列表){
    insert(子单);
}

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

insert(主单);
batchInsert(子单列表);

Mybatits поддерживает циклические теги, поэтому просто измените SQL в файле sqlMap. Кроме того, возможно и пакетное обновление, для выполнения пакетных операций необходимо добавить параметр allowMultiQueries=true в ссылку на базу данных.

2. Индекс базы данных

Конечно, индекс должен быть построен, в противном случае вы должны узнать, когда. Тем не менее, он строится и строится, но мы должны правильно его использовать. Мы можем использовать команду объяснения, чтобы определить, использует ли SQL индекс.EXPLAIN SELECT * FROM article WHERE id=10;

key и rows отражают используемый индекс и ожидаемое количество строк для сканирования. Есть еще несколько вещей, на которые нам нужно обратить внимание:

Когда мы оптимизируем ORDER BY в операторе Query, мы можем максимально использовать существующий индекс, чтобы избежать фактического вычисления сортировки, что может значительно повысить производительность операции ORDER BY. В процессе оптимизации какого-либо запроса, даже если порядок полей индекса корректируется, чтобы избежать фактической операции сортировки, стоит даже добавить поля индекса.Потому что в MySQL существует два типа упорядочения по реализациям:

1) Один из них — получить упорядоченные данные напрямую через упорядоченный индекс, чтобы клиент мог быть удовлетворен без какой-либо операции сортировки. Запрошенные упорядоченные данные возвращаются клиенту;

2) Один из них заключается в сортировке данных, возвращаемых механизмом хранения, с помощью алгоритма сортировки MySQL, а затем в сортировке отсортированных данных. данные возвращаются клиенту

Наш индексuser_id,define_id,seqСовместный индекс, видно, что первое изображение sort define_id идет сразу в индекс, второе изображение не может пройти через индекс и требует дополнительной операции сортировки. group by также является оптимизированным способом.

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

Тип java-приложения должен соответствовать типу столбца индекса базы данных. Например, тип java — long, а тип базы данных — varchar. Таким образом, индекс не будет использоваться для запроса, но сообщение об ошибке не будет сообщено .На следующем рисунке показано сравнение двух методов:

3. Счетчик нельзя использовать

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

1).Count будет запрашивать все записи, соответствующие условиям.Если таблица очень большая, это может привести к полному сканированию таблицы.Мы все знаем последствия. 2) Если для контроля используется count, то во время выполнения бизнес-логики он должен быть заблокирован, иначе результат count только что будет напрасным, что также заблокирует все запросы на эту активность.

В этом сценарии мы обычно добавляем поле счетчика к записям, которые необходимо контролировать, например, контролируя максимальное получаемое значение num=10. В бизнес-логике полный контроль можно преобразовать в способ SQL,update xxx set num=num-1 where id=xx and num>0;Это атомарная операция, может гарантировать, что она не превысит ошейник. В зависимости от результатов возврата, чтобы определить, были ли они успешными (возвращает результаты для количества затронутых строк).

4. Блокировка

Автономные блокировки и распределенные блокировки.На самом деле, если мы можем избежать блокировок, мы не должны их использовать, потому что блокировка означает, что они могут выполняться только последовательно, а количество параллелизма снижается до 1, что определенно повлияет на производительность.

Если это сценарий, аналогичный вычету запасов, см. статью 3. Избегается атомарными операциями в базе данных.
Для таких операций, как обновления, можно использовать оптимистическую блокировку, чтобы избежать долгосрочной блокировки.
Если вам нужно использовать блокировку, будь то блокировка для одного компьютера или распределенная блокировка, мы должны оценить влияние блокировки, будь то для одного пользователя или всех пользователей, один пользователь может использовать его, потому что параллелизм одного пользователя чрезвычайно низок. , но если работа всех пользователей заблокирована, она должна быть хорошо оценена, эта операция приведет к блокировке аналогичных операций всех пользователей.

5. Надлежащее резервирование

В распределенных системах избыточность должна быть очень распространенной ситуацией. Мы не должны гнаться за стандартом парадигмы базы данных в настоящее время, потому что он разработан в соответствии с первой парадигмой базы данных, и все поля не являются избыточными, но это доставляет много хлопот нашему запросу. Может быть, когда мы проверяем заказ, нам нужно делать связанные запросы, проверять информацию о подзаказе, проверять информацию о продукте, проверять информацию об оплате и т. д., и так много запросов, думать о том, может ли RT нашего интерфейса быть быстрым, и может ли qps может быть высоким. Избыточная базовая информация, такая как названия продуктов, может уменьшить запрос фактических модулей, что неплохо.

6. Кэш Redis

На самом деле в нашей системе вообще используется кеш, так что особой оптимизации для этой части нет. Или подытожить некоторый опыт. Выбор стратегии обновления кэша: недопустимое обновление или обновление по времени. Потому что отслеживается, что многие интерфейсы RT всегда регулярно тормозят, это потому, что когда кеш недействителен, необходимо собирать данные из db и других модулей, а затем пушить их в кеш.В это время все запросы не могут идти через кеш и трафик Это также может быть смертельным фактором, когда он старше. Если это так, например, главная страница рекомендует продукты, рекомендуемые сообщения и т. д., одни и те же сцены с большим количеством посещений могут регулярно обновляться.Использование командной строки Keys* строго запрещено: Redis — это один поток, и выполнение этой команды приведет к блокировке всех последующих запросов, что повлияет на производительность всей системы.

7. Поисковые системы

Это может сбивать с толку, как поисковая система может оптимизировать RT?Конечно, он медленнее, чем БД, но в некоторых сценариях может быть быстрее, чем БД. Например, форум сообщества должен фильтровать и сортировать статьи, всего полей десять, и их можно свободно комбинировать, в это время БД бессильна, потому что слишком много условий, различных операций сортировки и операций объединения. , и база данных не может построить индекс. Мы можем преобразовать поля в таблицах A и B в полную информацию, отправить ее в поисковую систему и выполнять поиск напрямую в соответствии с условиями при запросе. Это может не только обеспечить rt, но и предотвратить перетаскивание БД сложными запросами.