Elasticsearch數(shù)據(jù)遷移與集群容災(zāi)

本文討論如何跨集群遷移ES數(shù)據(jù)以及如何實(shí)現(xiàn)ES的同城跨機(jī)房容災(zāi)和異地容災(zāi)。

跨集群數(shù)據(jù)遷移

在ES的生產(chǎn)實(shí)踐中,往往會(huì)遇到以下問(wèn)題:

  • 一個(gè)運(yùn)行了較長(zhǎng)時(shí)間的ES集群,因?yàn)槲锢碓O(shè)備老化,需要把數(shù)據(jù)遷移到一個(gè)使用新機(jī)器搭建的ES集群中
  • 業(yè)務(wù)計(jì)劃上云,要把自建的ES集群數(shù)據(jù)遷移到云廠商的ES集群中

根據(jù)業(yè)務(wù)需求,存在以下場(chǎng)景:

  • 遷移過(guò)程中,舊的集群可以暫時(shí)停止服務(wù)或者暫停寫入,數(shù)據(jù)全部遷移到新的集群中后,業(yè)務(wù)切換到新的集群進(jìn)行讀取和寫入
  • 遷移過(guò)程中,舊集群不能停止寫入,業(yè)務(wù)不能停服

如果是第一種場(chǎng)景,數(shù)據(jù)遷移過(guò)程中可以停止寫入,可以采用諸如elasticsearch-dump、logstash、reindex、snapshot等方式進(jìn)行數(shù)據(jù)遷移。實(shí)際上這幾種工具大體上可以分為兩類:

  • scroll query + bulk: 批量讀取舊集群的數(shù)據(jù)然后再批量寫入新集群,elasticsearch-dump、logstash、reindex都是采用這種方式
  • snapshot: 直接把舊集群的底層的文件進(jìn)行備份,在新的集群中恢復(fù)出來(lái),相比較scroll query + bulk的方式,snapshot的方式遷移速度最快。

如果是第二種場(chǎng)景,數(shù)據(jù)遷移過(guò)程中舊集群不能停止寫入,需要根據(jù)實(shí)際的業(yè)務(wù)場(chǎng)景解決數(shù)據(jù)一致性的問(wèn)題:

  • 如果業(yè)務(wù)不是直接寫ES, 而是把數(shù)據(jù)寫入到了中間件,比如業(yè)務(wù)->kafka->logstash->es的架構(gòu),此時(shí)可以直接采用雙寫的策略,舊集群不停止讀寫,新的集群也直接寫入,然后遷移舊集群的數(shù)據(jù)到新集群中去,等數(shù)據(jù)追平之后,新的集群再提供讀服務(wù);
  • 如果業(yè)務(wù)是直接寫ES, 并且會(huì)進(jìn)行刪除doc操作;此時(shí)可以使用ES官方在6.5版本之后的CCR(跨集群復(fù)制)功能,把舊集群作為L(zhǎng)eader, 新集群作為Follower, 舊集群不停止讀寫,新集群從舊集群中follow新寫入的數(shù)據(jù);另一方面使用第三方工具把存量的舊集群中的數(shù)據(jù)遷移到新集群中,存量數(shù)據(jù)遷移完畢后,業(yè)務(wù)再切換到新的集群進(jìn)行讀寫。

數(shù)據(jù)遷移時(shí)可以停止舊集群的寫入

下面介紹一下在舊集群可以停止寫入的情況下進(jìn)行數(shù)據(jù)遷移的幾種工具的用法。

elasticsearch-dump

elasticsearch-dump是一款開源的ES數(shù)據(jù)遷移工具,github地址: https://github.com/taskrabbit/elasticsearch-dump

  1. 安裝elasticsearch-dump

    elasticsearch-dump使用node.js開發(fā),可使用npm包管理工具直接安裝:

     npm install elasticdump -g
    
  2. 主要參數(shù)說(shuō)明

     --input: 源地址,可為ES集群URL、文件或stdin,可指定索引,格式為:{protocol}://{host}:{port}/{index}
     --input-index: 源ES集群中的索引
     --output: 目標(biāo)地址,可為ES集群地址URL、文件或stdout,可指定索引,格式為:{protocol}://{host}:{port}/{index}
     --output-index: 目標(biāo)ES集群的索引
     --type: 遷移類型,默認(rèn)為data,表明只遷移數(shù)據(jù),可選settings, analyzer, data, mapping, alias
    
  3. 遷移單個(gè)索引

