本文集主要是总结自己在项目中使用ES 的经验教训,包括各种实战和调优。
自己写的单线程读取数据,多线程导入数据的代码示例:
按照网上的推荐,bulk一次写入数据的个数一般是1000-5000,请求大小一般为5-15MB。按照bulk官网的代码是可以设置请求个数、请求大小、发送请求时间,满足其一即发送bulk请求。即bulk-processor
我们这里采用是1000条请求发送一次。
具体代码示例见文档的底部。
elasticsearch写入性能优化
多线程插入
取消replias,写入完成之后在修改replias>=1
提高ES占用内存,ES内存最好占服务器内存的一半,同时最大和最小设置成一样(-Xms、-Xmx),避免GC.
减少shard刷新间隔。写入数据时可以设置为-1。
curl -XPUT http://localhost:9200/index/_settings -d '{"index" : {"refresh_interval" : "-1"}}'
bulk使用建议
每个请求大小建议在5-15MB,逐步增大测试,当接收到EsRejectedExecutionException,就说明已经到达节点的瓶颈了,就需要减少并发或者升级硬件增加节点
当写入数据时,确保bulk请求时轮询访问所有节点,不要发送所有请求到一个结点导致这一个节点要在内存存储所有请求的数据去处理
优化磁盘IO
使用SSD
使用RAID 0,不用镜像备份,用replicas保证数据正确性,增大磁盘IO
使用多个磁盘给Elasticsearch访问,通过在path.data中添加
不使用远程存储,如NFS/SMB/CIFS;延时将成为性能瓶颈
段合并
段合并是很消耗计算资源和磁盘IO的操作,特别是出现比较大的段合并。
当出现段合并的速度落后于索引写入的速度,Elasticsearch为了避免出现堆积的段数量爆发,会降低单个线程的索引写入速度,并且会在INFO的log里记录"now throttling indexing"
Elasticsearch默认比较保守,不想让搜索的性能被后台的段合并影响,默认的段合并速率限制比较低,默认是20MB/s,但如果使用的是SSD,可以考虑把这个参数设置到100-200MB/s
PUT /_cluster/settings { "persistent" : { "indices.store.throttle.max_bytes_per_sec" : "100mb" } }
如果你只是用bulk导入数据而不关注查询性能,可以关闭合并的阈值
PUT /_cluster/settings { "transient" : { "indices.store.throttle.type" : "none" } }
然后在导入完数据之后恢复成“merge”来恢复这个阈值设置
如果是机械硬盘,你需要增加下面的配置到elasticsearch.yml中
index.merge.scheduler.max_thread_count: 1
机械硬盘的并发IO性能较差,我们需要减少每个索引并发访问磁盘的线程数,这个设置会有max_thread_count+2个线程并发访问磁盘
如果是SSD可以忽略这个参数,默认线程数是Math.min(3, Runtime.getRuntime().availableProcessors() / 2),对于SSD来说没有问题。
可以增大index.translog.flush_threshold_size参数,默认是200M,可以增大到如1GB。增大这个参数可以允许translog在flush前存放更大的段(segment);更大的段的创建会减少flush的频率,并且更大的段合并越少,会减少磁盘IO,索引性能更高。
关于段合并的内容,可以查看文集中的其他文章。
其他优化
如果不需要实时精确的查询结果,可以把每个索引的index.refresh_interval设置为30s,如果在导入大量的数据,可以把这个值先设置为-1,完成数据导入之后在设置回来
如果在用bulk导入大量的数据,可以考虑不要副本,设置index.number_of_replicas: 0。有副本存在的时候,导入数据需要同步到副本,并且副本也要完成分析,索引和段合并的操作,影响导入性能。可以不设置副本导入数据然后在恢复副本。
如果导入的文档没有唯一的ID,可以使用Elasticsearch自动生成的唯一ID
性