Как улучшить производительность Lucene в распределенной среде? - PullRequest
11 голосов
/ 04 июня 2011

Я сталкиваюсь с большим временем поиска (порядка 10 секунд) при поиске в реализации master - shard в распределенной среде.Однако тот же запрос через Luke возвращает в миллисекундах.

Приложение является распределенной системой.Все узлы имеют общее монтирование NFS, в котором находятся индексы.Для простоты рассмотрим два узла Node1 и Node2.Запись /etc/fstab выглядит следующим образом.

nfs:/vol/indexes /opt/indexes nfs rw,suid,nodev,rsize=32768,wsize=32768,soft,intr,tcp 0 0

Существует несколько каналов (скажем, Feed1 и Feed2), которые попадают в систему, и для каждого канала на узел имастер для каждого канала.Индексы выглядят как

Feed1-master
Feed1-shard-Node1.com
Feed1-shard-Node1.com0
Feed1-shard-Node1.com1

Код, который выполняет поиск:

FeedIndexManager fim = getManager(feedCode);
searcher = fim.getSearcher();
TopDocs docs = searcher.search(q, filter, start + max, sort);

private FeedIndexManager getManager(String feedCode) throws IOException {
  if (!_managers.containsKey(feedCode)) {
    synchronized(_managers) {
      if (!_managers.containsKey(feedCode)) {
        File shard = getShardIndexFile(feedCode);
        File master = getMasterIndexFile(feedCode);
        _managers.put(feedCode, new FeedIndexManager(shard, master));
      }
    }
  }  
  return _managers.get(feedCode);
}

FeedIndexManager выглядит следующим образом.

public class FeedIndexManager implements Closeable {

  private static final Analyzer WRITE_ANALYZER = makeWriterAnalyzer();
  private final Directory _master;
  private SearcherManager _searcherManager;
  private final IndexPair _pair;

  private int _numFailedMerges = 0;
  private DateTime _lastMergeTime = new DateTime();

  public FeedIndexManager(File shard, File master) throws IOException {
    _master = NIOFSDirectory.open(master, new SimpleFSLockFactory(master));

    IndexWriter writer = null;
    try {
      writer = new IndexWriter(_master,
                               WRITE_ANALYZER, 
                               MaxFieldLength.LIMITED);
    } finally {
      if (null != writer) {
        writer.close();
      }
      writer = null;
    }

    _searcherManager = new SearcherManager(_master);
    _pair = new IndexPair(_master,
                          shard, 
                          new IndexWriterBuilder(WRITE_ANALYZER));
  }

  public IndexPair getIndexWriter() {
    return _pair;
  }

  public IndexSearcher getSearcher() {
    try {
      return _searcherManager.get();
    }
    catch (IOException ioe) {
      throw new DatastoreRuntimeException(
        "When trying to get an IndexSearcher for " + _master, ioe);
    }
  }

  public void releaseSearcher(IndexSearcher searcher) {
    try {
      _searcherManager.release(searcher);
    }
    catch (IOException ioe) {
      throw new DatastoreRuntimeException(
        "When trying to release the IndexSearcher " + searcher
        + " for " + _master, ioe);
    }
  }

  /**
   * Merges the changes from the shard into the master.
   */
  public boolean tryFlush() throws IOException {
    LOG.debug("Trying to flush index manager at " + _master
              + " after " + _numFailedMerges + " failed merges.");
    if (_pair.tryFlush()) {
      LOG.debug("I succesfully flushed " + _master);
      _numFailedMerges = 0;
      _lastMergeTime = new DateTime();
      return true;
    }
    LOG.warn("I couldn't flush " + _master + " after " + _numFailedMerges
             + " failed merges.");
    _numFailedMerges++;
    return false;
  }

  public long getMillisSinceMerge() {
    return new DateTime().getMillis() - _lastMergeTime.getMillis();
  }

  public long getNumFailedMerges() {
    return _numFailedMerges;
  }

  public void close() throws IOException {
    _pair.close();
  }

  /**
   * Return the Analyzer used for writing to indexes.
   */
  private static Analyzer makeWriterAnalyzer() {
    PerFieldAnalyzerWrapper analyzer = 
      new PerFieldAnalyzerWrapper(new LowerCaseAnalyzer());

    analyzer.addAnalyzer(SingleFieldTag.ID.toString(), new KeywordAnalyzer());
    // we want tokenizing on the CITY_STATE field
    analyzer.addAnalyzer(AddressFieldTag.CITY_STATE.toString(),
            new StandardAnalyzer(Version.LUCENE_CURRENT));
    return analyzer;
  }
}

Убийцей, которая потребляет около 95-98% задержки, является этот вызов, поиск занимает около 20 секунд, тогда как если индекс открывается через Luke, то это миллисекунды.

TopDocs docs = searcher.search(q, filter, start + max, sort);

У меня есть следующие вопросы

  1. Разумно ли иметь несколько мастеров на канал или я должен уменьшить его до одного мастера?Количество элементов в индексе составляет около 50 миллионов.

  2. Задержка является низкой для каналов, где число объектов составляет менее миллиона (ответ в секунду).Фиды, в которых число объектов превышает 2 миллиона, занимают около 20 секунд.Должен ли я поддерживать только 1 осколок на узел против 1 осколка на узел на канал?

  3. Слияние осколка с мастером предпринимается каждые 15 секунд.Этот параметр должен быть настроен?

В настоящее время я использую Lucene 3.1.0 и JDK 1.6.Коробки представляют собой два 64-разрядных ядра с 8 ГБ оперативной памяти.В настоящее время JVM работает с максимальным объемом 4 ГБ.

. Любые предложения по улучшению производительности высоко ценятся.Я уже выполнил все стандартные настройки производительности, которые обычно предписываются Lucene.Большое спасибо за чтение этого длинного поста.

1 Ответ

2 голосов
/ 04 июня 2011

Возможно, это не тот ответ, который вы искали, но посмотрите на Elastic Search . Это распределенный кластеризованный сервисный слой вокруг Lucene, который запрашивается по HTTP или может быть запущен встроенным.

И это быстро, довольно смешно. Похоже, что Lucene настроен правильно под одеялом, но при этом предоставляет все возможности конфигурации Lucene, если вам нужно их использовать.

Заставить Lucene работать в распределенной среде сложно, поскольку, как вы обнаруживаете, вы сталкиваетесь с неприятными проблемами блокировки. ElasticSearch предназначен для решения этой конкретной проблемы, поэтому вы можете решить и другие.

...