以下操作通過(guò)elasticdump命令將集群x.x.x.1中的companydatabase索引遷移至集群x.x.x.2。注意第一條命令先將索引的settings先遷移,如果直接遷移mapping或者data將失去原有集群中索引的配置信息如分片數(shù)量和副本數(shù)量等,當(dāng)然也可以直接在目標(biāo)集群中將索引創(chuàng)建完畢后再同步mapping與data

    elasticdump --input=http://x.x.x.1:9200/companydatabase --output=http://x.x.x.2:9200/companydatabase --type=settings
    elasticdump --input=http://x.x.x.1:9200/companydatabase --output=http://x.x.x.2:9200/companydatabase --type=mapping
    elasticdump --input=http://x.x.x.1:9200/companydatabase --output=http://x.x.x.2:9200/companydatabase --type=data
  1. 遷移所有索引:以下操作通過(guò)elasticdump命令將將集群x.x.x.1中的所有索引遷移至集群x.x.x.2。 注意此操作并不能遷移索引的配置如分片數(shù)量和副本數(shù)量,必須對(duì)每個(gè)索引單獨(dú)進(jìn)行配置的遷移,或者直接在目標(biāo)集群中將索引創(chuàng)建完畢后再遷移數(shù)據(jù)
    elasticdump --input=http://x.x.x.1:9200 --output=http://x.x.x.2:9200

logstash

logstash支持從一個(gè)ES集群中讀取數(shù)據(jù)然后寫入到另一個(gè)ES集群,因此可以使用logstash進(jìn)行數(shù)據(jù)遷移,具體的配置文件如下:

    input {
        elasticsearch {
            hosts => ["http://x.x.x.1:9200"]
            index => "*"
            docinfo => true
        }
    }
    output {
        elasticsearch {
            hosts => ["http://x.x.x.2:9200"]
            index => "%{[@metadata][_index]}"
        }
    }

上述配置文件將源ES集群的所有索引同步到目標(biāo)集群中,當(dāng)然可以設(shè)置只同步指定的索引,logstash的更多功能可查閱logstash官方文檔 logstash 官方文檔.

reindex

reindex是Elasticsearch提供的一個(gè)api接口,可以把數(shù)據(jù)從一個(gè)集群遷移到另外一個(gè)集群。

  1. 配置reindex.remote.whitelist參數(shù)

    需要在目標(biāo)ES集群中配置該參數(shù),指明能夠reindex的遠(yuǎn)程集群的白名單

  2. 調(diào)用reindex api

    以下操作表示從源ES集群中查詢名為test1的索引,查詢條件為title字段為elasticsearch,將結(jié)果寫入當(dāng)前集群的test2索引

     POST _reindex
     {
         "source": {
             "remote": {
                 "host": "http://x.x.x.1:9200"
             },
             "index": "test1",
             "query": {
                 "match": {
                     "title": "elasticsearch"
                 }
             }
         },
         "dest": {
             "index": "test2"
         }
     }
    

snapshot

