背景
智算轻量化版本需要透出用户任务日志给终端用户. 任务日志存储在ElasticSearch中, 智算后端通过ES API接口查询任务日志, 展示在智算开发平台. 由于轻量化版本硬件资源限制, ES集群的配置较低, 随着日志量上升, 接口查询性能遇到明显瓶颈, 频繁出现接口超时报错.
ES 配置: 4C12G, 3节点; 日志量: 15G/天
优化步骤
基于以上背景着手优化. 优化过程经历了如下步骤
- 网络超时配置优化
- 服务端查询条件优化
- ES性能优化
1. 网络超时配置优化
查看服务端报错日志, 在调用ES查询接口时出现SocketTimeoutException, 初步怀疑是网络不稳定导致socket超时. 考虑提高超时时间配置.
ES客户端关于网络超时时间的配置有如下三个:
- socketTimeout: 查询请求获得ES响应的超时时间
- connectTimeout: 和ES简历连接的超时时间
- connectionRequestTimeout: 从连接池获取连接的超时时间
也是http请求常用的三个超时配置, 这三个配置值默认都是5s. 从错误日志可以看出是从ES获得响应的时间超过5s, 而创建连接和获取连接都没超时. 因此修改socketTimeout 为 15s, 验证效果. 改完发现超时错误确实少了一点, 但依然会偶尔发生, 没有解决根本问题.
2. 服务端查询条件优化
15s依然超时, 意味着查询耗时太高, 需要优化查询本身的性能. 分析代码发现日志查询时间默认是一个月前到当前时间, 而实际用户任务启动的时间集中在最近两三天, 因此考虑缩短查询时间范围, 从任务启动时间开始查询. 测试结果发现优化效果不明显, 依然有15s以上的超时, 尤其是第一次查询时, 耗时普遍超过10s, 后续查询降到3s上下.
3. ES性能优化
以上两个优化只是缓解了部分问题, ES查询性能差这个根本问题还是没解决. 分析ES集群发现如下问题
- 集群配置虽然不高, 但是三个节点, 每个节点12G内存, 完全支撑的了15G日志的查询, 集群性能配置不应该是瓶颈
- 第一次查询性能差, 说明第一次查询很可能是从磁盘读取数据, 也就是说ES没做热数据缓存, 每次都是从磁盘现读的冷数据
- 后续查询降低到3s, 说明查询结果有缓存, 但是性能依然太差, 原因不确定
查看索引配置, 发现如下问题, 并针对性优化
- 日志索引字段太多, 有150+字段, 而接口查询实际用到了5个字段
- 原因: ES 默认会为采集的数据创建字段, 需要关闭动态匹配
- 优化方式: 关闭动态匹配
- 日志中有很多和后端服务不相干的内容, 采集了很多中间件的日志
- 原因: filebeat日志采集集群内所有容器日志, 没有针对容器进行过滤
- 优化方式: 采集规则针对pod名称, namespace进行过滤
- 索引配置了1个分片, 意味着搜索动作只会在一个节点是执行, 没有利用ES分布式查询的能力, 这也能解释上面的问题3, 在有缓存的情况下, 查询耗时依然打到秒级
- 原因: 创建索引时没有配置分片数
- 优化修改分片数为3
- 索引生命周期状态都是cold, 意味着数据没有做冷热划分, 所有日志都是冷数据, 每次新查询都需要从磁盘读取.
- 原因: ES默认不打开索引生命周期规则
- 优化: 根据业务需求, 最近3天数据设置为hot, 一周内数据设置为warm, 一周后数据为cold
- 索引中每个字段都默认打开了查询索引, 也会影响搜索性能
- 原因: ES 会为所有字段创建索引
- 优化: 配置字段时, 对不需要所属的字段关闭索引
结论
通过以上性能问题分析和优化, 业务日志查询耗时从平均15s下降到500ms以内, 显著优化了ES日志从查询性能, 提升用户使用体验.