2011-06-04 53 views
11

在分佈式環境中搜索主 - 碎片實施時,我正面臨着漫長的搜索時間(以秒爲單位的順序)。然而,通過Luke進行的相同查詢以毫秒爲單位返回。如何提高分佈式環境中的Lucene性能?

該應用程序是一個分佈式系統。所有節點共享一個共同的NFS掛載位置的索引所在。爲了簡單起見,我們考慮兩個節點Node1Node2/etc/fstab條目如下。

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

有多個Feed(比方說Feed1Feed2)擊中系統並且存在用於每個每個節點進料和爲每個頻道的主的碎片。該指數看起來像

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秒的搜索,而如果索引經由盧克打開它的單位是毫秒。

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

我有以下問題

  1. 它是明智的讓每個飼料多個主機或者我應該將其降低到只有一個主?該指數中的元素數量約爲5000萬。

  2. 對於實體數量少於一百萬(次要響應)的訂閱源,延遲較低。實體超過200萬的訂閱源大約需要20秒。我應該每個節點只維護每個節點1個碎片對每個節點1個碎片?

  3. 從碎片到主人的合併每15秒嘗試一次。這個參數是否應該調整?

我目前使用的是Lucene 3.1.0和JDK 1.6。這些盒子是兩個64位的內核,其中有8個  GB的RAM。目前JVM最多可以運行4   GB。

任何提高性能的建議都受到高度讚賞。我已經執行了Lucene通常規定的所有標準性能調整。非常感謝您閱讀這篇冗長的文章。

+0

我不明白這裏發佈了什麼。你說:「所有的節點共享一個共同的NFS掛載索引所在。」所以所有部件都在同一個物理系統上? NFS很可能會損害性能,就是這種情況。 – 2011-06-15 06:36:17

回答

2

這不是您要查找的答案,也許是,但看看Elastic Search。它是圍繞Lucene的分佈式集羣服務層,通過HTTP查詢或者可以嵌入運行。

而且速度很快,非常可笑。它似乎已經在封面下正確調整了Lucene,並且如果您需要使用它們,仍然會暴露完整的Lucene配置選項。

讓Lucene在分佈式環境中執行很困難,正如你發現的那樣,你最終會遇到令人討厭的鎖定問題。 ElasticSearch旨在解決該特定問題,因此您可以解決其他問題。

+1

嘿,謝謝你的快速回復。 Infact ES和SOLR在桌面上。但我在這裏打的是遺留的代碼。我希望我能翻轉開關,這實際上我會。我並不從事搜索優化業務,而是將其留給該領域的專家。儘管如此,你是否通過SOLR做過ES的基準測試?和/或你有一個在另一個推薦。 – Andy 2011-06-05 15:53:39