solr(軟提交和硬提交)


     因項目用到了solr作為檢索引擎,最近業務需求新增一個字段作為檢索條件,由於該字段經常被修改到,並且關聯的文檔比較多,如果修改的時候立即修改索引,則時間會很久,網上查了很多資料,發現了解決方案,今天特此記錄一番。

  方案:采用軟提交方式。

    solr4.x后引入了軟提交solrfCommit。

    solr配置方式:在solrconfig.xml中設置

       <updateHandler class="solr.DirectUpdateHandler2">

        <!-- 如果設置autoCommit,表示每隔一段時間(值單位為毫秒)或者當累積的文檔到達一定數量時就會進行一次commit -->
        <!-- openSearcher表示是否要新開一個searcher,如果不執行softCommit且值為false,當hardCommit執行完成后,
        索引雖然更新到磁盤文件了,但searcher沒有新開,這時需要reload或者重啟才能索引到更新后的索引;
        如果值設為true,則可以去掉softCommit -->
        <autoCommit>
        <!--<maxDocs>500</maxDocs>-->
        <maxTime>${solr.autoCommit.maxTime:300000}</maxTime> <!--每隔五分鍾持久化 -->
        <openSearcher>false</openSearcher>
        </autoCommit>
        <autoSoftCommit>
        <maxTime>${solr.autoSoftCommit.maxTime:60000}</maxTime> <!--每隔一分鍾軟提交 -->
        </autoSoftCommit>

        </updateHandler>

        可以參考 https://blog.csdn.net/weixin_39915358/article/details/80278882

      1、如果配置了上述配置,則在add  solrInputDocument的時候可以不commit,solr會根據配置 去執行軟提交和硬提交,這就節省了業務操作時的等待時間,代價沒這么昂貴。

      2、java代碼中也可以設置軟提交solrServer.commit(true, true, true),如果執行這句則會立刻執行軟提交,新增數據查詢可見。(個人覺得沒必要,因為配置文件已經配置有了)。

      3、不管是軟提交還是硬提交,還是不提交,都有日志文件生成,solr正常關閉時會執行一次硬提交,不正常關閉會在重啟的時候加載日志文件進行數據的恢復(親測有效)。硬提交設置時間一般為1-10分鍾,軟提交時間根據能容忍的情況而定。

      3、關於日志恢復網上看了一遍文章覺得寫得挺好的,可以參考https://hacpai.com/article/1489704451481?p=1&m=0 ,里面有句話“硬提交是關於持久化,軟提交是關於可見性“,這應該很比較通俗易懂的概括這兩個的作用。

 

  下面為地址https://hacpai.com/article/1489704451481?p=1&m=0的原文,怕以后找不到所以復制過來了。 

從 solr4.0 起,solr 多了一個軟提交(softcommit)功能,而硬提交功能(hardcommit)多了一個參數 -openSearcher。通常,軟提交和硬提交的作用很容易混淆,尤其是它們對於事務日志(transation log)的意義。這兩個功能的作用,雖然 solrconfig.xml 模板里面有提到,但是通常舉例說明都有局限性,如果要完全說明白 solrconfig 的所有的選項,起碼 10M 的文檔才能說得明白,而且沒有人會讀完整個文檔去弄明白所有的東西。因此,這篇文章更詳細地闡述一下硬提交、軟提交和 openSearcher 參數的效果。

准則