snapshot api是Elasticsearch用于對(duì)數(shù)據(jù)進(jìn)行備份和恢復(fù)的一組api接口,可以通過(guò)snapshot api進(jìn)行跨集群的數(shù)據(jù)遷移,原理就是從源ES集群創(chuàng)建數(shù)據(jù)快照,然后在目標(biāo)ES集群中進(jìn)行恢復(fù)。需要注意ES的版本問(wèn)題:

        目標(biāo)ES集群的主版本號(hào)(如5.6.4中的5為主版本號(hào))要大于等于源ES集群的主版本號(hào);
        1.x版本的集群創(chuàng)建的快照不能在5.x版本中恢復(fù);
  1. 源ES集群中創(chuàng)建repository

    創(chuàng)建快照前必須先創(chuàng)建repository倉(cāng)庫(kù),一個(gè)repository倉(cāng)庫(kù)可以包含多份快照文件,repository主要有一下幾種類型

     fs: 共享文件系統(tǒng),將快照文件存放于文件系統(tǒng)中
     url: 指定文件系統(tǒng)的URL路徑,支持協(xié)議:http,https,ftp,file,jar
     s3: AWS S3對(duì)象存儲(chǔ),快照存放于S3中,以插件形式支持(repository-s3)
     hdfs: 快照存放于hdfs中,以插件形式支持(repository-hdfs)
     cos: 快照存放于騰訊云COS對(duì)象存儲(chǔ)中,以插件形式支持(repository-cos)
    

    以repository-cos為例,創(chuàng)建倉(cāng)庫(kù):

     PUT _snapshot/my_cos_backup
     {
         "type": "cos",
         "settings": {
             "app_id": "xxxxxxx",
             "access_key_id": "xxxxxx",
             "access_key_secret": "xxxxxxx",
             "bucket": "xxxxxx",
             "region": "ap-guangzhou",
             "compress": true,
             "chunk_size": "500mb",
             "base_path": "/"
         }
     }
    
  2. 源ES集群中創(chuàng)建snapshot

    調(diào)用snapshot api在創(chuàng)建好的倉(cāng)庫(kù)中創(chuàng)建快照

     curl -XPUT http://x.x.x.1:9200/_snapshot/my_backup/snapshot_1?wait_for_completion=true
    

    創(chuàng)建快照可以指定索引,也可以指定快照中包含哪些內(nèi)容,具體的api接口參數(shù)可以查閱官方文檔官方文檔

  3. 目標(biāo)ES集群中創(chuàng)建repository

    目標(biāo)ES集群中創(chuàng)建倉(cāng)庫(kù)和在源ES集群中創(chuàng)建倉(cāng)庫(kù)類似,用戶可在騰訊云上創(chuàng)建COS對(duì)象bucket, 將倉(cāng)庫(kù)建在COS的某個(gè)bucket下。

  4. 移動(dòng)源ES集群snapshot至目標(biāo)ES集群的倉(cāng)庫(kù)

    把源ES集群創(chuàng)建好的snapshot上傳至目標(biāo)ES集群創(chuàng)建好的倉(cāng)庫(kù)中

  5. 從快照恢復(fù)

     curl -XPUT http://x.x.x.2:9200/_snapshot/my_backup/snapshot_1/_restore
    
  6. 查看快照恢復(fù)狀態(tài)

     curl http://x.x.x.2:9200/_snapshot/_status
    

數(shù)據(jù)遷移時(shí)不能停止舊集群的寫入

如果舊集群不能停止寫入,此時(shí)進(jìn)行在線數(shù)據(jù)遷移,需要保證新舊集群的數(shù)據(jù)一致性。目前看來(lái),除了官方提供的CCR功能,沒有成熟的可以嚴(yán)格保證數(shù)據(jù)一致性的在線數(shù)據(jù)遷移方法。此時(shí)可以從業(yè)務(wù)場(chǎng)景出發(fā),根據(jù)業(yè)務(wù)寫入數(shù)據(jù)的特點(diǎn)選擇合適的數(shù)據(jù)遷移方案。

一般來(lái)說(shuō),業(yè)務(wù)寫入數(shù)據(jù)的特點(diǎn)有以下幾種:

  • add only, 只追加新數(shù)據(jù),比如日志、APM場(chǎng)景中,數(shù)據(jù)基本都是時(shí)序數(shù)據(jù),只會(huì)追加,沒有更新、刪除數(shù)據(jù)的操作
  • add & update, 數(shù)據(jù)有追加也有更新,但是沒有刪除數(shù)據(jù)的操作
  • add & update & delete, 數(shù)據(jù)有追加,也有更新和刪除,搜索場(chǎng)景比較常見

下面來(lái)具體分析不同的寫入數(shù)據(jù)的特點(diǎn)下,該如何選擇合適的數(shù)據(jù)遷移方式。

add only

在日志或者APM的場(chǎng)景中,數(shù)據(jù)都是時(shí)序數(shù)據(jù),一般索引也都是按天創(chuàng)建的,當(dāng)天的數(shù)據(jù)只會(huì)寫入當(dāng)前的索引中。此時(shí),可以先把存量的不再寫入的索引數(shù)據(jù)一次性同步到新集群中,然后使用logstash或者其它工具增量同步當(dāng)天的索引,待數(shù)據(jù)追平后,把業(yè)務(wù)對(duì)ES的訪問(wèn)切換到新集群中。

