如果是在一个index-heavy的环境下,也许可以考虑牺牲部分查询的性能来满足index性能的提升,这种情形下,多半查询是非常稀少的,可以容忍结果返回的合理延时。这种特殊的应用场景,有一些措施可以用来提升index的性能。
1:科学的性能测试
导致性能低下可能有许多原因,定位影响最大的因素。
(1)一个node,一个shard,没有replicas,进行性能测试。
(2)全部用default值,得出性能基线,作为衡量性能的依据。
(3)长时间的测试(30+minites),一些事件诸如GC,merge等并不会立马发生。
(4)在default基础上,开始逐个修改,如果性能提升,则保留,然后继续修改其他影响因子。
2:用bulk方式
显而易见,bulk request可以提升index的性能。Bulk size取决于你的数据、分析器、集群配置等,但是一个好的开始是每次buck5-15m的数据,注意这是物理大小。document数目并不是一个好的buck的标准。比如:每次buck1000document,如果单个document是1k,则是1m,如果单个document是100k,则每一个是100m。因此,这个差距是相当大的。buck需要加载到内存中,因此,物理大小相比document的数量而言,具有更大的重要性。以5-15m为基线开始测试,缓慢增加,直到性能不能再提升为止。之后,开始增加buck操作的并行度,比如多线程。
用marvel或者iostat等工具,监控node,来发现是哪一种资源开始出现瓶颈。如果开始收到EsRejectedExecutionException,说明集群的某些资源开始出现了问题,这时候应该考虑减小并发度。
3:存储
(1)用ssd(用不起哈哈)
(2)用RAID0,Striped RAID会提升disk io,也引进了潜在的问题(a drive dies)。不要用mirrored or partity RAIDS,因为replicas提供了这个功能。
(3)用mutiple drivers,通过指定多个path.data让es可以将数据分不到不同的地方。
(4)不要用remote-mounted storage,诸如NFS/SMB/CIFS.
(5)用过用的是EC2,请注意EBS。即使是ssd-based EBS的options也会比local drivers慢一些。
4:段数目和merge操作
segment merge操作非常昂贵,会吃掉大量的disk io。merge操作是在后台被调度,因为执行时间会比较久,尤其是比较大的segment。这样是合理的,因为大segment的merge操作是相对较少的。
但是有时候merge操作会落后与index的摄入量。如果出现这种情况,es会自动限制index request只用一个线程。这会防止segment爆炸(在被merge前出现了大量的segment)。es在发现merge操作落后与index的摄入量的时候,日志中会出现以“now throttling indexing”开头的INFO日志。es的默认设置对此是有考虑的:不想让search的性能受到merge的影响,但是在一些情况下(比如ssd,或者index-heavy),限制设置的上限确实有些低。默认是20mb/s,对于splnning disk而言,这个默认值非常合理。如果是ssd disk,可以考虑增加到100-200mb/s,对应设置项为indices.store.throttle.max_bytes_per_sec:"100mb",逐个测试哪一个具体的数值更合适一些。如果是在做buck操作而无需考虑search性能的情况狂下,你当然想要让index的性能达到disk的极限了,因此设置indices.store.throttle.type:"none"。完全禁止merge。当index结束后,重新开启即可。如果是在使用spinning disk而非ssd,在elasticsearch.yml中增加以下设置:index.merge.scheduler.max_thread_count:1。Spinning disk在处理并发io的时候较慢,因此需要减少访问disk的并发线程数。上述设置将会允许3个thread。如果是ssd的话,可以忽略,默认的设置工作的就很好,Math.min(3,Runtime.getRuntime().availableProcessors()/2)。最后,调整index.translog.flush_threshold_size,默认200mb,比如增加到1gb。这样会使得大的segment在flush之前先在内存中聚合。通过生成更大的segment,减少flush的频率,同时较少了merge的频率。
以上所有的措施都在致力于较少disk io,以提升index性能。
5:其他
(1)index.refresh_interval。设置为-1,待index结束后重新设置回来。前提是对search并不要求near-realtime的准确性。
(2)buck操作过程中设置index.numer_of_replicas为0。如果不为0的时候,整个document被发送到replicas所在节点,index process会再次执行,这也就以为着每一个replica都会执行analysis、index和潜在的merge。如果设置为0,等待结束后,然后再设置为合理的值,只是执行字节对字节的copy,这将会更高效。
(3)如果业务不需要显式的指定id,请用es自动生成的id。这避免了version lookup,因为自动生成的id是唯一的。
(4)如果使用自定义的id,请使用零填充序列的id、UUID-1和nanotime。这些id是一致连续的格式,压缩效果更好。相反的,UUID-4是完全随机的,压缩效果不好因此会锁好lucene的性能。