<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Elasticsearch學習筆記(二)單節點準實時索引的實現 ## 為什么要學習架構? Elasticsearch的一些架構設計,對我們做性能調優、故障處理,具有非常重要的影響。下面將從Elasticsearch 的準實時索引的實現、自動發現、rounting和replica的讀寫過程,shard的allocate控制 ## 使文本可以被搜索? 在傳統的數據庫中,一個字段存一個值,但是這對于全文搜索是不足的。想要讓文本中的而每個單詞都可以 被搜索,這意味著數據庫需要多個值。 支持一個字段多個值的最佳數據結構是倒排索引。倒排索引包含了出現在所有文檔中唯一的值或或詞的有序列 表,以及每個詞所屬的文檔列表。 ![](https://box.kancloud.cn/2016-03-10_56e11d242e8ce.jpg) 倒排索引存儲了比包含一個term的文檔列表多地多的信息,它可能包含每一個term的文檔數量,一個term出現 在制定文檔中的頻次,每個文檔中term的順序,每個文檔的長度,所有文檔的平均長度等等。這些統計信息使 Elasticsearch知道哪些term更重要,哪些文檔更重要,也就是相關性。 在全文搜索的早些時候,會為整個文檔集合建立一個大索引,并且寫入磁盤。只有新索引準備好了它就會替代 舊的索引,最近的修改可以被檢索。 **不可變性** 寫入磁盤的倒排索引是不可變的,它有如下好處: - 不需要鎖。如果從來不需要跟新一個索引,就不必擔心多個程序見同時嘗試修改。 - 一旦索引被讀入文件系統的緩存,它就一直在那兒,因為不會改變。只要文件系統緩存有足夠的空 間,大部分的讀會直接訪問內存而不是磁盤。這有助于性能的提升。 - 在索引的聲明周期內,所有的其他緩存都可用。他們不需要再每次數據變化了都重建,因此數據不會變。 - 寫入單個大的倒排索引,可以壓縮數據,較少的磁盤IO和需要緩存索引的大小。 當然,不可變的索引有它的缺點,首先是它不可變。如果想要搜索一個新文檔,必須重建整個索引。這不僅限 制了一個索引所能裝下的數據,還有一個索引可以被更新的頻次。 ## 準實時索引的實現? 本文主要介紹Elasticsearch的準實時索引的實現,至于基于Lucene的倒排索引將不在這里介紹,有興趣的讀者 可以去Lucene的相關文章,或者閱讀《Lucene in Action》等書籍。下面將介紹Elasticsearch索引流程中發生的 具體操作,重點在于其中的segment、buffer和translog三部分對性能方面的影響。 ### 1、動態更新的Lucene索引 要做到實時跟新條件下數據的可用和可靠,就需要在倒排索引的基礎上,再做一系列更高級的處理。 總結一下Lucene的處理辦法:新收到的數據寫入新的索引文件里。 Lucene把每次生成的倒排索引,叫做一個段(segment)。然后另外使用一個commit文件,記錄索引內的所有 segment。而生成segment的數據來源,則是內存中的buffer,也就是說,動態跟新過后過程如下: 1)當前磁盤上有三個segement可用,同時有一個commit文件記錄當前的segment 2)新收到的數據進入內存buffer,索引狀態如下所示。 3)buffer刷到磁盤,生成一個新的segment,commit文件同步跟新。 這樣可以完成跟新,也產生了幾個問題:1、每次一有數據就刷新到磁盤,會增大對磁盤的操作2、刷新到磁盤的 時間占據很大一部分時間3、如果刷新的過程中刷新失敗應該怎么控制呢? ![](https://box.kancloud.cn/2016-03-10_56e11d243e39f.jpg) ![](https://box.kancloud.cn/2016-03-10_56e11d2453c90.jpg) ![](https://box.kancloud.cn/2016-03-10_56e11d2467956.jpg) ### 2、刪除和更新 segment是不可變的,所以文檔即不能從舊的段中刪除,舊的段也不能更新以反映文檔最新的文本。相反,每 一個提交點包括一個.del文件,包含了段上已經被刪除的文檔 當一個文檔被刪除,它是實際上只是在.del文件中被標記刪除,亦然可以匹配查詢,但最終返回之前會被從結果 中刪除。 文檔的跟新操作是類似的:當一個文檔被更新,舊版本的文檔被標記為刪除,新版本的文檔在新的段中索引。也 許該文檔的不同版本都會匹配一個查詢,但是老版本會從結果中刪除。 ### 3、利用磁盤緩存實現的準實時檢索 既然涉及到磁盤,那么一個不可避免的問題就來了:磁盤太慢了!對我們要求的實時性很高的服務來說,這種處 理還不夠。所以,在剛剛第3步的處理中,還有一個中間狀態: 1)內存buffer生成一個新的segment,刷到文件系統緩存中,Lucene即可檢索到這個新的segment,索引狀態如 圖所示。 2)文件系統緩存真正同步到磁盤上,commit文件跟新。 刷到文件系統緩存中這個步驟,Elasticsearch默認1s的時間間隔,這也就是說相當于是實時搜索的,Elasticsearch 也提供了單獨的/_reflush接口,用戶如果對1s間隔還是不太滿意,可以主動調用接口來保證搜索可見。 reflush API ~~~ POST /_refresh <1> POST /blogs/_refresh <2> ~~~ - <1> refresh所有索引 - <2> 只refresh 索引`blogs` 一般來說我們會通過/_settings接口或者定制template的方式,加大refresh_interval參數: ~~~ PUT /my_logs/_settings { "refresh_interval": -1 } <1> PUT /my_logs/_settings { "refresh_interval": "1s" } <2> ~~~ - <1> 禁用所有自動refresh - <2> 每秒自動refresh ### 4、translog提供的磁盤同步控制 既然refresh只是寫到文件系統緩存中,那么最后一步寫到實際磁盤又是由什么來控制的呢?如果這期間發生 主機錯誤、硬盤故障等異常情況,數據會不會丟失? 這里,其實Elasticsearch提供了另一個機制來控制。Elasticsearch也把數據寫入到內存buffer的同時, 其實還另外記錄了一個treanslog的日志。也就是說,在內存數據進入到buffer這一步驟時,其實還另外記錄 了一個translog記錄。如圖所示 1.當一個文檔被索引,它被加入到內存緩存,同時加到事務日志。 **圖1:新的文檔加入到內存緩存,同時寫入事務日志** ![](https://box.kancloud.cn/2016-03-10_56e11d2477b86.jpg) 2.refersh使得分片進入下圖描述的狀態。每個分片都進行refresh - 內存緩沖區的文檔寫入到segment中,但是還沒有同步到磁盤。 - segment被打開,使得新的文檔可以搜索。 - 緩存被清空 - 但是事務日志沒變化 圖2:經過一次refresh,緩存被清除,但事務日志沒有 ![](https://box.kancloud.cn/2016-03-10_56e11d2490b7e.jpg) 3、隨著更多的文檔加入到緩存區,寫入日志 圖3:事務日志會記錄增長的文檔 ?![](https://box.kancloud.cn/2016-03-10_56e11d24abef4.jpg) 4、假如在這期間發生異常,Elasticsearch會從commit位置開始,恢復整個translog文件中的記錄,保護**數據的一致性**。 等到真正把segement刷到磁盤,且commit文件被清空的時候,translog文件才清空,這一步叫flush,同樣地,Elasticsearch提供了 /_flush接口。 - 內存緩存區的所有文檔會寫入到新段中, - 清楚緩存 - 一個提交點寫入到硬盤中 - 文件系統緩存通過gsync操作flush到硬盤 - 事務日志被清除 事務日志記錄了沒有flush到硬盤的所有操作。當故障重啟后,ES會用最近一次提交點從硬盤恢復所有已知的段,并且從日志里恢復所有的操作。 事務日志還用來提供實時的CRUD操作。當年用ID進行CRUD時,它在檢索相關段內的文檔前會首先檢查日志最新的改動。這意味著ES可以實時地獲取文檔的最新版本。 圖4:flush過后,段被全提交,事務日志清除 ![](https://box.kancloud.cn/2016-03-10_56e11d24c6a04.jpg) 在ES中,進行一次提交并刪除事務日志的操作叫做?`flush`。分片每30分鐘,或事務日志過大會進行一次flush操作。 對于flush操作,Elasticsearch的操作默認設置為:每30分鐘主動進行一次flush,或懂translog文件大于512M,主動進行一次flush,這兩個行為可以通過 分別設置index.translog.flush_threshold_period和index.translog.flush_threslog_size參數修改 **flush API** 當然也可以手動進行flush ~~~ POST /blogs/_flush <1> POST /_flush?wait_for_ongoing <2> ~~~ - <1> flush索引`blogs` - <2> flush所有索引,等待操作結束再返回 ### 5、translog的一致性 索引數據的一致性通過translog保證。那么translog文件自己呢? 默認情況下,Elasticsearch每5秒就會強制刷新到translog日志到磁盤上,所以,如果數據沒有副本,然后又發生故障,確實有可能丟失5秒數據,可以通過設置 index.gateway.local.sync設置,然后重啟Elasticsearch 前面一直在講的是Lucene的索引,Elasticsearch在這個基礎上,做了一些改動,Elasticsearch的索引是分片的集合,而分片就相當于Lucene的索引。 ### 6、segement merge的影響 上面提到Lucene思想:新收到的數據寫入到新的索引文件里面,每一個索引文件都是不可變的,開新文件就會給服務器帶來負載壓力因為默認每1秒鐘就會有一個新文件產生,每個文件都需要文件句柄、內存、cpu等各種資源,給服務器帶來很大的開銷 為了解決這個問題,Elasticsearch會不斷地在后臺運行任務,主動將這些零散地segement做數據歸并,盡量讓索引中只保有少量的,每個都比較大的segement。 這個過程是由獨立的線程來進行的,并不影響segment的產生。歸并過程中,刪除之間幾個小的segment,改成新的大的segment。等檢索請求都從小segement轉到大的segement上以后,刪除沒用的小segement。 圖1:兩個提交的段和一個未提交的段合并為了一個更大的段? ![](https://box.kancloud.cn/2016-03-10_56e11d24e9f77.jpg) 圖2:段合并完后,舊的段被刪除? ![](https://box.kancloud.cn/2016-03-10_56e11d250820f.jpg) - 新的段flush到了硬盤。 - 新的段寫入commit文件,排除舊的段。 - 新的段打開供搜索。 - 舊的段被刪除 ### 歸并線程設置 segment歸并的過程,需要先讀取segment,歸并計算,再寫一遍segment,最后還要保證刷到磁盤,可以說,這是一個非常消耗磁盤I/O 的任務。 默認情況下,歸并線程的限速設置indices.store.throttle.max_bytes_per_sec是20MB。對于寫入量較大,磁盤轉速較高,甚至使用SSD盤的服務器來說,這個限速明顯是過低的。對于EIK應用來說,建議可以適當跳大 ~~~ curl -XPUT 'http://localhost:9200/_cluster/settings' -d ' { "persistent" : { "indices.store.throttle.max_bytes_per_sec" : "100mb" } }' ~~~ 歸并策略 歸并線程是按照一定的歸并策略來挑選segment進行歸并的。 index.merge.policy.floor_segment默認2MB,小于這個大小的segment,優先被歸并 index.merge.policy.max_merge_at_once默認一次最多歸并10個segment index.merge.policy.max_merge_at_once_explicit默認optimize時一次最多歸并30個segment index.merge.policy.max_merge_segment默認5GB,大于這個大小的segment.不用參與歸并,optimize除外 根據這些策略,其我們也可以從另一個角度考慮如何減少segment歸并的線程以及提高效應的辦法:加大reflush間隔, 盡量讓每次新生成的segment本身大小就很大。 **optimize API** optmize API最好描述為強制合并段API。它強制合并段以達到指定max_num_segments參數。這是為了減少段的數量 (通常為1)達到提高搜索性能的目的。 `POST /logstash-2014-10/_optimize?max_num_segments=1 <1>` <1> 把索引中的每個分片都合并成一個段 由于optimize線程對資源的消耗比普通的歸并線程大得多,索引,絕對不建議對還在寫入數據的熱索引執行這個操作,這個問題 對于ELK stack來說很好辦,一般索引都是按天分割的。 本文介紹的是單節點準實時索引介紹到這里,考慮到篇幅的問題,將會在下篇介紹Elasticsearch的集群分片解決方案。 [**http://blog.csdn.net/u010994304/article/details/50441419**](http://blog.csdn.net/u010994304/article/details/50441419)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看