具體的實(shí)現(xiàn)方案為:

  1. 全量遷移冷索引
    因?yàn)槔涞乃饕辉賹懭?,可以采用elasticdump、logstash、reindex進(jìn)行遷移;如果數(shù)據(jù)量比較大的情況下,可以采用snapshot方式進(jìn)行遷移。
  2. 增量遷移熱索引

add only的數(shù)據(jù)寫入方式,可以按照數(shù)據(jù)寫入的順序(根據(jù)_doc進(jìn)行排序,如果有時(shí)間戳字段也可以根據(jù)時(shí)間戳排序)批量從舊集群中拉取數(shù)據(jù),然后再批量寫入新集群中;可以通過(guò)寫程序,使用用scroll api 或者search_after參數(shù)批量拉取增量數(shù)據(jù),再使用bulk api批量寫入。

使用scroll拉取增量數(shù)據(jù):

    POST {my\_index}/_search?scroll=1m
    
    {
      "size":"100",
      "query": {
        "range": {
          "timestamp": {
            "gt": "now-1m",
            "lt": "now/m"
          }
        }
      }
    }
    POST _search/scroll
    {
        "scroll": "1m",
        "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAHCbaFndPR3J4bDJtVDh1bnNRaW5yYWZBWncAAAAAABwm2RZ3T0dyeGwybVQ4dW5zUWlucmFmQVp3AAAAAAAcJtwWd09HcnhsMm1UOHVuc1FpbnJhZkFadwAAAAAAHCbbFndPR3J4bDJtVDh1bnNRaW5yYWZBWncAAAAAABwm3RZ3T0dyeGwybVQ4dW5zUWlucmFmQVp3"
}
    

上述操作可以每分鐘執(zhí)行一次,拉起前一分鐘新產(chǎn)生的數(shù)據(jù),所以數(shù)據(jù)在舊集群和新集群的同步延遲為一分鐘。

使用search_after批量拉取增量數(shù)據(jù):

    POST {my\_index}/_search
    {
     "size":100,
      "query": {
        "match_all": {}
      },
      "search_after": [
        1569556667000
      ],
      "sort": "timestamp"
    }

上述操作可以根據(jù)需要自定義事件間隔執(zhí)行,每次執(zhí)行時(shí)修改search_after參數(shù)的值,獲取指定值之后的多條數(shù)據(jù);search_after實(shí)際上相當(dāng)于一個(gè)游標(biāo),每執(zhí)行一次向前推進(jìn),從而獲取到最新的數(shù)據(jù)。

使用scroll和search_after的區(qū)別是:

  • scroll相當(dāng)于對(duì)數(shù)據(jù)做了一份快照,快照會(huì)保存在內(nèi)存中,會(huì)比較消耗資源;search_after是無(wú)狀態(tài)的,并不會(huì)過(guò)多的消耗內(nèi)存資源。
  • scroll可以分批次執(zhí)行,search_after獲取到的結(jié)果只能一次拉取完,所以需要合理控制search_after參數(shù)的值以及size的大小,以免出現(xiàn)一次拉取過(guò)多的數(shù)據(jù)導(dǎo)致內(nèi)存暴漲。
  • scroll執(zhí)行過(guò)程中并不能獲取到更新后的數(shù)據(jù)(對(duì)add only的場(chǎng)景并無(wú)影響),search_after每次拉取到的數(shù)據(jù)都是最新的。

另外,如果不想通過(guò)寫程序遷移舊集群的增量數(shù)據(jù)到新集群的話,可以使用logstash結(jié)合scroll進(jìn)行增量數(shù)據(jù)的遷移,可參考的配置文件如下:

    input {
      elasticsearch {
        hosts => "x.x.x.1:9200"
        index => "my_index"
        query => '{"query":{"range":{"timestamp":{"gte":"now-1m","lt":"now/m"}}}}'
        size => 100
        scroll => "1m"
        docinfo => true
        schedule => "*/1 * * * *" #定時(shí)任務(wù),每分鐘執(zhí)行一次
      }
    }
   output {
      elasticsearch {
         hosts => "x.x.x.2:9200"
        index => "%{[@metadata][_index]}"
        document_type => "%{[@metadata][_type]}"
        document_id => "%{[@metadata][_id]}"
      }
    }

