目录
一些旧的工具
Ø elastic-hq:性能分析
Ø cerebro:索引管理、settings
Ø whatson:segment分析
Ø es cat api
ES慢日志
合理的控制index
ES写入参数调整
GET _all/_settings
PUT _all/_settings
{
"index.translog.durability" : "async",
"index.translog.flush_threshold_size" : "256mb",
"index.translog.sync_interval" : "60s",
"index.refresh_interval" : "60s"
}
索引设置
◦ 索引刷新间隔 index.refresh_interval 为30s或更大
◦ 事务日志持久化模式 index.translog.durability 为 async
◦ 推迟分片分配 index.unassigned.node_left.delayed_timeout 为 10m
◦ 合并线程数 index.merge.scheduler.max_thread_count 对机械硬盘为1
◦ 限制节点分片数 index.routing.allocation.total_shards_per_node 一般为1或2
◦ 设置合理的refresh时间 index.refresh_interval: 300S
◦ 设置合理的flush间隔 index.translog.flush_threshold_size: 4g index.translog.flush_threshold_ops: 50000
◦ 适当增加索引限制 indices.store.throttle.max_bytes_per_sec: 60mb
◦ 适当提高bulk队列 threadpool.bulk.queue_size: 1000
ES什么时候会平衡分片
"cluster.routing.allocation.balance.shard":"0.45f",//定义分配在该节点的分片数的因子 阈值=因子*(当前节点的分片数-集群的总分片数/节点数,即每个节点的平均分片数)
"cluster.routing.allocation.balance.index":"0.55f",//定义分配在该节点某个索引的分片数的因子,阈值=因子*(保存当前节点的某个索引的分片数-索引的总分片数/节点数,即每个节点某个索引的平均分片数)
"cluster.routing.allocation.balance.threshold":"1.0f",//超出这个阈值就会重新分配分片
"cluster.routing.allocation.total_shards_per_node":-1,//单个节点的最大分片数
//Disk-based Shard Allocation
"cluster.routing.allocation.disk.threshold_enabled":true,//是否开启基于硬盘的分发策略
"cluster.routing.allocation.disk.watermark.low":"85%",//不会分配分片到硬盘使用率高于这个值的节点
"cluster.routing.allocation.disk.watermark.high":"90%",//如果硬盘使用率高于这个值,则会重新分片该节点的分片到别的节点
"cluster.info.update.interval":"30s",//当前硬盘使用率的查询频率
"cluster.routing.allocation.disk.include_relocations":true,//计算硬盘使用率时,是否加上正在重新分配给其他节点的分片的大小
Merge对写入速度的影响
now throttling indexing: numMergesInFlight=6, maxNumMerges=5 什么鬼?
◦ Merge速率落后新segment生成速率
◦ ES开始限制新数据写入速率,防止segment files explosion
◦ 集群可能负载过高 ,如高开销的搜索进行中
◦ 也可能是集群硬件配置太好,默认的merge rate(20MB/s)设置太保守,可适当提高
◦ 调高索引的refresh interval和translog flush size可避免过多小segment file写到磁盘,减少小文件 merge频率
lucene merge的困扰
有限的机器资源第⼆个跳出来出问题是cpu,24 core 机器 cpu load达到200,最⾼500。
问题根源:
1.Lucene 索引同时只能由⼀个线程执⾏写操作
2.lucene要根据条件进⾏索引段合并(merge),以提⾼查询效率 当如此⼤的数据量⼀旦触发merge滚雪球效应的时候,可能会持续⼏分钟。导致后续发送过来的数据等待写⼊,同 时数据也会挤压在内存,也会导致内存问题。
优化⽅向:
1.将⼀次⻓merge合并操作尽量分散在多次merge合并操作中调整lucene merge操作相关参数
2.将⽇志量⼤的应⽤分布到多个lucene 索引中,同时避免不同⼤应⽤分布到相同 lucene 索引上。
| 调整参数 | 说明 | 调整前 | 调整后 |
|---|---|---|---|
| mergeFactor | 当⼤⼩⼏乎相当的段的数量达到此值的时候,开始合并 | 20 | 10 |
| maxMergeSize | 当⼀个段的⼤⼩⼤于此值的时候,就不再参与合并 | 4G | 3G |
索引写入不稳定
针对大索引:
max_merge_at_once: 10
max_merged_segment: 10gb
segments_per_tier: 10
floor_segment: 20mb
针对小索引:
max_merge_at_once: 30
max_merged_segment: 5gb
segments_per_tier: 30
floor_segment: 10mb
避免使用 cache
Sort、Aggregation需要uninvert the inverted index
• 这个过程需要做解析和类型转换,开销高
• 因此结果会被cache起来加速
• Field cache会为被搜索的索引全量构造,而不是 只为match的doc id构造
• 大索引构造fieldcache容易引起长时间Old GC,甚 至OOM
• 在进行检索和聚合操作时,ES会读取反向索引,并进行反向解析,然 后进行排序,将结果保存在内存中。这个处理会消耗很多Heap,有必 要进行限制, 不然会很容易出现OOM,限制Field Data的Heap Size的使用
indices.fielddata.cache.size: 40%
indices.breaker.fielddata.limit: 50%
Doc Values
• Indexing时构造在磁盘上
• 顺序扫描,对文件系统cache友好
• 热数据访问等同于直接读写内存
• ES 2.0成为默认设置,之前版本需手动开启
• Analyzed String fields不支持Doc Values
• 关闭_all字段
避免对分词字段排序
• Kibana对所有字段都可排序
• 但分词字段排序其实毫无意义
• 由于DocValues无法作用于分词字段,只能临时构造放到 cache
• 分词字段词典一般很大 • 可能导致长时间GC甚至OOM
解决办法:
• 利用multifield,默认字段名不分词
• 教育用户
• Hack kibana,对分词字段禁用排序
避免deep pagination
GET /_search?size=5&from=100005
1. 每个shard需要返回top 100010给请求结点。
2. 请求的结点合并所有结果,排序后返回其中5条!
大量拉数据
eg:用户通过一次API调用拉取1000万条数据导致结点OOM,集群罢工
正确方法:
◦ Scan & scroll API分批次拉取
◦ 类似数据库cursor
◦ 数据不排序,资源消耗低
索引太大搜索慢怎么办
选定数据可以分片的维度,然后: 将选定维度设置为routing key,将同一个key的数据route到同一个shard
◦ 前提是routing key的基数(cardinality)要高,shard数量要少
◦ 否则可能导致数据分布不均,从而产生热点问题
◦ 脑洞大开的讨论: engineering.datarank.com/2015/06/30/…
按照选定维度切分成不同的索引
◦ 切成过多的索引会导致集群状态信息过大
GC优化
有时可能因为gc时间过长,导致该数据节点被主节点踢出集群的情 况,导致集群出现不健康的状态,为了解决这样的问题,我们适当 的调整ping参数。
discovery.zen.fd.ping_timeout: 40s
discovery.zen.fd.ping_interval: 5s
discovery.zen.fd.ping_retries: 5
调整所有client和数据节点的JVM新生代大小 数据节点young gc频繁,适当调转新生代大小(-Xmn3g),降低young gc的频率
参考资料:
部分摘自京东ELK平台建设
摘部分自携程日志平台建设
部分摘自饿了么日志平台建设
部分摘自华泰证券日志平台内部分享