OpenSearch Segment Replication 初體驗(yàn)

1 Data Replication 簡(jiǎn)介

作為一個(gè)分布式數(shù)據(jù)系統(tǒng),Elasticsearch/OpenSearch 也有主副本( Primary Shard )和副本( Replica Shard )的概念。

Replica 是 Primary 的 Clone ( 復(fù)制體 ),這樣就可以實(shí)現(xiàn)系統(tǒng)的高可用,具備容災(zāi)能力。

Replica 從 Primary 復(fù)制數(shù)據(jù)的過程被成為數(shù)據(jù)復(fù)制( Data Replication ),Data Replication 的核心考量指標(biāo)是 Replica 和 Primary 的延遲( Lag )大小,如果 Lag 一直為0,那么就是實(shí)時(shí)復(fù)制,可靠性最高。

Data Replication 的方案有很多,接下來主要介紹基于文檔的復(fù)制方案( Document Replication ) 和基于文件的復(fù)制方案 ( Segment Replication )。

1.1 Document Replication

Elasticsearch/OpenSearch 目前采用的是基于文檔的復(fù)制方案,整個(gè)過程如下圖所示:

image.png
  1. Client 發(fā)送寫請(qǐng)求到 Primary Shard Node
  2. Primary Shard Node 將相關(guān)文檔先寫入本地的 translog,按需進(jìn)行 refresh
  3. 上述步驟執(zhí)行成功后,Primary Shard Node 轉(zhuǎn)發(fā)寫請(qǐng)求到 Replica Shard Nodes,此處轉(zhuǎn)發(fā)的內(nèi)容是實(shí)際的文檔
  4. Replica Shard Node 接收到寫請(qǐng)求后,先寫入本地的 translog,按需進(jìn)行 refresh,返回 Primary Shard Node 執(zhí)行成功
  5. Primary Shard Node 返回 Client 寫成功。
  6. 后續(xù) Primary Shard Node 和 Replica Shard Node 會(huì)按照各自的配置獨(dú)立進(jìn)行 refresh 行為,生成各自的 segment 文件。

這里要注意的一點(diǎn)是:Primary Shard 和 Replica Shard 的 refresh 是獨(dú)立的任務(wù),執(zhí)行時(shí)機(jī)和時(shí)間會(huì)有所差異,這也會(huì)導(dǎo)致兩邊實(shí)際生成和使用的 segment 文件有差異。

以上便是 Document Replication 的簡(jiǎn)易流程,對(duì)完整流程感興趣的,可以通過下面的連接查看更詳細(xì)的介紹。

1.2 Segment Replication

elasticsearch 數(shù)據(jù)寫入最耗時(shí)的部分是生成 segment 文件的過程,因?yàn)檫@里涉及到分詞、字典生成等等步驟,需要很多 CPU 和 Memory 資源。

而 Document Replication 方案需要在 Primary Node 和 Replica Nodes 上都執(zhí)行 segment 文件的生成步驟,但是在 Replica Nodes 上的執(zhí)行實(shí)際是一次浪費(fèi),如果可以避免這次運(yùn)算,將節(jié)省不少 CPU 和 Memory 資源。

解決的方法也很簡(jiǎn)單,等 Primary Node 運(yùn)行完畢后,直接將生成的 segment 文件復(fù)制到 Replica Nodes 就好了。這種方案就是 Segment Replication。

Segment Replication 的大致流程如下圖所示:

image.png
  1. Client 發(fā)送寫請(qǐng)求到 Primary Shard Node
  2. Primary Shard Node 將相關(guān)文檔先寫入本地的 translog,按需和相關(guān)配置進(jìn)行 refresh,此處不是一定觸發(fā) refresh
  3. 上述步驟執(zhí)行成功后,Primary Shard Node 轉(zhuǎn)發(fā)寫請(qǐng)求到 Replica Shard Nodes,此處轉(zhuǎn)發(fā)的內(nèi)容是實(shí)際的文檔
  4. Replica Shard Node 接收到寫請(qǐng)求后,寫入本地的 translog,然后返回 Primary Shard Node 執(zhí)行成功
  5. Primary Shard Node 返回 Client 寫成功。
  6. Primary Shard Node 在觸發(fā) refresh 后,會(huì)通知 Replica Shard Nodes 同步新的 segment 文件。
  7. Replica Shard Nodes 會(huì)對(duì)比本地和 Primary Shard Node 上的 segment 文件列表差異,然后請(qǐng)求同步本地缺失和發(fā)生變更的 segment 文件。
  8. Primary Shard Node 根據(jù) Replica Shard Nodes 的相關(guān)請(qǐng)求完成 segment 文件的發(fā)送
  9. Replica Shard Nodes 在完整接收 segment 文件后,刷新 Lucene 的 DirectoryReader 載入最新的文件,使新文檔可以被查詢