使用過(guò)程中可以根據(jù)實(shí)際業(yè)務(wù)的需求調(diào)整定時(shí)任務(wù)參數(shù)schedule以及scroll相關(guān)的參數(shù)。

add & update

業(yè)務(wù)場(chǎng)景如果是寫入ES時(shí)既有追加,又有存量數(shù)據(jù)的更新,此時(shí)比較重要的是怎么解決update操作的數(shù)據(jù)同步問(wèn)題。對(duì)于新增的數(shù)據(jù),可以采用上述介紹的增量遷移熱索引的方式同步到新集群中。對(duì)于更新的數(shù)據(jù),此時(shí)如果索引有類似于updateTime的字段用于標(biāo)記數(shù)據(jù)更新的時(shí)間,則可以通過(guò)寫程序或者logstash,使用scroll api根據(jù)updateTime字段批量拉取更新的增量數(shù)據(jù),然后再寫入到新的集群中。

可參考的logstash配置文件如下:

    input {
      elasticsearch {
        hosts => "x.x.x.1:9200"
        index => "my_index"
        query => '{"query":{"range":{"updateTime":{"gt":"now-1m","lt":"now/m"}}}}'
        size => 100
        scroll => "1m"
        docinfo => true
        schedule => "* */1 * * *" #定時(shí)任務(wù),每分鐘執(zhí)行一次
      }
    }
   output {
      elasticsearch {
         hosts => "x.x.x.2:9200"
        index => "%{[@metadata][_index]}"
        document_type => "%{[@metadata][_type]}"
        document_id => "%{[@metadata][_id]}"
      }
    }
    

實(shí)際應(yīng)用各種,同步新增(add)的數(shù)據(jù)和更新(update)的數(shù)據(jù)可以同時(shí)進(jìn)行。但是如果索引中沒有類似updateTime之類的字段可以標(biāo)識(shí)出哪些數(shù)據(jù)是更新過(guò)的,目前看來(lái)并沒有較好的同步方式,可以采用CCR來(lái)保證舊集群和新集群的數(shù)據(jù)一致性。

add & update & delete

如果業(yè)務(wù)寫入ES時(shí)既有新增(add)數(shù)據(jù),又有更新(update)和刪除(delete)數(shù)據(jù),可以采用6.5之后商業(yè)版X-pack插件中的CCR功能進(jìn)行數(shù)據(jù)遷移。但是使用CCR有一些限制,必須要注意:

  • 舊集群和新集群的版本必須都在6.5及以上才能使用
  • Leader Index必須開啟index.soft_deletes.enabled, 否則不能使用CCR, 該參數(shù)的意義是打開后Leader Index中的所有操作都會(huì)被暫存下來(lái),F(xiàn)ollower Index 可以通過(guò)pull這些操作然后進(jìn)行重放,從而達(dá)到數(shù)據(jù)同步的目的;另外index.soft_deletes.enabled也只能在6.5之后的版本使用,并且只能在創(chuàng)建索引時(shí)開啟,如果沒有開啟的話可以通過(guò)reindex到新的索引解決。

具體的使用方式如下:

  1. 在新集群中配置舊集群的地址,注意必須為transport端口

    PUT /_cluster/settings
    {
      "persistent" : {
        "cluster" : {
          "remote" : {
            "leader" : {
              "seeds" : [
                "x.x.x.1:9300" 
              ]
            }
          }
        }
      }
    }
    
  2. 創(chuàng)建Leader Index

    PUT my_leader_indx
    {
        "settings":{
            "index.soft_deletes.enabled": true
        }
    }
    
  3. 創(chuàng)建Follower Index

    PUT my_follower_index/_ccr/follow?wait_for_active_shards=1
    {
      "remote_cluster" : "leader",
      "leader_index" : "my_leader_indx"
    }
    
  4. 查看Follower Index統(tǒng)計(jì)信息

    GET my_follower_index/_ccr/stats
    

使用中間件進(jìn)行雙寫

如果業(yè)務(wù)是通過(guò)中間件如kafka把數(shù)據(jù)寫入到ES, 則可以使用如下圖中的方式,使用logstash消費(fèi)kafka的數(shù)據(jù)到新集群中,在舊集群和新集群數(shù)據(jù)完全追平之后,可以切換到新集群進(jìn)行業(yè)務(wù)的查詢,之后再對(duì)舊的集群下線處理。


