OpenSearch Segment Replication 初體驗

1 Data Replication 簡介

作為一個分布式數據系統,Elasticsearch/OpenSearch 也有主副本( Primary Shard )和副本( Replica Shard )的概念。

Replica 是 Primary 的 Clone ( 復制體 ),這樣就可以實現系統的高可用,具備容災能力。

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

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

1.1 Document Replication

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

image.png
  1. Client 發送寫請求到 Primary Shard Node
  2. Primary Shard Node 將相關文檔先寫入本地的 translog,按需進行 refresh
  3. 上述步驟執行成功后,Primary Shard Node 轉發寫請求到 Replica Shard Nodes,此處轉發的內容是實際的文檔
  4. Replica Shard Node 接收到寫請求后,先寫入本地的 translog,按需進行 refresh,返回 Primary Shard Node 執行成功
  5. Primary Shard Node 返回 Client 寫成功。
  6. 后續 Primary Shard Node 和 Replica Shard Node 會按照各自的配置獨立進行 refresh 行為,生成各自的 segment 文件。

這里要注意的一點是:Primary Shard 和 Replica Shard 的 refresh 是獨立的任務執行時機和時間會有所差異,這也會導致兩邊實際生成和使用的 segment 文件有差異。

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

1.2 Segment Replication

elasticsearch 數據寫入最耗時的部分是生成 segment 文件的過程,因為這里涉及到分詞、字典生成等等步驟,需要很多 CPU 和 Memory 資源。

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

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

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

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

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

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

2 Segment Replication 初體驗

OpenSearch 在 2.3 版本中發布了實驗版本的 Segment Replication 功能,接下來就讓我們一起體驗一下吧~

2.1 準備 docker 環境和相關文件

本次體驗基于 docker-compose 來執行,如下為相關內容(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:

簡單說明如下:

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

2.2 運行 OpenSearch 集群

執行如下命令運行 OpenSearch Cluster:

docker-compose -f docker-compose.yml up

運行成功后,可以訪問 http://127.0.0.1:5601 打開 Dashboards 界面,進入 Dev Tools 中執行后續的操作

2.3 測試 Segment Replication

測試思路如下:

  1. 創建兩個 index,一個默認配置,一個啟用 segment replication,主分片數為1,副本數為1
  2. 向兩個 index 中插入若干條數據
  3. 比較兩個 index 中 segment file 的數量和大小

相關命令如下:

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 一列可以對比 segment 文件大小。

如下是默認基于文檔復制的結果:

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 數相同,但是 size 大小是不同的,這也說明其底層的 segment 文件是獨立管理的。

如下是基于 Segment 復制的結果:

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 完全一致。

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

3 總結

根據 OpenSearch 社區的初步測試,Segment Replication 相較于 Document Replication 的性能結果如下:

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

這個測試結果還是很誘人的,但 Segment Replication 也有其自身的局限,下面簡單列幾點( 不一定準確 ):

  • Segment Replication 對于網絡帶寬資源要求更高,目前測試中發現有近1倍的增長,需要更合理的分配 Primary Shard 到不同的 Node 上,以分散網絡帶寬壓力
  • Segment Replication 可能會由于文件傳輸的延遲而導致 Replica Shard 上可搜索的文檔短時間內與 Primary Shard 不一致
  • Replica Shard 升級為 Primary Shard 的時間可能會因為重放 translog 文件而變長,導致 Cluster 不穩定

友情提示下,由于該特性目前還是實驗階段,還不具備上生產環境的能力,大家可以持續關注~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一、ES基本概念 1.1 索引(Index) 一個索引就是一個擁有幾分相似特征的文檔的集合。一個索引由一個名字來標...
    CJ21閱讀 2,419評論 2 21
  • 1.為什么要使用Elasticsearch? ? 因為在我們商城中的數據,將來會非常多,所以采用以往的模糊查詢,模...
    陳二狗想吃肉閱讀 5,679評論 0 12
  • 一,讀寫底層原理 Elasticsearch寫人數據的過程 1)客戶端選擇一個node發送請求過去,這個node就...
    CoderZS閱讀 1,790評論 0 0
  • Cluster:代表一個集群,集群中有多個節點,其中有一個為主節點,這個主節點是可以通過選舉產生的,主從節點是對于...
    moonhatred閱讀 872評論 0 0
  • 簡單操作可以直接使用ElasticsearchRespositor接口,復雜的使用ElasticsearchTem...
    一個彩筆程序猿閱讀 804評論 0 0