1. Предпосылки
В первую очередь было установлено, что приложение для онлайн-анализа работает ненормально, и данные анализа не выводятся несколько дней подряд. Поэтому войдите в онлайн, чтобы просмотреть журнал error.log и найти:
Во-вторых, процесс расследования.
1. Предварительное позиционирование
jinfo
Во-первых, мы используемjinfo pid
Просмотрите связанные с кучей параметры текущего jvm:
jstat
Далее используем командуjstat -gcutil pid 1s 5
Проверьте текущее использование кучи в течение 5 секунд:
jmap
В дополнение к команде jstat мы также можем использоватьjmap -heap pid
Просмотр текущего ворса JVM:
jmap -F -histo pid | head -n 13
Посмотрите первые 13 строк печати, то есть посмотрите ТОП10 крупных объектов (лучше всего ограничиться головой, иначе перечисленные объекты заполнят ваш экран, дополнительно: обязательные параметры подключения-F
правильноjmap -histo:live
это недействительно):java.util.HashMap
иjava.util.ArrayList
Очень бросается в глаза... Сначала запишите, а потом продолжайте анализировать.
Наконец, мы используем командуjmap -F -dump:file=a.bin pid
Скидываем кучу и обнаруживаем, что в сброшенном файле 4.02G, что очень пугает, так что пользуйтесьtar -czvf a.tar.gz a.bin
Упакуйте это!
2. Углубленный анализ МАТ
Отрегулируйте максимальную память кучи MAT
Будет упакованаa.tar.gz
Вернитесь к локальному и разархивируйте. Однако, поскольку a.bin слишком велик, память будет переполняться при открытии MAT, поэтому отрегулируйте максимальную память кучи программного обеспечения MAT:
[ MAT根目录下的MemoryAnalyzer.ini ]
-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200
-vmargs
-Xmx6g
-Xmx изменен на 6G!
MAT анализирует большие объекты
java.lang.Object[]
изDetails
,Как показано ниже:jmap -histo pid | head -n 13
исключениеArrayList
, а также внутреннеHashMap
составляют!Прогулка по коду
комбинироватьerror.log日志报出的问题JAVA类
,报错代码行数
, а затем объединить问题应该出在一个ArrayList上
, легко найти соответствующий блок кода проблемы:
/**
* 按照指定起止时间分析数据
* @param beginTime 起始时间
* @param endTime 截至时间
*/
@Override public void exec(String beginTime, String endTime) {
List<Map<String, Object>> emlWithLoginList = new ArrayList<>();
List<Map<String, Object>> emlList = new ArrayList<>();
while (true) {
try {
//如果已分析到截至时间,则退出。
if (DateUtil.compareTime(beginTime, endTime) > 0) {
break;
}
//每次循环向前推10小时,YCYX_PERIOD=10小时
String tmpTime=DateUtil.addHours(beginTime, YCYX_PERIOD);
//1.构造请求
BoolQueryBuilder bqb = QueryBuilders.boolQuery();
bqb.must(QueryBuilders.rangeQuery(CREATE_TIME).gt(beginTime).lte(tmpTime));
bqb.must(QueryBuilders.termQuery(IS_DELETE, IS_FIELD_VALUE));
bqb.must(QueryBuilders.existsQuery(TOS));
bqb.must(QueryBuilders.existsQuery(FROMS));
bqb.must(QueryBuilders.existsQuery(SEND_TYPE));
bqb.must(QueryBuilders.existsQuery(SESSION_ID));
log.debug("emlAnalysis begin at " + beginTime + ", and end at " + lastTime);
SearchSourceBuilder requestBuilder = new SearchSourceBuilder().query(bqb).size(PAGE_SIZE).sort(CREATE_TIME, SortOrder.ASC).fetchSource(new String[] {"*"},
new String[] {EML_CONTENT});
//2.发起请求
EsHelper.getResponseScroll(EsCluster.DEFAULT, INF_EML_INDEX, "14m", requestBuilder.toString(), result -> {
//3.解析结果
EsSearchHit[] hits = result.getHits().getHits();
List<Map<String, Object>> loginList;
for (EsSearchHit hit : hits) {
//将邮件Map添加到列表中
Map<String, Object> emlMap = hit.getSource();
emlList.add(emlMap);
//将邮件+MailLogin的Map添加到另一个列表中
Map<String, Object> emlWithLoginMap = new HashMap(emlMap);
String sessionId = emlMap.get(SESSION_ID).toString();
MailLogin mailLogin = EsService.getMailLoginBySessionId(sessionId);
emlWithLoginMap.put("Login_Key", mailLogin );
emlWithLoginList.add(emlWithLoginMap);
}
return true;
});
//4.A类检测逻辑
checkDSYJEml(emlWithLoginList);
emlWithLoginList.clear();
//5.B类检测逻辑
checkYCYXEml(emlList);
emlList.clear();
beginTime = tmpTime;
} catch (Throwable e) {
log.error("", e);
}
}
}
Как видно из приведенного выше кода, Список проблем должен бытьemlWithLoginList
илиemlList
Один из двух списков хранит в основном одно и то же содержимое, за исключениемemlWithLoginList
Внутри элемента Map хранится дополнительный файл с именемLogin_Key
ключ!
А через МАТ проверил все Ключи элементов Карты в Списке задач, и родственных обращений не нашел.Login_Key
, поэтому предполагается, что список проблем должен быть такимemlList
!
Итак, давайте сначала предположим, это потому, что данные ES за текущий период времени слишком велики?
Как видно из кода, данные, запрашиваемые ES, передаются черезCREATE_TIME(该常量值为@createtime)
Для восходящего запроса данные, которые должны быть проверены в первую очередь, должны находиться в этом问题List
в начале, а затем данные проверены в问题List
конец.
Так что найди по МАТ问题List
Первый и последний элементы , то есть время начала и окончания этого запроса:
На рисунке показано, что, запросив этот пакет данных, программа получила 310 000 фрагментов данных!
И я пошел в Kibana, чтобы запросить объем данных за этот период времени:
Сразу завораживает, ситуация немного неразумная, долго обдумывал, поэтому внимательно прочитал следующий код:
clear()
Метод очищает Список, почемуemlWithLoginList
нет проблем, покаemlList
Но переполнение памяти?
Тогда очевидно:
- при выполнении
checkYCYXEml(emlList)
Когда было исключение, оно будет прямо нижеcatch
захватить; - Так что не упадет
emlList.clear()
код пока не идетbeginTime = timeTime
; - Поскольку try catch находится внутри цикла while, цикл будет продолжаться после того, как будет выброшено исключение, а также потому, что выполнение не выполняется.
beginTime = timeTime
, поэтому запрашиваемые данные по-прежнему являются данными предыдущего периода времени; - В то же время это также может объяснить, почему
emlWithLoginList
Нет проблем, потому что перед кодом исключения обычноclear()
работать.
Тогда, если этоcheckYCYXEml(emlList)
При возникновении исключения файл error.log должен быть напечатан вместе с журналом исключений через ключевое словоcheckYCYXEml
Поиск:
Согласно вышеизложенному, если причина в этом, этот код повторит запрос2019-11-01 16:00:00
прибыть2019-11-02 02:00:00
данных и постоянно добавляется вemlList
, и, наконец, взорвать JVM!
то это в МАТ问题List
Должно быть несколько одинаковых элементов (данные добавляются многократно).
Как это проверить?
Поскольку эти данные имеютemlkey
Поле, представляет собой уникальный первичный ключ, соответствующий данной записи в ЭП._id
, так через ВСУ, по некоторым даннымemlkey
, выяснить, является ли问题emlList
Существует несколько элементов с одинаковымиemlkey
, что можно доказать.
Группа струн МАТ
-XX:+UseStringDeduplication
функция для решения проблемы повторяющихся строк. Это приведет к этим сотням тысяч экземпляров String, но все их базовые массивы будут указывать на один и тот же массив char.
Фигура представляет собой операцию группировки для String, В настоящее время мы можем найти элемент случайным образом.emlkey
, запрос:
merge shortest paths to gc roots
можно посмотреть кратчайший путь от этих объектов до GC ROOT.. Грубо говоря, я просто хочу использовать эту функцию, чтобы проверить, какому объекту принадлежит текущая String:854742740486326718e
emlkey
свойства, аdocument_id
Атрибут, эти два значения одинаковые, оба представляют ES_id
, как показано на рисунке:В конце концов, эта проблема в основном позиционируется.Репарация проста, и два метода CLEAR() перемещаются в НАКОНЕЦ после catch, то есть 100% будут вызываться, а коллега прерывания - коллега, для Icetimeout .Проблема решена.