Выжившие поколения продолжают расти при выполнении запроса Solr - PullRequest
1 голос
/ 16 июня 2020

Я тестирую запрос с помощью jSolr (7.4), потому что считаю, что он вызывает утечку памяти в моей программе. Но я не уверен, что это действительно утечка памяти, поэтому обращаюсь за советом!

Этот метод вызывается несколько раз во время работы моей программы индексирования (должна быть в состоянии работать недели / месяцы без каких-либо проблем. ). Вот почему я тестирую его на al oop, который я профилирую с помощью Netbeans Profiler.

Если я просто извлекаю идентификатор из всех документов (их 33k) в данном индексе:

public class MyIndex {
    // This is used as a cache variable to avoid querying the index everytime the list of documents is needed
 private List<MyDocument> listOfMyDocumentsAlreadyIndexed = null;

 public final List<MyDocument> getListOfMyDocumentsAlreadyIndexed() throws SolrServerException, HttpSolrClient.RemoteSolrException, IOException {

  SolrQuery query = new SolrQuery("*:*");

  query.addField("id");
  query.setRows(Integer.MAX_VALUE); // we want ALL documents in the index not only the first ones

  SolrDocumentList results = this.getSolrClient().
    query(query).getResults();

    /**
    * The following was commented for the test, 
    * so that it can be told where the leak comes from.
    *
    */

    //            listOfMyDocumentsAlreadyIndexed = results.parallelStream()
    //                    .map((doc) -> { // different stuff ...
    //                                  return myDocument;
    //                                  })
    //                    .collect(Collectors.toList());

    return listOfMyDocumentsAlreadyIndexed; 
    /** The number of surviving generations 
     *  keeps increasing whereas if null is 
     * returned then the number of surviving 
     * generations is not increasing anymore
    */
}

Я получаю это от профилировщика (после почти 200 запусков, которые могут имитировать год выполнения моей программы):

enter image description here

Объект, который является наиболее выживающим является String:

enter image description here

Является ли ожидаемое поведение растущего числа выживших поколений ожидаемым поведением при запросе всех документов в индексе?

Если это так, то причина root ошибки «OOM Java heap space», которую я получаю через некоторое время на производственном сервере, как кажется, из трассировки стека:

Exception in thread "Timer-0" java.lang.OutOfMemoryError: Java heap space
at org.noggit.CharArr.resize(CharArr.java:110)
at org.noggit.CharArr.reserve(CharArr.java:116)
at org.apache.solr.common.util.ByteUtils.UTF8toUTF16(ByteUtils.java:68)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:868)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:857)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:266)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocument(JavaBinCodec.java:541)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:305)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readArray(JavaBinCodec.java:747)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:272)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocumentList(JavaBinCodec.java:555)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:307)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readOrderedMap(JavaBinCodec.java:200)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:274)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.unmarshal(JavaBinCodec.java:178)
at org.apache.solr.client.solrj.impl.BinaryResponseParser.processResponse(BinaryResponseParser.java:50)
at org.apache.solr.client.solrj.impl.HttpSolrClient.executeMethod(HttpSolrClient.java:614)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:255)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:244)
at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:194)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:942)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:957)

Будет ли увеличение объема кучи («-Xmx») с 8 ГБ до большего решает проблему определенно, или это просто откладывает ее? Что можно сделать, чтобы обойти это?

Изменить через несколько часов

Если null возвращается из тестируемого метода (getListOfMyDocumentsAlreadyIndexed), то количество выжившие поколения остаются стабильными на протяжении всего теста:

enter image description here

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

Редактировать даже позже

Я заметил, что выжившие поколения все еще увеличивались на вкладке телеметрии, когда я профилировал «определенные классы» ( "сфокусированный (инструментированный)"), тогда как он был стабильным при профилировании "Все классы" ("Общие (выборочные)"). Поэтому я не уверен, что это решило проблему:

Profiling defined classes (focused)

Profiling all classes (sampled)

Любые подсказки приветствуются : -)

1 Ответ

0 голосов
/ 28 июня 2020

Проблема возникает из следующей строки:

query.setRows(Integer.MAX_VALUE);

Это не должно выполняться в соответствии с этой статьей:

Параметр rows для Solr может использоваться для возврата большего количества чем 10 строк по умолчанию. Я видел, как пользователи успешно устанавливали параметр строк на 100-200 и не видели никаких проблем. Однако установка более высокого значения параметра rows имеет большие последствия для памяти, и этого следует избегать любой ценой.

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

SolrQuery q = (new SolrQuery(some_query)).setRows(r).setSort(SortClause.asc("id"));
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
boolean done = false;
while (! done) {
  q.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
  QueryResponse rsp = solrServer.query(q);
  String nextCursorMark = rsp.getNextCursorMark();
  doCustomProcessingOfResults(rsp);
  if (cursorMark.equals(nextCursorMark)) {
    done = true;
  }
  cursorMark = nextCursorMark;
}

Обратите внимание: вы не должны превышать 200 документов в setRows, иначе утечка памяти все равно произойдет (например, для 500 это произойдет).

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

введите описание изображения здесь

Однако этот метод намного медленнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...