請記住,“硬提交是關於持久化的,軟提交是關於可見性的”。硬提交和軟提交是相關的概念,但是它們的目的是不一樣的。這句話隱含了很多細節,我們將就其中一些進行闡明。首先是幾個定義:

  • Transaction Log(Tlog): 記錄了原始文檔,用於索引恢復功能。在 SolrCloud 中,每個節點都有自己的 tlog。在更新的時候,整個文檔會寫入 tlog 中。在原子更新(Atomic update)時,仍然是整個文檔寫進來,包括了從老文檔中讀取出來的內容,換言之,原子更新時,寫到 tlog 的不是增量數據。Tlog 是保證一致性的關鍵,有了它,就算索引段(segment)關閉前 JVM 崩潰了,索引也不會丟失。

    • 注意:一旦服務器沒有正常關閉,則重新啟動時,tlog 會進行回放。因此,如果你的 tlog 很大(我們見過 GB 級別的 tlog),則重啟會非常慢,例如幾個小時才啟動成功。
  • Hard commit : 硬提交通過 solrconfig.xml 的選項來實現,或者客戶端顯式調用。硬提交會結束當前索引段的構建,並開啟新的索引段的構建。

  • openSearcher:選項的子屬性,用來控制新提交的數據是否能被后來的搜索操作檢索到(是否可見)。

  • Soft commit:軟提交是比硬提交(openSearcher=true)使文檔可見的更輕量級的操作,而且軟提交不會結束當前索引段的構建。

    • 重要:雖然軟提交是輕量級的操作,但是也不是完全沒有代價的。你應該使軟提交的時間間隔盡可能長來保證更好的性能。
  • fsynch:底層 IO 命令,當 fsynch 調用返回后,數據必定已寫到了磁盤中。這個和 java 程序的 flush 是不一樣的。java 的 flush 只是保證已經向操作系統提交了數據,操作系統並沒有立刻寫到磁盤中,而是在適當的時候才會真正寫入磁盤。

  • flush:java 程序把數據提交給操作系統。這個操作返回后,數據並沒有真正落盤,如果操作系統崩潰了,數據有可能會丟失掉。

    • 請注意,特別是在 solrcloud,多於一個副本的情況下,所有副本同時掛掉,並且數據都沒有落盤,才會發生數據丟失,這種情況是很少見的。

    • 操作系統在 flush 命令后大概 10-50 毫秒就會把數據寫入磁盤。如果 jvm 崩潰了,操作系統仍然會把數據寫到磁盤,但是,如果是操作系統崩潰,而 IO 子系統又沒來得及把數據刷到磁盤,則會丟失數據。這通常不是你需要關注的,只有當你需要絕對確保沒有數據丟失時,這才很重要。

Transaction Logs

事務日志是 solr4 中數據完整性的保證,但也引入了很多的麻煩,我們詳細聊一下。索引構建的流程如下:

  • 寫入的數據被一個節點接收,然后轉交到正確的 leader 節點。

  • 從那個 leader 節點發送到所有相關分片的所有副本。

  • 所有副本索引完后回應 leader 節點。

  • leader 節點回應一開始的接收節點。

  • 當所有的 leader 節點都回應之后,接收節點回應客戶端,在這個點上,所有的數據都已經 flush 到了集群中的所有相關節點的 tlog 中

  • 如果 jvm 崩潰了,文檔也已經安全地寫到了 tlog 中,但是,如果是操作系統奔潰,那就不一定了。

    • 如果 jvm 崩潰(或者 killed -9 殺掉),然后重啟,tlog 會回放。

    • 你可以修改 solrconfig.xml 里面的配置,在返回前用 fsynch 而不是 flush,但這樣是沒有必要的。所有 leaders 和 replicas 同時因為硬件掛掉而丟失數據的幾率是很小的。有些場景,就算存在細微的幾率丟失數據也是不允許的,則可以采用這種犧牲吞吐量的方式。

注意:tlog 文件會在 hard commit(不管 openSearcher 是 true 還是 false)時滾動(rolled over)。老的 tlog 文件會關閉,而打開一個新的 tlog 文件。保留足夠的 tlog 來存放 100 個文檔,然后其他 tlog 會刪除掉。假設你每批 25 個文檔來建索引,每批完成后執行 hard commit。這樣,任何時候你都會保持 5 個 tlog 文件,最老的 4 個每個包括 25 個文檔,共 100 個,加上當前的 tlog。當當前 tlog 關閉后,最老的那個就會刪除掉,而一個新的 tlog 文件會打開。需要特別注意的是,solr 不會嘗試只把 100 個文檔存入特定的 tlog。只有你告訴 solr 要滾動了,它才會滾動,比如發出 commit 命令或 autoCommit 發生了。所以,在大量寫入的情況下,比如 1000 個文檔每秒,而你一個小時沒有 commit,則單個 tlog 文件就包含了 3,600,000 個文檔。如果 solr 發生了意外關閉,則重啟后,這個 tlog 就會全部 replay,完成后才能提供搜索服務,這可能需要幾個小時的時間。而且,你可能沒有那么大的耐心來等待,覺得可能哪里出了問題了,然后又重啟,這個 tlog 又重頭 replay。就是這樣,如果你有很大的 tlog,則肯定是有問題的,你需要修改你的 hard commit 配置。這個坑對於從 3.x 過來的人更容易踩到,3.x 的時代,hard commit 一般都設置得比較長,因為,那時候還沒有 openSearcher=false 這個選項,hard commit 代價是昂貴的。

Soft commit

