1、使用 bulk 批量写入
你如果要往es里面灌入数据的话,那么根据你的业务场景来,如果你的业务场景可以支持让你将一批数据聚合起来,一次性写入es,那么就尽量采用bulk的方式,每次批量写个几千条这样子。
bulk批量写入的性能比你一条一条写入大量的 document 的性能要好很多。但是如果要知道一个bulk请求最佳的大小,需要对单个 es node 的单个 shard 做压测。
先 bulk 写入 100 个 document,然后 200个,400个,以此类推,每次都将 bulk size 加倍一次。如果bulk写入性能开始变平缓的时候,那么这个就是最佳的bulk大小。
并不是 bulk size 越大越好,而是根据你的集群等环境具体要测试出来的,因为越大的 bulk size 会导致内存压力过大,因此最好一个请求不要发送超过 10MB 的数据量。
先确定一个是 bulk size,此时就尽量是 单线程,一个es node,一个 shard,进行测试。看看单线程最多一次性写多少条数据,性能是比较好的。
2、使用多线程写入 elasticsearch
单线程发送bulk请求是无法最大化es集群写入的吞吐量的。
如果要利用集群的所有资源,就需要使用多线程并发将数据bulk写入集群中。
为了更好的利用集群的资源,这样多线程并发写入,可以减少每次底层磁盘 fsync 的 次数 和 开销。
首先对单个es节点的单个shard做压测,比如说,先是2个线程,然后是4个线程,然后是8个线程,16个,每次线程数量倍增。
一旦发现es返回了 TOO_MANY_REQUESTS 的错误,JavaClient也就是 EsRejectedExecutionException。
此时那么就说明 es 是已经到了一个并发写入的最大瓶颈了,此时我们就知道最多只能支撑这么高的并发写入了。
3、禁用一些无用字段
1. 关闭 _all 配置选项,降低内存使用量以及提升写入速度
2. 内存是宝贵的,每次创建索引的时候要做到充分利用,即
<1. 有的字段不用的我们坚决不索引
<2. 各个字段含义清晰就设置为最小类型
<3. 有些大文本字段如果只用于召回,不用于返回数据,尽可能的只索引不存储
4、refresh 和 replia
这要分两种情况来对待,分别为:全量重建索引 和 实时增量索引
全量重建索引
可以禁止 refresh 和 replica,即 index.refresh_interval = -1 & index.number_of_replicas = 0
<1. 此时就不需要创建 segment file,对应文件句柄少了,所消耗的资源也会降低很多
<2. 创建的 segment 文件少了,对应 merge 的压力也会降下来
<3. 不需要将数据复制到其他的 replica shards 上面去,降低了保证数据一致性的耗时
此时写入的速度会非常快。
一旦写完之后,我们做完对应的 merge optimization 优化就可以将相关参数复原。
实时增量索引
默认的refresh间隔是 1s,用 index.refresh_interval 参数可以设置,这样会其强迫 es 每秒中都将内存中的数据写入磁盘中,创建一个新的segment file。
正是这个间隔,让我们每次写入数据后,1s以后就可以看到。
但是如果我们将这个间隔调大,比如30s,可以接受写入的数据30s后才看到,那么我们就可以获取更大的写入吞吐量,因为30s内都是写内存的,每隔30s才会创建一个segment file。
5、使用自动生成的 id
如果我们要手动给 es document 设置一个id,那么 es 需要每次都去确认一下那个id是否存在于相同的分片中,这个过程是比较耗费时间的。
如果我们使用自动生成的id,那么es就可以跳过这个步骤,写入性能会更好。对于你的业务中的表id,可以作为 es document 的一个 field。
6、用性能更好的硬件设备
可以使用性能更好的 SSD 磁盘来替代 机械磁盘