image

使用中間件進(jìn)行同步雙寫的優(yōu)點(diǎn)是:

  • 寫入過(guò)程中丟失數(shù)據(jù)風(fēng)險(xiǎn)較低
  • 可以保證新舊集群的數(shù)據(jù)一致性

當(dāng)然,雙寫也可以使用其他的方式解決,比如自建proxy,業(yè)務(wù)寫入時(shí)向proxy寫入,proxy把請(qǐng)求轉(zhuǎn)發(fā)到一個(gè)或者多個(gè)集群中,但是這種方式存在以下問(wèn)題:

  • proxy的性能會(huì)影響數(shù)據(jù)寫入的性能
  • proxy故障可能會(huì)丟失數(shù)據(jù),需要有一套完善的機(jī)制保證proxy的可用性

Elasticsearch跨機(jī)房容災(zāi)

隨著業(yè)務(wù)規(guī)模的增長(zhǎng),業(yè)務(wù)側(cè)對(duì)使用的ES集群的數(shù)據(jù)可靠性、集群穩(wěn)定性等方面的要求越來(lái)越高,所以要比較好的集群容災(zāi)方案支持業(yè)務(wù)側(cè)的需求。

同城跨機(jī)房容災(zāi):主備集群

image

如果是公司在自建IDC機(jī)房?jī)?nèi),通過(guò)物理機(jī)自己搭建的ES集群,在解決跨機(jī)房容災(zāi)的時(shí)候,往往會(huì)在兩個(gè)機(jī)房 部署兩個(gè)ES集群,一主一備,然后解決解決數(shù)據(jù)同步的問(wèn)題;數(shù)據(jù)同步一般有兩種方式,一種方式雙寫,由業(yè)務(wù)側(cè)實(shí)現(xiàn)雙寫保證數(shù)據(jù)一致性,但是雙寫對(duì)業(yè)務(wù)側(cè)是一個(gè)挑戰(zhàn),需要保證數(shù)據(jù)在兩個(gè)集群都寫成功才能算成功。另外一種方式是異步復(fù)制,業(yè)務(wù)側(cè)只寫主集群,后臺(tái)再把數(shù)據(jù)同步到備集群中去,但是比較難以保證數(shù)據(jù)一致性。第三種方式是通過(guò)專線打通兩個(gè)機(jī)房,實(shí)現(xiàn)跨機(jī)房部署,但是成本較高。

同城跨機(jī)房容災(zāi):跨機(jī)房部署集群

image

因?yàn)閿?shù)據(jù)同步的復(fù)雜性,云廠商在實(shí)現(xiàn)ES集群跨機(jī)房容災(zāi)的時(shí)候,往往都是通過(guò)只部署一個(gè)集群解決,利用ES自身的能力同步數(shù)據(jù)。國(guó)外某云廠商實(shí)現(xiàn)跨機(jī)房部署ES集群的特點(diǎn)1是不強(qiáng)制使用專用主節(jié)點(diǎn),如上圖中的一個(gè)集群,只有兩個(gè)節(jié)點(diǎn),既作為數(shù)據(jù)節(jié)點(diǎn)也作為候選主節(jié)點(diǎn);主分片和副本分片分布在兩個(gè)可用區(qū)中,因?yàn)橛懈北痉制拇嬖?,可用區(qū)1掛掉之后集群仍然可用,但是如果兩個(gè)可用區(qū)之間網(wǎng)絡(luò)中斷時(shí),會(huì)出現(xiàn)腦裂的問(wèn)題。如下圖中使用三個(gè)專用主節(jié)點(diǎn),就不會(huì)存在腦裂的問(wèn)題了。


image

但是如果一個(gè)地域沒有三個(gè)可用區(qū)怎么辦呢,那就只能在其中一個(gè)可用區(qū)中放置兩個(gè)專用主節(jié)點(diǎn)了,如國(guó)內(nèi)某云廠商的解決方案:


image