Soft commit 是和可見性有關的,hard commit 是和持久性有關的。對於 soft commit 的理解是,它能使文檔可見,但是會有一些代價。尤其是在 solrconfig.xml 里定義的頂層的 cache(filterCache、queryResultCache 等)會失效,autowarning 會在頂層 cache 發生(比如 filterCache、queryResultCache)。這時候,newSearcher 的查詢都會被執行,而且,fieldvaluecache 也會失效,因此,facet 查詢也不得不等 cache 重新生成。在頻繁的 soft commit 下,cache 基本上沒什么效果,在某些場景下,最好去掉它。然而,索引段級別的 cache(譯者注:比如 fieldcache),用於 function 查詢,排序等,是基於索引段的,因此不會因為 soft commit 而失效,它們能繼續被使用。

那么這意味着什么呢?

假設一個 softcommit 被執行了,則:

  • tlog 不會被截斷,它會繼續增長。

  • 新增的文檔會可見。

  • 某些 cache 必須重新加載。

  • 頂層的 cache 會失效。

  • autowarming 會被觸發。

  • 新的索引段會生成。

注意,我沒有說任何關於索引段的事情,那是 hardcommit 做的。再次重申,soft commit 比 hard commit(openSearcher=true)代價小,但是並不是完全沒有代價的,正如格言所說的“天下沒有免費的午餐”。soft commit 用來支持近實時搜索,但是是有代價的,因此,設置 soft commit 的時間間隔盡可能長,來獲取更好的性能。

Hard commit

hard commit 是有關持久化的,softcommit 是有關可見性的。這里,還要分兩種情況,openSearcher=true 和 openSearcher=false。首先,我會解析一下這兩種情況下都會發生的事情。不管 openSearcher=true 還是 openSearcher=false,都會出現以下的結果:

  • tlog 會截斷:當前 tlog 會關閉,一個新的 tlog 會開始,在已關閉的 tlog 中,如果較新的 tlog 超過了 100 個文檔,則老的 tlog 會刪除掉。

  • 當前正在索引的索引段會關閉,並 flush。

  • 可能會觸發后台的段合並。

這些就是 hardcommit 一定會發生的事情,無論 openSearcher 怎樣設置。

  • openSearcher=true:Solr/Lucene searchers 被重新打開,所有的 cache 都失效(譯者注:索引段級別的 cache 不會失效),autowarming 會執行。這是老版本唯一能看到新增加的文檔的方法。

  • openSearcher=false:除了以上四點以外沒有其他動作了。如果要搜索新的文檔,需要執行一次 soft commit。

Recovery

我上面說了持久化的問題,那么我們再來深入探討下。當機器宕機,jvm 崩潰,無論怎樣,你的集群的狀態是這樣的。

  • 最后返回成功的更新調用已經將你的文檔寫到了集群中的 tlog,默認是你的 tlog 已經 flush,但是沒有 fsync‘d,我們之前已經提到過,你可以修改這個默認行為,但是不推薦這樣做。

  • 當重啟機器,它會聯系 leader 節點,然后會執行其中一個恢復動作

    • 如果 leader 節點接收到小於等於 100 個文檔,則會從它自己的 tlog 回放文檔(譯者注:缺失的文檔會從 leader 的 tlog 同步過來)。注意,在回放的過程中,新進來的文檔會寫到 tlog 的末尾,它們也會回放。

    • 如果從節點下線到現在,leader 節點接收了大於 100 個文檔,則會采用傳統的同步方式從 leader 節點同步整個索引。

恢復是需要一定的時間的,這是人們在使用 solrcloud 經常遇到的坑。他們會做各種實驗,各種地方關閉、啟動服務,用 kill -9 命令殺 solr 進程等。一方面,它是好的,演練了 solrcloud 的恢復過程。另一方面,它又沒有什么效果,因為這是需要高度依賴人的經驗的。如果你的某些節點一天中消失好多次,那么你應該去修復它,這個比 solr 恢復時間較長的問題要嚴重得多了。

建議

說到建議,我常常覺得很為難,因為在某些場景下,任何建議都是錯的。我首先建議的是不要把問題想的過了。一些聰明的人會更可靠地進行調優。先嘗試一些簡單的調整,只調整一些必要的配置。尤其是,先看一下 tlog 的大小,調整一下 hard commit 時間間隔大小,使 tlog 的大小比較合理。記住,如果 jvm 崩潰了,最常見的后果是 tlog 回放時間較長。15 分鍾能忍受嗎?如果不能,那么為什么不設置得小一些呢。我們見過 hard commit 比 soft commit 時間間隔小得多的設置,參考下面提到的大批量索引構建。

優雅地關閉 solr,換句話說,在索引構建的過程中,“kill -9”只會自找麻煩。

優雅地關閉,意味着:

  • 停止寫入新的文檔。

  • 發送一個 hardcommit 命令或等待 autoCommit 時間間隔過期。

  • 停止 solr 服務。

    你可以調整一些配置,以適合你的場景。

