在ES的生產實踐中,往往會遇到以下問題:
根據業務需求,存在以下場景:
如果是第壹種場景,數據遷移過程中可以停止寫入,可以采用諸如elasticsearch-dump、logstash、reindex、snapshot等方式進行數據遷移。實際上這幾種工具大體上可以分為兩類:
如果是第二種場景,數據遷移過程中舊集群不能停止寫入,需要根據實際的業務場景解決數據壹致性的問題:
下面介紹壹下在舊集群可以停止寫入的情況下進行數據遷移的幾種工具的用法。
elasticsearch-dump是壹款開源的ES數據遷移工具,github地址: /taskrabbit/elasticsearch-dump
以下操作通過elasticdump命令將集群x.x.x.1中的companydatabase索引遷移至集群x.x.x.2。註意第壹條命令先將索引的settings先遷移,如果直接遷移mapping或者data將失去原有集群中索引的配置信息如分片數量和副本數量等,當然也可以直接在目標集群中將索引創建完畢後再同步mapping與data
logstash支持從壹個ES集群中讀取數據然後寫入到另壹個ES集群,因此可以使用logstash進行數據遷移,具體的配置文件如下:
上述配置文件將源ES集群的所有索引同步到目標集群中,當然可以設置只同步指定的索引,logstash的更多功能可查閱logstash官方文檔 logstash 官方文檔 .
reindex是Elasticsearch提供的壹個api接口,可以把數據從壹個集群遷移到另外壹個集群。
snapshot api是Elasticsearch用於對數據進行備份和恢復的壹組api接口,可以通過snapshot api進行跨集群的數據遷移,原理就是從源ES集群創建數據快照,然後在目標ES集群中進行恢復。需要註意ES的版本問題:
如果舊集群不能停止寫入,此時進行在線數據遷移,需要保證新舊集群的數據壹致性。目前看來,除了官方提供的CCR功能,沒有成熟的可以嚴格保證數據壹致性的在線數據遷移方法。此時可以從業務場景出發,根據業務寫入數據的特點選擇合適的數據遷移方案。
壹般來說,業務寫入數據的特點有以下幾種:
下面來具體分析不同的寫入數據的特點下,該如何選擇合適的數據遷移方式。
在日誌或者APM的場景中,數據都是時序數據,壹般索引也都是按天創建的,當天的數據只會寫入當前的索引中。此時,可以先把存量的不再寫入的索引數據壹次性同步到新集群中,然後使用logstash或者其它工具增量同步當天的索引,待數據追平後,把業務對ES的訪問切換到新集群中。
具體的實現方案為:
add only的數據寫入方式,可以按照數據寫入的順序(根據_doc進行排序,如果有時間戳字段也可以根據時間戳排序)批量從舊集群中拉取數據,然後再批量寫入新集群中;可以通過寫程序,使用用scroll api 或者search_after參數批量拉取增量數據,再使用bulk api批量寫入。
使用scroll拉取增量數據:
上述操作可以每分鐘執行壹次,拉起前壹分鐘新產生的數據,所以數據在舊集群和新集群的同步延遲為壹分鐘。
使用search_after批量拉取增量數據:
上述操作可以根據需要自定義事件間隔執行,每次執行時修改search_after參數的值,獲取指定值之後的多條數據;search_after實際上相當於壹個遊標,每執行壹次向前推進,從而獲取到最新的數據。
使用scroll和search_after的區別是:
另外,如果不想通過寫程序遷移舊集群的增量數據到新集群的話,可以使用logstash結合scroll進行增量數據的遷移,可參考的配置文件如下:
使用過程中可以根據實際業務的需求調整定時任務參數schedule以及scroll相關的參數。
業務場景如果是寫入ES時既有追加,又有存量數據的更新,此時比較重要的是怎麽解決update操作的數據同步問題。對於新增的數據,可以采用上述介紹的增量遷移熱索引的方式同步到新集群中。對於更新的數據,此時如果索引有類似於updateTime的字段用於標記數據更新的時間,則可以通過寫程序或者logstash,使用scroll api根據updateTime字段批量拉取更新的增量數據,然後再寫入到新的集群中。
可參考的logstash配置文件如下:
實際應用各種,同步新增(add)的數據和更新(update)的數據可以同時進行。但是如果索引中沒有類似updateTime之類的字段可以標識出哪些數據是更新過的,目前看來並沒有較好的同步方式,可以采用CCR來保證舊集群和新集群的數據壹致性。
如果業務寫入ES時既有新增(add)數據,又有更新(update)和刪除(delete)數據,可以采用6.5之後商業版X-pack插件中的CCR功能進行數據遷移。但是使用CCR有壹些限制,必須要註意:
具體的使用方式如下:
如果業務是通過中間件如kafka把數據寫入到ES, 則可以使用如下圖中的方式,使用logstash消費kafka的數據到新集群中,在舊集群和新集群數據完全追平之後,可以切換到新集群進行業務的查詢,之後再對舊的集群下線處理。
使用中間件進行同步雙寫的優點是:
當然,雙寫也可以使用其他的方式解決,比如自建proxy,業務寫入時向proxy寫入,proxy把請求轉發到壹個或者多個集群中,但是這種方式存在以下問題:
隨著業務規模的增長,業務側對使用的ES集群的數據可靠性、集群穩定性等方面的要求越來越高,所以要比較好的集群容災方案支持業務側的需求。
如果是公司在自建IDC機房內,通過物理機自己搭建的ES集群,在解決跨機房容災的時候,往往會在兩個機房 部署兩個ES集群,壹主壹備,然後解決解決數據同步的問題;數據同步壹般有兩種方式,壹種方式雙寫,由業務側實現雙寫保證數據壹致性,但是雙寫對業務側是壹個挑戰,需要保證數據在兩個集群都寫成功才能算成功。另外壹種方式是異步復制,業務側只寫主集群,後臺再把數據同步到備集群中去,但是比較難以保證數據壹致性。第三種方式是通過專線打通兩個機房,實現跨機房部署,但是成本較高。
因為數據同步的復雜性,雲廠商在實現ES集群跨機房容災的時候,往往都是通過只部署壹個集群解決,利用ES自身的能力同步數據。國外某雲廠商實現跨機房部署ES集群的特點1是不強制使用專用主節點,如上圖中的壹個集群,只有兩個節點,既作為數據節點也作為候選主節點;主分片和副本分片分布在兩個可用區中,因為有副本分片的存在,可用區1掛掉之後集群仍然可用,但是如果兩個可用區之間網絡中斷時,會出現腦裂的問題。如下圖中使用三個專用主節點,就不會存在腦裂的問題了。
但是如果壹個地域沒有三個可用區怎麽辦呢,那就只能在其中壹個可用區中放置兩個專用主節點了,如國內某雲廠商的解決方案:
但是重建節點的過程還是存在問題的,如上圖中,集群本身的quorum應該為2,可用區1掛掉後,集群中只剩壹個專用主節點,需要把quorum參數(discovery.zen.minimum_master_nodes)調整為1後集群才能夠正常進行選主,等掛掉的兩個專用主節點恢復之後,需要再把quorum參數(discovery.zen.minimum_master_nodes)調整為2,以避免腦裂的發生。
當然還是有可以把無法選主和腦裂這兩個可能發生的問題規避掉的解決方案,如下圖中國內某雲廠商的解決思路:
創建雙可用區集群時,必須選擇3個或者5個專用主節點,後臺會在壹個隱藏的可用區中只部署專用主節點;方案的優點1是如果壹個可用區掛掉,集群仍然能夠正常選主,避免了因為不滿足quorum法定票數而無法選主的情況;2是因為必須要選擇三個或5個專用主節點,也避免了腦裂。
想比較壹主壹備兩個集群進行跨機房容災的方式,雲廠商通過跨機房部署集群把原本比較復雜的主備數據同步問題解決了,但是,比較讓人擔心的是,機房或者可用區之間的網絡延遲是否會造成集群性能下降。這裏針對騰訊雲的雙可用區集群,使用標準的benchmark工具對兩個同規格的單可用區和雙可用區集群進行了壓測,壓測結果如下圖所示:
從壓測結果的查詢延時和寫入延時指標來看,兩種類型的集群並沒有明顯的差異,這主要得益與雲上底層網絡基礎設施的完善,可用區之間的網絡延遲很低。
類似於同城跨機房容災,異地容災壹般的解決思路是在異地兩個機房部署壹主壹備兩個集群。業務寫入時只寫主集群,再異步地把數據同步到備集群中,但是實現起來會比較復雜,因為要解決主備集群數據壹致性的問題,並且跨地域的話,網絡延遲會比較高;還有就是,當主集群掛掉之後,這時候切換到備集群,可能兩邊數據還沒有追平,出現不壹致,導致業務受損。當然,可以借助於kafka等中間件實現雙寫,但是數據鏈路增加了,寫入延遲也增加了,並且kafka出現問題,故障可能就是災難性的了。
壹種比較常見的異步復制方法是,使用snapshot備份功能,定期比如每個小時在主集群中執行壹次備份,然後在備集群中進行恢復,但是主備集群會有壹個小時的數據延遲。以騰訊雲為例,騰訊雲的ES集群支持把數據備份到對象存儲COS中,因為可以用來實現主備集群的數據同步,具體的操作步驟可以參考 /document/product/845/19549 。
在6.5版本官方推出了CCR功能之後,集群間數據同步的難題就迎刃而解了。可以利用CCR來實現ES集群的異地容災:
CCR是類似於數據訂閱的方式,主集群為Leader, 備集群為Follower, 備集群以pull的方式從主集群拉取數據和寫請求;在定義好Follwer Index時,Follwer Index會進行初始化,從Leader中以snapshot的方式把底層的segment文件全量同步過來,初始化完成之後,再拉取寫請求,拉取完寫請求後,Follwer側進行重放,完成數據的同步。CCR的優點當然是因為可以同步UPDATE/DELETE操作,數據壹致性問題解決了,同步延時也減小了。
另外,基於CCR可以和前面提到的跨機房容災的集群結合,實現兩地多中心的ES集群。在上海地域,部署有多可用區集群實現跨機房的高可用,同時在北京地域部署備集群作為Follwer利用CCR同步數據,從而在集群可用性上又向前走了壹步,既實現了同城跨機房容災,又實現了跨地域容災。
但是在出現故障時需要把集群的訪問從上海切換到北京時,會有壹些限制,因為CCR中的Follwer Index是只讀的,不能寫入,需要切換為正常的索引才能進行寫入,過程也是不可逆的。不過在業務側進行規避,比如寫入時使用新的正常的索引,業務使用別名進行查詢,當上海地域恢復時,再反向的把數據同步回去。
現在問題就是保證上海地域集群數據的完整性,在上海地域恢復後,可以在上海地域新建壹個Follower Index,以北京地域正在進行寫的索引為Leader同步數據,待數據完全追平後,再切換到上海地域進行讀寫,註意切換到需要新建Leader索引寫入數據。
數據同步過程如下所示:
1.上海主集群正常提供服務,北京備集群從主集群Follow數據
2.上海主集群故障,業務切換到北京備集群進行讀寫,上海主集群恢復後從北京集群Follow數據