這里和 Document Replication 最大的不同是 Replica Shard Nodes 不會(huì)在獨(dú)立生成 segment 文件,而是直接從 Primary Shard Node 同步,本地的 translog 只是為了實(shí)現(xiàn)數(shù)據(jù)的可靠性,在 segment 文件同步過來后,就可以刪除。

以上便是 Segment Replication 的簡(jiǎn)易流程,對(duì)完整流程感興趣的,可以通過下面的連接查看更詳細(xì)的介紹。

2 Segment Replication 初體驗(yàn)

OpenSearch 在 2.3 版本中發(fā)布了實(shí)驗(yàn)版本的 Segment Replication 功能,接下來就讓我們一起體驗(yàn)一下吧~

2.1 準(zhǔn)備 docker 環(huán)境和相關(guān)文件

本次體驗(yàn)基于 docker-compose 來執(zhí)行,如下為相關(guān)內(nèi)容(docker-compose.yml):

version: '3'
services:
  opensearch-node1:
    image: opensearchproject/opensearch:2.3.0
    container_name: os23-node1
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node1
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
      - plugins.security.disabled=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m -Dopensearch.experimental.feature.replication_type.enabled=true" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536 # maximum number of open files for the OpenSearch user, set to at least 65536 on modern systems
        hard: 65536
    volumes:
      - ./os23data1:/usr/share/opensearch/data
    ports:
      - 9200:9200
      - 9600:9600 # required for Performance Analyzer
    networks:
      - opensearch-net
  opensearch-node2:
    image: opensearchproject/opensearch:2.3.0
    container_name: os23-node2
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node2
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true
      - plugins.security.disabled=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m -Dopensearch.experimental.feature.replication_type.enabled=true"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - ./os23data2:/usr/share/opensearch/data
    networks:
      - opensearch-net
  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:2.3.0
    container_name: os23-dashboards
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      OPENSEARCH_HOSTS: '["http://opensearch-node1:9200","http://opensearch-node2:9200"]'
      DISABLE_SECURITY_DASHBOARDS_PLUGIN: "true"
    networks:
      - opensearch-net

networks:
  opensearch-net:

簡(jiǎn)單說明如下:

  • 為了演示方便,關(guān)閉了安全特性
  • 要在 OPENSEARCH_JAVA_OPTS 中添加 -Dopensearch.experimental.feature.replication_type.enabled=true 才能開啟segment replication 功能

2.2 運(yùn)行 OpenSearch 集群

執(zhí)行如下命令運(yùn)行 OpenSearch Cluster:

docker-compose -f docker-compose.yml up

運(yùn)行成功后,可以訪問 http://127.0.0.1:5601 打開 Dashboards 界面,進(jìn)入 Dev Tools 中執(zhí)行后續(xù)的操作

2.3 測(cè)試 Segment Replication

測(cè)試思路如下:

  1. 創(chuàng)建兩個(gè) index,一個(gè)默認(rèn)配置,一個(gè)啟用 segment replication,主分片數(shù)為1,副本數(shù)為1
  2. 向兩個(gè) index 中插入若干條數(shù)據(jù)
  3. 比較兩個(gè) index 中 segment file 的數(shù)量和大小

相關(guān)命令如下:

PUT /test-rep-by-doc
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  }
}

GET test-rep-by-doc/_settings

POST test-rep-by-doc/_doc
{
  "name": "rep by doc"
}

GET _cat/shards/test-rep-by-doc?v

GET _cat/segments/test-rep-by-doc?v&h=index,shard,prirep,segment,generation,docs.count,docs.deleted,size&s=index,segment,prirep


