# 优化Elasticsearch和OpenSearch集群写入性能
CSS服务中的Elasticsearch和OpenSearch集群在使用前，建议参考本文进行集群的写入性能优化，便于提高集群的写入性能，提升使用效率。
#### 数据写入流程
图1数据写入流程   
![](https://support.huaweicloud.com/bestpractice-css/figure/zh-cn_image_0000001934020374.png "点击放大")
如[图1]所示，以Elasticsearch集群为例，介绍客户端往Elasticsearch或OpenSearch集群中写入数据的流程。图中的P表示主分片Primary，R表示副本分片Replica，主副分片在数据节点Node里是随机分配的，但是不能在同一个节点里。
1. 客户端向Node1发送写数据请求，此时Node1为协调节点。
2. 节点Node1根据数据的_id将数据路由到分片2，此时请求会被转发到Node3，并执行写操作。
3. 当主分片写入成功后，它将请求转发到Node2的副本分片上。当副本写入成功后，Node3将向协调节点报告写入成功，协调节点向客户端报告写入成功。
Elasticsearch中的单个索引由一个或多个分片(shard)组成，每个分片包含多个段（Segment），每一个Segment都是一个倒排索引。
图2Elasticsearch的索引组成   
![](https://support.huaweicloud.com/bestpractice-css/figure/zh-cn_image_0000001961178889.png "点击放大")
如[图3]所示，将文档插入Elasticsearch时，文档首先会被写入缓冲区Buffer中，同时写入日志Translog中，然后在刷新时定期从该缓冲区刷新文档到Segment中。刷新频率由refresh_interval参数控制，默认1秒刷新一次。更多写入性能相关的介绍请参见Elasticsearch的官方介绍[Near Real-Time Search](https://www.elastic.co/guide/en/elasticsearch/guide/master/near-real-time.html)。
图3文档插入Elasticsearch的流程   
![](https://support.huaweicloud.com/bestpractice-css/figure/zh-cn_image_0000001961178893.png "点击放大")
#### 写入性能优化
基于Elasticsearch的数据写入流程分析，有以下几种性能优化方案。
表1写入性能优化 
| 优化方案          | 方案说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|:---|:---|
| 使用SSD盘或升级集群配置  | 使用SSD盘可以大幅提升数据写入与merge操作的速度，对应到CSS服务，建议选择"超高IO型"存储，或者超高IO型主机。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 采用Bulk API     | 客户端采用批量数据的写入方式，每次批量写入的数据建议在1\~10MB之间。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| 随机生成_id          | 如果采用指定_id的写入方式，数据写入时会先触发一次查询操作，进而影响数据写入性能。对于不需要通过_id检索数据的场景，建议使用随机生成的_id。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| 设置合适的分片数       | 分片数建议设置为集群数据节点的倍数，且分片的大小控制在50GB以内。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| 关闭副本          | 数据写入与查询错峰执行，在数据写入时关闭数据副本，待数据写入完成后再开启副本。 关闭副本的命令如下： ``` PUT {index}/_settings { "number_of_replicas": 0 } ```                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| 调整索引的刷新频率     | 数据批量写入时，可以将索引的刷新频率"refresh_interval"设置为更大的值或者设置为"-1"（表示不刷新），通过减少分片刷新次数提高写入性能。 将更新时间设置为15s的命令如下： ``` PUT {index}/_settings { "refresh_interval": "15s" } ```                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| 优化写入线程数与写入队列大小 | 为应对突发流量，可以适当地提升写入线程数与写入队列的大小，防止突发流量导致出现错误状态码为429的情况。 Elasticsearch和OpenSearch的线程池配置说明： - thread_pool.write.size：控制写入操作的线程数量，建议根据实际负载调整。 - 默认值：与系统CPU核数相同  - 取值范围：1 \~（系统CPU核数 + 1）    - thread_pool.write.queue_size：定义等待执行写入任务的队列大小。如果队列满，新任务将被拒绝。 - 默认值：10000  - 取值范围：所有合法整数值（Integer）     |
| 设置合适的字段类型      | 指定索引中各字段的类型，防止Elasticsearch默认将字段猜测为keyword和text的组合类型，增加不必要的数据量。其中keyword用于关键词搜索，text用于全文搜索。 对于不需要索引的字段，建议"index"设置为"false"。 将字段"field1"设置为禁用索引的命令参考如下： ``` PUT {index} { "mappings": { "properties": { "field1":{ "type": "text", "index": false } } } } ```                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 优化shard均衡策略     | Elasticsearch默认采用基于磁盘容量大小的Load balance策略，在多节点场景下，尤其是在新扩容的节点上，可能出现shard在各节点上分配不均的问题。为避免这类问题，可以通过设置索引级别的参数"routing.allocation.total_shards_per_node"控制索引分片在各节点的分布情况。此参数可以在索引模板中配置，也可以修改已有索引的settings生效。 修改已有索引的settings的命令如下： ``` PUT {index}/_settings { "index": { "routing.allocation.total_shards_per_node": 2 } } ```                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
   
