正文
不过,geo_point 禁用了doc_values,有些一般查询仍然有效。
13、indices.fielddata.cache.expire 配置移除(默认会忽略)。
二、升级之路
1、IO 压力增大
2.0 刚出的时候,我们进行了测试,发现 IO 压力有点大。启用比不启用 doc_values,IO 压力要增加一倍以上(测试磁盘非 SSD)。
2.0 初始版本,Delete 会导致 IO 压力更大,删除操作会有 translog 等诡异问题。
解决办法:建议升级到较高版本,如 2.2 及以上。
2、Index 速度变慢。
在 1.x 时候,我们没有启用 Bulk 接口,而是使用 Index 接口,升级后发现更新速度比较慢。我们改用 Bulk 接口以解决这个问题。
3、Bulk 接口的问题
如果使用 Bulk 接口来进行删除,建议升级到较高版本,因为 2.0 初始版本 Bulk delete 可以不需要提供 routing,但是这样性能也很差。较高版本修复了这个问题,删除一个 DOC,需要提供 routing。
其实要获得 routing 并不困难,2.x 在你查询的时候,提供的结果中,就有 routing 这个数据,这个对于做删除操作还是比较方便的,不需要进行计算,还能保证在 routing 频繁变化后删除干净。
3、Doc Values
Lucene 索引是一种倒排索引,当需要进行排序或者计算时,需要在内存中使用 fielddata cache 进行计算,极端情况下,可能导致 OOM 或者内存泄露。这时候可以考虑启用 doc_values,这个是索引时候已经进行处理的一种非倒排索引。启用 doc_values,性能有一点损失,但是可以设置较小的 heap size,而留下内存给系统缓存 doc_values 索引,性能几乎相当。
1)启用 doc_values 后,Index size 增加近一倍。
2)启用 doc_values ,当进行 aggs,sort 时,减少内存需求,减低 GC 压力。可以设置较小的 heap size。
3)启用 doc_values 后,当 Lucene 索引有效使用系统缓存时,性能几乎相当。
4)2.x 你仍然可以 Disable doc_values,设置一个较大的 heap。只要没有较大的 GC 问题,选择 disable doc_values 是可以的,而且带来的好处是索引较小。这是一个平衡选择,大家可以根据平时使用情况进行调整。我们选择了 disable doc_values 以减少索引大小。
4、GC 各种挂、挂、挂。
在 1.x 升级到 2.x 的过程,基于集群只能滚动式升级,这决定 1.x 和 2.x 集群是同时共存。而在升级过程中,不幸躺着中枪,频繁遇到 GC 问题,几乎导致升级失败。
首先我们尝试了进行 GC 调优,CMS,G1,调整 heap size,heap NEW size ….,各种策略均告失败。调整 thread pool 各项参数,对 query:size 过大数字也进行调整,以减少 GC 压力,这些调整也均失效。
具体表现为,运行一段时间后,集群中某些 Node 的 CPU Usage 会突然上升,最后 JVM 保持在 100% CPU Usage,集群 Node 因为长期下线,被集群踢出,如果运气好,Node 还会回来,大部分情况下它就保持在 100% CPU Usage 不死不活。
检查日志,并无 OOM,而显示 GC 问题很大,在几次 CMS GC (new heap) 后,发生 Full GC,并且 Heap 使用率一直保持 90% 左右,GC 进入死循环。
一开始,判断是 GC 问题,故而一直进行 GC 调优,未果。
当我们遇到 JVM GC 时,很可能并非 GC 策略本身问题,而可能是应用的 BUG。最后,我们不得不另寻出路。
1)对 Cache (Static 配置,需要配置在 elasticsearch.yml 并重启) 和 Circuit breaker 配置进行调整。如下:
Static 配置:
indices.queries.cache.size
indices.cache.filter.size
indices.queries.cache.size
indices.memory.index_buffer_size
Circuit breaker 配置:
indices.breaker.request.limit
indices.breaker.fielddata.limit
indices.breaker.total.limit
前者和后者中相关的配置需要保持前者小于后者。
调整这些数据,未果。
2)Mapping 过大?
我们的 Mapping 确实比较大,因为业务处理逻辑复杂,各种名字的字段没有明确的限制,所以 Mapping 是比较大的。在 Mapping 很大的时候,当一个新的字段进行索引,每个索引都要进行 mapping 更新,可能会导致 OOM。不过我们观察到我们的 GC 问题和索引更新并没有很明显的联系,因为我们在进行索引初始化时,快速 Bulk 索引也只是 LA 比较大,并无 GC 问题,再一个在 1.x mapping 也没有什么问题。
3)Shards 太多?
shards 过多,也是可能导致 GC 问题的。因为每个 shard 的内存使用控制变得复杂。尽管我们某些集群的 shards 数量较多( shards 90 * 2 = 180 个 shard),但尝试调整或合并 Shards,均告无果。
4)Doc_values 和 fielddata cache 选择
因为 GC 这种问题,所以我们尝试减少 JVM 的内存使用,降低 GC 压力。启用 doc_values后,Heap 内存占用变小,但不能解决这个问题。减小 Heap 大小,以减轻 GC 压力,也无法解决这个问题。
5) Filtered Query 兼容之坑
我们对 1.x 和 2.x 集群加上了版本区分。在 2.x 的情况下,我们对查询进行了强制修改。修改办法就是上面提到的 Filtered Query 变更。即取消 filtered 而使用 bool 来进行代替。GC 问题得到缓解。
6)Aggerations histogram
我们经过仔细对比 1.x 和 2.x,对于 aggs histogram 的默认值变化(doc_min_count从1到0),一开始并没有重视,后来显式的设置这个参数为 1。GC问题得到解决。
上面的 5)6) 就是 GC 问题两个很深的坑。
虽然他们算不上是 BUG,然而在 filtered query 只是 deprecated,而不是不能使用的情况下,这也太坑人了,遇到需要多集群滚动式升级的(比如我们),可能就会沿用 filtered query,以便能平滑升级,然后就会掉进深坑而不能自拔。
而 6)也算不上是 BUG,不过对于 doc_min_count = 0,大概率会触发 GC,使用任何 GC 策略都不能正常使用。