PUT /test-rep-by-seg
{
  "settings": {
    "index": {
      "replication.type": "SEGMENT",
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  }
}


GET test-rep-by-seg/_settings

POST test-rep-by-seg/_doc
{
  "name": "rep by seg"
}

GET _cat/shards/test-rep-by-seg

GET _cat/segments/test-rep-by-seg?v&h=index,shard,prirep,segment,generation,docs.count,docs.deleted,size&s=index,segment,prirep

插入文檔后,通過 _cat/segments 可以得到 segment file 列表,然后通過 size 一列可以對(duì)比 segment 文件大小。

如下是默認(rèn)基于文檔復(fù)制的結(jié)果:

index           shard prirep segment generation docs.count docs.deleted  size
test-rep-by-doc 0     p      _0               0          2            0 3.7kb
test-rep-by-doc 0     r      _0               0          1            0 3.6kb
test-rep-by-doc 0     p      _1               1          2            0 3.7kb
test-rep-by-doc 0     r      _1               1          3            0 3.8kb
test-rep-by-doc 0     p      _2               2          1            0 3.6kb
test-rep-by-doc 0     r      _2               2          3            0 3.8kb
test-rep-by-doc 0     p      _3               3          6            0 3.9kb
test-rep-by-doc 0     r      _3               3          6            0 3.9kb
test-rep-by-doc 0     p      _4               4          5            0 3.9kb
test-rep-by-doc 0     r      _4               4          6            0 3.9kb
test-rep-by-doc 0     p      _5               5          6            0 3.9kb
test-rep-by-doc 0     r      _5               5          6            0 3.9kb
test-rep-by-doc 0     p      _6               6          4            0 3.8kb
test-rep-by-doc 0     r      _6               6          1            0 3.6kb

從中可以看到,雖然 Primary Shard 和 Replica Shard 的 segment 數(shù)相同,但是 size 大小是不同的,這也說明其底層的 segment 文件是獨(dú)立管理的。

如下是基于 Segment 復(fù)制的結(jié)果:

index           shard prirep segment generation docs.count docs.deleted  size
test-rep-by-seg 0     p      _0               0          2            0 3.7kb
test-rep-by-seg 0     r      _0               0          2            0 3.7kb
test-rep-by-seg 0     p      _1               1          7            0   4kb
test-rep-by-seg 0     r      _1               1          7            0   4kb
test-rep-by-seg 0     p      _2               2          5            0 3.9kb
test-rep-by-seg 0     r      _2               2          5            0 3.9kb

從中可以看到 Primary Shard 和 Replica Shard 的 segment 完全一致。

除此之外也可以從磁盤文件中對(duì)比,同樣可以得出相同的結(jié)論:Segment Replication 是基于文件的數(shù)據(jù)復(fù)制方案,Primary 和 Replica 的 segment 文件列表完全相同。

3 總結(jié)

根據(jù) OpenSearch 社區(qū)的初步測(cè)試,Segment Replication 相較于 Document Replication 的性能結(jié)果如下:

  • 在 Replica Nodes 上,CPU 和 Memory 資源減少 40%~50%
  • 寫入性能方面,整體吞吐量提升約 50%,P99 延遲下降了 20% 左右

這個(gè)測(cè)試結(jié)果還是很誘人的,但 Segment Replication 也有其自身的局限,下面簡(jiǎn)單列幾點(diǎn)( 不一定準(zhǔn)確 ):

  • Segment Replication 對(duì)于網(wǎng)絡(luò)帶寬資源要求更高,目前測(cè)試中發(fā)現(xiàn)有近1倍的增長(zhǎng),需要更合理的分配 Primary Shard 到不同的 Node 上,以分散網(wǎng)絡(luò)帶寬壓力
  • Segment Replication 可能會(huì)由于文件傳輸?shù)难舆t而導(dǎo)致 Replica Shard 上可搜索的文檔短時(shí)間內(nèi)與 Primary Shard 不一致
  • Replica Shard 升級(jí)為 Primary Shard 的時(shí)間可能會(huì)因?yàn)橹胤?translog 文件而變長(zhǎng),導(dǎo)致 Cluster 不穩(wěn)定

友情提示下,由于該特性目前還是實(shí)驗(yàn)階段,還不具備上生產(chǎn)環(huán)境的能力,大家可以持續(xù)關(guān)注~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 一、ES基本概念 1.1 索引(Index) 一個(gè)索引就是一個(gè)擁有幾分相似特征的文檔的集合。一個(gè)索引由一個(gè)名字來標(biāo)...
    CJ21閱讀 2,436評(píng)論 2 21
  • 1.為什么要使用Elasticsearch? ? 因?yàn)樵谖覀兩坛侵械臄?shù)據(jù),將來會(huì)非常多,所以采用以往的模糊查詢,模...
    陳二狗想吃肉閱讀 5,708評(píng)論 0 12
  • 一,讀寫底層原理 Elasticsearch寫人數(shù)據(jù)的過程 1)客戶端選擇一個(gè)node發(fā)送請(qǐng)求過去,這個(gè)node就...
    CoderZS閱讀 1,806評(píng)論 0 0
  • Cluster:代表一個(gè)集群,集群中有多個(gè)節(jié)點(diǎn),其中有一個(gè)為主節(jié)點(diǎn),這個(gè)主節(jié)點(diǎn)是可以通過選舉產(chǎn)生的,主從節(jié)點(diǎn)是對(duì)于...
    moonhatred閱讀 883評(píng)論 0 0
  • 簡(jiǎn)單操作可以直接使用ElasticsearchRespositor接口,復(fù)雜的使用ElasticsearchTem...
    一個(gè)彩筆程序猿閱讀 814評(píng)論 0 0