國(guó)內(nèi)某云廠商的做法是不管當(dāng)前地域有幾個(gè)可用區(qū),只要用戶只選擇在兩個(gè)可用區(qū)創(chuàng)建集群,那集群的節(jié)點(diǎn)必然只分布在兩個(gè)可用區(qū)中。但是這樣會(huì)引發(fā)集群無(wú)法選主的問(wèn)題。比如上圖中的集群,如果可用區(qū)2掛掉,就只剩一個(gè)主節(jié)點(diǎn)了,不能滿足quorum法定票數(shù), 無(wú)法選主了,這時(shí)候集群就不可用了。針對(duì)可能發(fā)生的腦裂和無(wú)法選主這兩個(gè)問(wèn)題,國(guó)外某云廠商和國(guó)內(nèi)某云廠商的解決辦法是進(jìn)行故障恢復(fù),重建節(jié)點(diǎn)。

但是重建節(jié)點(diǎn)的過(guò)程還是存在問(wèn)題的,如上圖中,集群本身的quorum應(yīng)該為2,可用區(qū)1掛掉后,集群中只剩一個(gè)專用主節(jié)點(diǎn),需要把quorum參數(shù)(discovery.zen.minimum_master_nodes)調(diào)整為1后集群才能夠正常進(jìn)行選主,等掛掉的兩個(gè)專用主節(jié)點(diǎn)恢復(fù)之后,需要再把quorum參數(shù)(discovery.zen.minimum_master_nodes)調(diào)整為2,以避免腦裂的發(fā)生。

當(dāng)然還是有可以把無(wú)法選主和腦裂這兩個(gè)可能發(fā)生的問(wèn)題規(guī)避掉的解決方案,如下圖中國(guó)內(nèi)某云廠商的解決思路:


image

創(chuàng)建雙可用區(qū)集群時(shí),必須選擇3個(gè)或者5個(gè)專用主節(jié)點(diǎn),后臺(tái)會(huì)在一個(gè)隱藏的可用區(qū)中只部署專用主節(jié)點(diǎn);方案的優(yōu)點(diǎn)1是如果一個(gè)可用區(qū)掛掉,集群仍然能夠正常選主,避免了因?yàn)椴粷M足quorum法定票數(shù)而無(wú)法選主的情況;2是因?yàn)楸仨氁x擇三個(gè)或5個(gè)專用主節(jié)點(diǎn),也避免了腦裂。

想比較一主一備兩個(gè)集群進(jìn)行跨機(jī)房容災(zāi)的方式,云廠商通過(guò)跨機(jī)房部署集群把原本比較復(fù)雜的主備數(shù)據(jù)同步問(wèn)題解決了,但是,比較讓人擔(dān)心的是,機(jī)房或者可用區(qū)之間的網(wǎng)絡(luò)延遲是否會(huì)造成集群性能下降。這里針對(duì)騰訊云的雙可用區(qū)集群,使用標(biāo)準(zhǔn)的benchmark工具對(duì)兩個(gè)同規(guī)格的單可用區(qū)和雙可用區(qū)集群進(jìn)行了壓測(cè),壓測(cè)結(jié)果如下圖所示:

  • 多可用區(qū)集群:


    image
  • 單可用區(qū)集群:


    image

從壓測(cè)結(jié)果的查詢延時(shí)和寫入延時(shí)指標(biāo)來(lái)看,兩種類型的集群并沒有明顯的差異,這主要得益與云上底層網(wǎng)絡(luò)基礎(chǔ)設(shè)施的完善,可用區(qū)之間的網(wǎng)絡(luò)延遲很低。

異地容災(zāi):主備集群

