es写入流程
- 写入lucene缓存,此时数据不可见,同时会写一份数据到translog; 如果此时写入成功,会将写请求转发到对应的副分片上.
- 到达一定时间,或内存中的数据达到一定量时,出发refresh,生成segment,此时数据存在与文件缓存系统内存中,可见.
- 日志数据到达一定大小或者时间超过一定时间时,flush: 内存中的数据刷新到文件缓存中 --> 清空内存 --> 文件系统缓存数据刷新到硬盘中 --> 删除旧日志,创建新日志
优化点
加大 Translog Flush ,目的是降低 Iops、Writeblock。
增加 Index Refresh 间隔,目的是减少 Segment Merge 的次数。
调整 Bulk 线程池和队列。
优化节点间的任务分布。
优化 Lucene 层的索引建立,目的是降低 CPU 及 IO。
批量提交
- 当有大量的写任务时,使用批量提交是种不错的方案: 但是每次提交的数据量为多大时能达到最优的性能,受文件大小、数据类型、网络情况、集群状态等因素的影响。通用的策略如下。
1. Bulk 默认设置批量提交的数据量不能超过 100M。数据条数一般是根据文档的大小和服务器性能而定的,但是单次批处理的数据大小应从 5MB~15MB 逐渐增加,当性能没有提升时,把这个数据量作为最大值。
2. 在通过增加一次提交的数量而效果没有显著提升时,则需要逐渐增加并发数,并监控服务器的CPU、io、内存等使用情况
3. 若抛出EsRejectedExecutionException错误,则表明集群已经没有处理能力了,说明至少有一种资源已经到达瓶颈,这时需要升级已经到达瓶颈的资源或者增加集群的节点。
优化存储设备
ES 是一种密集使用磁盘的应用,在段合并的时候会频繁操作磁盘,所以对磁盘要求较高,当磁盘速度提升之后,集群的整体性能会大幅度提高。
磁盘的选择,提供以下几点建议:
1. 使用固态硬盘(Solid State Disk)替代机械硬盘。SSD 与机械磁盘相比,具有高效的读写速度和稳定性。
2. 使用 RAID 0。RAID 0 条带化存储,可以提升磁盘读写效率。
在 ES 的服务器上挂载多块硬盘。使用多块硬盘同时进行读写操作提升效率,
3. 在配置文件 ES 中设置多个存储路径,如下所示:
path.data:/ path/to/data1,/ path/to/data2。
4. 避免使用 NFS(Network File System)等远程存储设备,网络的延迟对性能的影响是很大的。
合理使用段合并
- Lucene 以段的形式存储数据。当有新的数据写入索引时,Lucene 就会自动创建一个新的段。随着数据量的变化,段的数量会越来越多,消耗的多文件句柄数及 CPU 就越多,查询效率就会下降,es默认采用较保守的策略,让后台定期进行段合并
索引写入效率下降:当段合并的速度落后于索引写入的速度时,ES 会把索引的线程数量减少到 1。 这样可以避免出现堆积的段数量爆发,同时在日志中打印出“now throttling indexing”INFO 级别的“警告”信息。
提升段合并速度:ES 默认对段合并的速度是 20m/s,如果使用了 SSD,我们可以通过以下的命令将这个合并的速度增加到 100m/s。
PUT /_cluster/settings
{"persistent": {"indices.store.throttle.max_bytes_per_sec": "100mb"}}
段合并线程数:
index.merge.scheduler.max_thread_count : Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)), 如果只有一块硬盘且是机械硬盘,设为1(减少寻址浪费)
减少段合并次数:
index.merge.policy.floor_segment:2M 小于该值的segment会被优先合并,可调小以优化
每次合并个数:
index.merge.policy.max_merge_at_once:10 可适当增大,较小merge次数
最大segment尺寸:
index.merge.policy.max_merged_segment: 5G 可适当减小,减少merge
减少refresh次数
- Lucene 在新增数据时,采用了延迟写入的策略,默认情况下索引的 refresh_interval 为 1 秒。
Lucene 将待写入的数据先写到内存中,超过 1 秒(默认)时就会触发一次 Refresh,然后 Refresh 会把内存中的的数据刷新到操作系统的文件缓存系统中。
如果我们对搜索的实效性要求不高,可以将 Refresh 周期延长,例如 30 秒。
这样还可以有效地减少段刷新次数,但这同时意味着需要消耗更多的Heap内存。
如下所示:
index.refresh_interval:30s
indices.memory.index_buffer_size: 10% heapMemory
PUT /twitter/_settings
{"index" : {"refresh_interval" : "30s"}}
修改translog设置
PUT /twitter/_settings
{"index.translog.sync_interval": "30s","index.translog.durability": "async"}
加大flush设置
- Flush 的主要目的是把文件缓存系统中的段持久化到硬盘,当 Translog 的数据量达到 512MB 或者 30 分钟时,会触发一次 Flush。
index.translog.flush_threshold_size 参数的默认值是 512MB,我们进行修改。
增加参数值意味着文件缓存系统中可能需要存储更多的数据,所以我们需要为操作系统的文件缓存系统留下足够的空间。
减少副本数量
- ES 为了保证集群的可用性,提供了 Replicas(副本)支持,然而每个副本也会执行分析、索引及可能的合并过程,所以 Replicas 的数量会严重影响写索引的效率。
当写索引时,需要把写入的数据都同步到副本节点,副本节点越多,写索引的效率就越慢。
如果我们需要大批量进行写入操作,可以先禁止 Replica 复制,设置 index.number_of_replicas: 0 关闭副本。在写入完成后,Replica 修改回正常的状态。
合理mapping
- 字段的 index 属性设置为: false
- 字段的 type 属性设为:keyword