es数据写入过程
1.Refresh
将文档先保存在index buffer中,以refresh_interval为间隔时间,定期清空buffer,生成segment,借助文档系统缓存的特性
先将segament放在文档系统缓存中,并开放查询,以提升搜索的实时性
2.Translog
Segment没有写入磁盘,即使发生了宕机,重启后数据也能恢复,默认配置是每次请求都会落盘
3.Flush
删除旧的translog文件
生成好的segament写入磁盘/更新commit pointer并写入磁盘,es自动完成,优化点不多
降低refresh的频率
1.增加refresh_interval的数值,默认为1s,改成-1,会禁止自动refresh
避免过于频繁的refresh,生成过多的segment文件,但是会降低搜索的实时性
增大静态配置参数
indices.memory.index_buffer_size(默认是10%,会导致自动触发refresh
降低写磁盘的频率,但是会降低容灾能力
index.translog.durability:默认是request,每个请求都落盘。设置称async,异步写入
index.translog.sync_interval设置为60s,每分钟执行一次(每分钟写一次磁盘)
index.translog.flush_threshod_size:默认为512Mb,可以适当调大,当translog超过该值,会触发flush操作
分片设定
副本在写入时候设置为0,完成后再增加
合理设置主分片数,确保均匀分配在所有数据节点上
index.routing.allocation.total_share_per_node,限定每个索引在每个节点上可分配的主分片数
5个节点的集群,索引有5个主分片,一个副本(5+5)/5=2
生产环境要适当调大这个数字,避免有节点下线时,分片无法正常迁移
Bulk,线程池和队列大小
- 单个bulk请求的数据不要太大,官方建议5-15Mb
- 写入端的Buik请求超时要足够长,建议60s以上
- 写入端尽量轮训,把数据打到不同节点上
服务器端
- 索引创建属于计算密集型任务,使用固定大小的线程池来配置,来不及处理的放入队列,线程数应该配置成CPU核数+1
- 避免过多的上下文切换
- 队列大小可以适当增加,不要过大,否则占用的内存会成为Gc的负担
查询优化
-
尽量Denormalize数据,从而获取最佳的性能
-
使用Nested类型的数据,查询性能会慢几倍,
-
使用parent/child关系,查询速度会慢几百倍
-
尽量使用Filter Context,利用缓存机制,减少不必要的算分
-
结合Profile,explain Api分析慢查询的问题,持续优化数据模型
-
严禁使用*开头的通配符terms查询
-
聚合查询会消耗内存,控制聚合的数量,减少内存开销
-
通配符开头的正则表达式,性能非常差,避免使用
避免Over Sharing
一个查询需要查询每个分片,分片过多,会导致不必要的开销,应用场景控制每个分片的大小
Force-merge Read-Only索引
使用基于时间序列的索引,将只读的索引进行force merge ,减少segment数量