大批量索引構建

假設你希望把大批量的數據盡可能快地寫入系統,將來用於搜索。比如,數據源的初始化。

  • 設置 soft commit 時間間隔足夠長,比如 10 分鍾或更長(配置為 -1 則不自動 soft commit)。soft commit 是有關可見性的,我想大批量索引構建應該不是為了滿足實時搜索的,所以沒必要額外地打開任何類型的 searcher。

  • 設置 hard commit 時間間隔為 15 秒,openSearcher=false。重申一下,這里假設你只是為了把大量數據導入 solr,而不是為了實時搜索。這樣設置,就是最壞的情況也只是當你重啟,你最多只需要從 tlog 回放 15 秒的數據。如果你的系統頻繁重啟,則先找到頻繁重啟的原因。

  • 只有當你已經嘗試了簡單的方案而沒有解決問題,你才需要考慮進一步的改進方案,一般是一些不常見的做法,它們包括:

     
     + 在批量索引時完全關閉tlog。 + 離線構建索引,比如mapreduce方式構建索引。 + 在構建索引時,每個分片只有一個leader節點,沒有副本,構建完成后,再開啟副本,讓它們進行傳統的復制來保持一致。注意,這個是自動實現的,如果副本發現和leader相差太遠,就會觸發傳統的復制。復制完成后,它會繼續接受leader節點的文檔,並保存到自己的tlog中。 + 諸如此類

索引更新很頻繁,檢索請求量很少

比如,日志檢索。這個場景下,每天有大量的日志要寫進來,但是檢索請求卻很少,主要用作故障排除和日志分析。

  • 設置 soft commit 時間間隔足夠長,設置為你能忍受新文檔不可見的最長時間。這可能是幾分鍾或更長。甚至幾個小時,直到執行一次 hard commit(openSearcher=true)或 soft commit。

  • 設置 hard commit(openSearcher=false)的時間間隔為 15 秒。

索引更新不頻繁,檢索請求量小或大

這是相對靜止的索引,但時不時有一些更新操作。比如說 5-10 分鍾有一個更新操作。

  • 除非近實時搜索是必需的功能,在這種場景下,我會去掉 soft commit,每 5 分鍾提交一次 hard commit(openSearcher=true)。如果你是采用外部單線程來構建索引,由客戶端來提交 hard commit 可能更合理。

索引更新很頻繁,檢索請求量大

這是近實時搜索的場景,是最復雜的場景,這需要有較多的經驗,我是這樣做的

  • 設置 soft commit 的時間間隔為你能忍受的最大長度。不要聽信你的產品經理的話“我需要不超過 1 秒鍾的延遲”。時間間隔從長到短,逐漸嘗試,看看用戶服務是否滿足,是否用戶注意到了延遲,直到找到一個合適的值。soft commit 和近實時搜索非常好用,但是並非沒有代價的。

  • 設置 hardcommit 的時間間隔為 15 秒。

Solrj 和 http 和客戶端索引

一般來說,所有的配置選項也能通過 solrj 和 http 實現。 Late edit說過,“從客戶端進行提交要特別小心,實際上,最好不要這樣做”。一般來說,客戶端索引時不要發送提交命令到 solr,這樣做經常會犯錯,尤其是你有多個客戶端同時進行索引的時候。提交命令並發地發送過來,並發地執行,你很可能會看到這樣的警告“too many warming searchers”,或者你會看到無數的小段。還是在 solrconfig.xml 中配置自動提交(hard commit 或 soft commit)來控制提交頻率吧。如果你一定要控制可見性,你想索引后馬上能看到新的文檔,而無法忍受等待自動提交觸發。那么,只在最后執行一次就好了。實際上,只在只有一個客戶端的情況下,我才會自己來提交。否則,我會在索引全部完成,我才手工提交一次,像這樣

http://host:port/solr/collection/update?commit=true

你也可以用 solrj,在添加索引的時候,設置 commitWithin 參數,單位是毫秒。這種方式,無論多少客戶端都沒問題的。服務端 timer 在接受到第一個帶有 commitWithin 參數的更新時啟動,經過 commitWithin 時間之后,任何客戶端發送的所有的文檔都會提交掉,無論那些文檔是否包含了 commitWithin 參數。下一個帶有 commitWithin 參數的更新又會啟動一個新的 timer。最后記住,優化索引(optimzing)是一般來說是沒有必要的。

英文鏈接
https://lucidworks.com/2013/08/23/understanding-transaction-logs-softcommit-and-commit-in-sorlcloud/

 

 

 

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM