《Elastic Stack 实战手册》——四、应用实践——4.3 性能优化场景——4.3.3.Elasticsearch 性能优化之内存和熔断浅析(中): https://developer.aliyun.com/article/1225156?spm=a2c6h.13148508.setting.19.438f4f0e18NXNE
4.2 熔断器源码浅析
熔断器相关代码主要位于两个包中,包括熔断器接口、一些子类以及异常类和具体服务类等, 本节分别阅读两个包中的代码。
common.breaker
这里定义熔断器接口和两个实现类和异常类,具体如图 4 所示:
CircuitBreaker 中两个枚举定义了 breaker 细分类:
· enum Type {MEMORY,PARENT,NOOP}
· enum Durability {TRANSIENT,PERMANENT}
ChildMemoryCircuitBreaker 类 addEstimateBytesAndMaybeBreak() 方法判断是否请求需要 占用的 bytes 通过 memoryUserd() 计算后超过限制触发跳闸,如图 5 所示:
图 5 熔断器是否触发判断
例如:terms agg,会通过 BigArrays 这个工具类申请大数组来存放计算数据,在实际分配内 存之前,调用 adjustBreaker() 方法 (其内部调用 addEstimateBytesAndMaybeBreak() 方法) 将新申请数组的大小交给 ChildMemoryCircuitBreaker 来判断是否触发跳闸。
indices.breaker
主要包含具体的熔断服务类 HierarchyCircuitBreakerService,具体结构如图 6:
图 6 熔断器服务类
HierarchyCircuitBreakerService 内部类 MemoryUsage 实现父熔断器获取内存状态准则,如 图 7 所示:
图 7 父熔断器行为准则
currentMemoryUsage() 调用的即 JVM 底层的内容:
//构造 MemoryMXBean 调用 getUsed() MemoryMXBeanMEMORY_MX_BEAN = ManagementFactory.getMemoryMXBean(); return MEMORY_MX_BEAN.getHeapMemoryUsage().getUsed();//MemoryUsage
CircuitBreakerStats 类负责熔断器状态监控,_nodes/stats/breaker 调用。
图 8 熔断器状态
具体示例如下:
其中当前使用子熔断器均为自己统计,父熔断器采用 memoryUsed() 方式统计。触发次数为 AtomicLong 类型,每次触发熔断都会加 1,且会打印如下日志。
日志中会输出内存限制和使用数值信息和 label 信息,表示引起熔断具体原因:
· : 查询结果分片间聚合
· : agg 等申请的 BigArrays 过大
· : http 请求 content 过长
· "allocated_buckets" :桶太多了( search.max_buckets )
· ……
5. 小结
本篇文章旨在对 Elasticsearch 内存的使用情况和其在预防 OOM 设置的熔断机制进行简单的 分析,了解其中缘由有助于我们更好的优化 Elasticsearch 内存方面的配置,并在出现内存方 面的异常时更快的定位问题和找到解决办法。
由于作者能力有限,文章中存在的错误以及遗漏还望读者可以批评指出,共同学习,共同进步。
创作人简介:
齐乐,从事大数据开发工作近四年,主要方向为 ES,已通过 ECE 认证,近期在研究 Spark
和 Flink。欢迎一起学习,一起讨论,共同进步。