solr的軟硬提交

最近又被soft commit 和 hard commit搞得有點迷糊,其實都怪自己沒有早點看源代碼。問題出自這段代碼,這也是我一開始接觸solr時,查到的代碼sample(事實證明問題都出在這裏,引以爲戒,有問題真的不要不求甚解)

if (rs.next()){
    while (true) {
        NiuniuSolrInputDocument doc = new NiuniuSolrInputDocument(rs);
        docs.add(doc);
        idx++;
        if(idx>=1000){
            httpSolrServer.add(docs);
            httpSolrServer.commit();
            docs.clear();
            idx = 0;
        }
        if (!rs.next())
            break;
    }
    if(idx!=0){
        httpSolrServer.add(docs);
        httpSolrServer.commit();
    }
}

問題


可以看到我每次執行完add方法以後,都會commit一下,認爲只有commit過後文檔纔會真正的提交。如果按照這個思路走,批量建索引等可能問題不算大,但是如果研究solrconfig的autoCommit和autoSoftCommit就會有問題了。

問題來了,如果有autoCommit那我爲毛要手動commit?

事實是,每次執行httpSolrServer.add(docs)方法,就會進行如下工作:

public UpdateResponse add(Iterator<SolrInputDocument> docIterator) throws SolrServerException, IOException {
    UpdateRequest req = new UpdateRequest();
    req.setDocIterator(docIterator);
    return req.process(this);
  }

即add方法已經把文檔加入到solr中了,只要你的solr設置過autoCommit,那麼每隔一段時間或者每當累積的文檔到達一定數量,就會進行一次commit。

hard commit AND soft commit

看了manual裏的autoCommit和autoSoftCommit的介紹,autoCommit就是自動commit,這裏的commit指的是hard commit,裏面有幾個參數:
maxDocs:add到solr緩衝區的文檔數量超過這個值時,自動執行commit把結果寫入到磁盤索引文件中
maxTime:最長多久執行一次commit,即如果文檔一直沒有通過commit沉澱到磁盤上,那麼持久性就可能出問題,所以要隔一段時間就執行一次commit
openSearcher:要不要新開一個searcher,如果要新開,那麼目前已有的cache就會失效,具體代碼可以看SolrIndexSearcher,它裏面有幾個Cache成員變量,如果你新建立一個searcher那麼cache失效也是正常的了,除非你有autoWarming機制。在詳細一點,就是,如果不執行softCommit(autoSoftCommit的maxTime設置成-1),同時在hard commit的時候openSearcher=false,那麼執行完hard commit之後,磁盤文件雖然改變了,但是searcher沒有新開,需要reload或者重啓,才能看到索引中的新文檔。所以相當於softCommit本身就自帶openSearcher,那麼,如果autoCommit的openSearcher=false,就一定要做softCommit,或者就索性不autoSoftCommit,而是使用autoCommit + openSearcher=true。

上面提到了hard commit,那麼對應的就是softCommit,softCommit和NRTCachingDirectoryFactory息息相關。NRT是Near Realtime的縮寫,即近實時的索引方式。

<directoryFactory name="DirectoryFactory"
                    class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/

solr.NRTCachingDirectoryFactory, the default,
wraps solr.StandardDirectoryFactory and caches small files in memory
for better NRT performance.

   solr.RAMDirectoryFactory is memory based, not
   persistent, and doesn't work with replication

這個有什麼用呢?淘寶的增量商品架構走的就是這種方式,解釋一下用它的理由:

  1. 用戶增量添加商品,我們需要讓這些增量商品儘早能被檢索到
  2. 按照標準的索引文件的格式,文檔想要被檢索到就需要改寫磁盤上的文件,頻繁的改寫帶來了難以接受的IO開銷
  3. 那麼我們需要一種折中的方案,可以先把這部分增量放到內存中,這也是cache的意思,在檢索時會去索引文件和內存中都去查詢,這樣的話就能實時把文檔檢索到,同時不會太頻繁的更新磁盤
  4. 放在內存而不是磁盤就意味着存在persistence的問題,如果服務crash,內存中的文檔就會丟失,這個時候我們就需要autoCommit了。

所以如果我們面臨的是heavy index和heavy query的場景,需要在提交後就能立馬檢索到,就需要對每次增量都進行soft commit,然後設置一個我們能夠容忍的時間interval或者數量上限,定時或者定量去執行一次hard commit,這樣即使系統crash我們也只會丟失這個時間段的文檔,而之前的文檔已經都持久化了。而如果能夠容忍提交後隔20秒才能搜索到,那麼就設置autoSoftCommit參數爲20000就好了,這樣add到index中的文檔每隔20s就會自動softCommit一次,就能被檢索到了。

最終方案,我們把UpdateHandler的參數設置成:

<autoCommit>
  <maxTime>600000</maxTime>
  <openSearcher>false</openSearcher>
</autoCommit>

<autoSoftCommit>
  <maxTime>5000</maxTime>
</autoSoftCommit>

然後在增量提交文檔時,不需要指定commit或者softCommit,新的文檔會根據autoSoftCommit來自動進行軟提交,然後會根據autoCommit來自定進行hard commit,這樣新添加的文檔在5秒之內就可以被檢索到,然後每隔10分鐘,這些文檔就會寫到磁盤上。
curl
http://localhost:8080/solr/niuniu_resource/update? -H "Content-Type: text/xml" --data-binary
'
<add>
<doc>
<field name="raw_id">123478</field>
</doc>
</add>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章