類似于同城跨機(jī)房容災(zāi),異地容災(zāi)一般的解決思路是在異地兩個(gè)機(jī)房部署一主一備兩個(gè)集群。業(yè)務(wù)寫入時(shí)只寫主集群,再異步地把數(shù)據(jù)同步到備集群中,但是實(shí)現(xiàn)起來(lái)會(huì)比較復(fù)雜,因?yàn)橐鉀Q主備集群數(shù)據(jù)一致性的問(wèn)題,并且跨地域的話,網(wǎng)絡(luò)延遲會(huì)比較高;還有就是,當(dāng)主集群掛掉之后,這時(shí)候切換到備集群,可能兩邊數(shù)據(jù)還沒有追平,出現(xiàn)不一致,導(dǎo)致業(yè)務(wù)受損。當(dāng)然,可以借助于kafka等中間件實(shí)現(xiàn)雙寫,但是數(shù)據(jù)鏈路增加了,寫入延遲也增加了,并且kafka出現(xiàn)問(wèn)題,故障可能就是災(zāi)難性的了。
一種比較常見的異步復(fù)制方法是,使用snapshot備份功能,定期比如每個(gè)小時(shí)在主集群中執(zhí)行一次備份,然后在備集群中進(jìn)行恢復(fù),但是主備集群會(huì)有一個(gè)小時(shí)的數(shù)據(jù)延遲。以騰訊云為例,騰訊云的ES集群支持把數(shù)據(jù)備份到對(duì)象存儲(chǔ)COS中,因?yàn)榭梢杂脕?lái)實(shí)現(xiàn)主備集群的數(shù)據(jù)同步,具體的操作步驟可以參考https://cloud.tencent.com/document/product/845/19549。

image

在6.5版本官方推出了CCR功能之后,集群間數(shù)據(jù)同步的難題就迎刃而解了??梢岳肅CR來(lái)實(shí)現(xiàn)ES集群的異地容災(zāi):


image

CCR是類似于數(shù)據(jù)訂閱的方式,主集群為L(zhǎng)eader, 備集群為Follower, 備集群以pull的方式從主集群拉取數(shù)據(jù)和寫請(qǐng)求;在定義好Follwer Index時(shí),F(xiàn)ollwer Index會(huì)進(jìn)行初始化,從Leader中以snapshot的方式把底層的segment文件全量同步過(guò)來(lái),初始化完成之后,再拉取寫請(qǐng)求,拉取完寫請(qǐng)求后,F(xiàn)ollwer側(cè)進(jìn)行重放,完成數(shù)據(jù)的同步。CCR的優(yōu)點(diǎn)當(dāng)然是因?yàn)榭梢酝経PDATE/DELETE操作,數(shù)據(jù)一致性問(wèn)題解決了,同步延時(shí)也減小了。

另外,基于CCR可以和前面提到的跨機(jī)房容災(zāi)的集群結(jié)合,實(shí)現(xiàn)兩地多中心的ES集群。在上海地域,部署有多可用區(qū)集群實(shí)現(xiàn)跨機(jī)房的高可用,同時(shí)在北京地域部署備集群作為Follwer利用CCR同步數(shù)據(jù),從而在集群可用性上又向前走了一步,既實(shí)現(xiàn)了同城跨機(jī)房容災(zāi),又實(shí)現(xiàn)了跨地域容災(zāi)。

image

但是在出現(xiàn)故障時(shí)需要把集群的訪問(wèn)從上海切換到北京時(shí),會(huì)有一些限制,因?yàn)镃CR中的Follwer Index是只讀的,不能寫入,需要切換為正常的索引才能進(jìn)行寫入,過(guò)程也是不可逆的。不過(guò)在業(yè)務(wù)側(cè)進(jìn)行規(guī)避,比如寫入時(shí)使用新的正常的索引,業(yè)務(wù)使用別名進(jìn)行查詢,當(dāng)上海地域恢復(fù)時(shí),再反向的把數(shù)據(jù)同步回去。

POST /<follower_index>/_ccr/pause_follow
POST /<follower_index>/_close
POST /<follower_index>/_ccr/unfollow
POST /<follower_index>/_open

現(xiàn)在問(wèn)題就是保證上海地域集群數(shù)據(jù)的完整性,在上海地域恢復(fù)后,可以在上海地域新建一個(gè)Follower Index,以北京地域正在進(jìn)行寫的索引為L(zhǎng)eader同步數(shù)據(jù),待數(shù)據(jù)完全追平后,再切換到上海地域進(jìn)行讀寫,注意切換到需要新建Leader索引寫入數(shù)據(jù)。

數(shù)據(jù)同步過(guò)程如下所示:

1.上海主集群正常提供服務(wù),北京備集群從主集群Follow數(shù)據(jù)


image

2.上海主集群故障,業(yè)務(wù)切換到北京備集群進(jìn)行讀寫,上海主集群恢復(fù)后從北京集群Follow數(shù)據(jù)


image

3.主備集群數(shù)據(jù)追平后,業(yè)務(wù)切換到上海集群進(jìn)行讀寫
image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容