ELKstack中文指南之elasticsearch架构原理
所属分类 elasticsearch
浏览量 2712
根据原文整理
https://elkguide.elasticsearch.cn/elasticsearch/principle/
ES 来源于作者 Shay Banon 的第一个开源项目 Compass 库,
而这个 Java 库最初的目的只是为了给 Shay 当时正在学厨师的妻子做一个菜谱的搜索引擎。
2010 年,ES 正式发布。
2015 年初,Elasticsearch 公司召开了第一次全球用户大会 。诸多 IT 巨头纷纷赞助,参会,演讲。
会后,Elasticsearch 公司宣布改名 Elastic,公司官网也变成 http://elastic.co/。
这意味着 Elasticsearch 的发展方向,不再限于搜索业务,也就是说,Elastic Stack 等机器数据和 IT 服务领域成为官方更加注意的方向。
随后几个月,专注监控报警的 Watcher 发布 beta 版,社区有名的网络抓包工具 Packetbeat、
多年专注于基于机器学习的异常探测 Prelert 等 ITOA 周边产品纷纷被 Elastic 公司收购。
架构原理 设计工作原理 性能调优,故障处理
全文索引 倒排索引
动态更新的 Lucene 索引 近实时索引
segment in-memory buffer translog
新收到的数据写到新的索引文件里。每次生成的倒排索引, 段(segment)
commit 文件,记录索引内所有的 segment。
生成 segment 的数据来源,是内存中的 buffer
数据写入过程
内存buffer
刷到文件系统缓存 (默认1秒刷一次)
flush到磁盘 同步更新commit 文件
commit point
主动调用 /_refresh接口 刷到文件缓存 ,保证搜索可见
5.0 ?refresh=wait_for,写入数据后不强制刷新但一直等到刷新才返回。
curl -XPOST http://127.0.0.1:9200/logstash-2015.06.21/_settings -d'
{ "refresh_interval": "10s" }
'
增加refresh时间间隔,降低实时性,提升写入性能
导入历史数据可以先完全关闭掉 refresh_interval 设置为 -1
导入完成后,手动调用
curl -XPOST http://127.0.0.1:9200/logstash-2015.05.01/_refresh
translog
flush ,把 segment 刷到磁盘,且 commit 文件进行更新的时候, translog 文件才清空。
/_flush 接口
默认每隔30分钟 flush一次
或者当 translog 文件大小大于 512MB (老版本是 200MB)时,主动进行一次 flush。
index.translog.flush_threshold_period
index.translog.flush_threshold_size
index.translog.flush_threshold_ops 每收到多少条数据后 flush 一次
索引数据的一致性通过 translog 保证。
默认情况下, 每隔 5 秒,或每次请求操作结束前,会强制刷新 translog 日志到磁盘上。
为了保证不丢数据,每次 index、bulk、delete、update 操作,触发刷新 translog 到磁盘上,才返回 200 OK。
提升性能可配置
index.translog.durability=async
分布式索引 分片 shard
为了做到近实时(realtime)搜索
默认每 1 秒,都会有一个新文件产生,每个文件都需要有文件句柄,内存,CPU 使用等各种资源。
后台 segment merge
将小的 segment 合并成大的segment 文件。
后台线程执行合并任务 消耗磁盘 IO 和 CPU
在 5.0 之前,合并线程的限速配置 indices.store.throttle.max_bytes_per_sec 是 20MB。
SSD 盘 ,写入性能高,可调整为 100M
curl -XPUT http://127.0.0.1:9200/_cluster/settings -d'
{
"persistent" : {
"indices.store.throttle.max_bytes_per_sec" : "100mb"
}
}'
throttle 节流
5.0 开始,ES 对此作了大幅度改进
使用了 Lucene 的 CMS(ConcurrentMergeScheduler) 的 auto throttle 机制,正常情况下已经不再需要手动配置 indices.store.throttle.max_bytes_per_sec 了
合并线程数 默认数目的计算公式是: Math.min(3, Runtime.getRuntime().availableProcessors() / 2)。
一般来说就是 3 个归并线程
index.merge.scheduler.max_thread_count
合并策略
index.merge.policy.floor_segment 默认 2MB,小于这个大小的 segment,优先被归并。
index.merge.policy.max_merge_at_once 默认一次最多归并 10 个 segment
index.merge.policy.max_merge_at_once_explicit 默认 forcemerge 时一次最多归并 30 个 segment。
index.merge.policy.max_merged_segment 默认 5 GB,大于这个大小的 segment,不用参与归并。forcemerge 除外。
减少 segment 合并消耗以及提高响应的办法
加大 flush 间隔,尽量让每次新生成的 segment 本身就比较大。
默认的最大 segment 大小是 5GB。
在负载较低的时间,通过 forcemerge 接口,强制合并 segment。
curl -XPOST http://127.0.0.1:9200/logstash-2015-06.10/_forcemerge?max_num_segments=1
由于 forcemerge 线程对资源的消耗比普通的合并线程大得多,因此绝对不建议对写入数据的热索引执行这个操作。
routing和replica的读写过程
shard = hash(routing) % number_of_primary_shards
每个数据都有一个 routing 参数,默认使用 _id 值。
索引的主分片数不可修改!!!
副本一致性
数据写入过程
客户端请求发送给 Node 1 节点,注意图中 Node 1 是 Master 节点,实际完全可以不是。
Node 1 用数据的 _id 取余计算得到应该讲数据存储到 shard 0 上。通过 cluster state 信息发现 shard 0 的主分片已经分配到了 Node 3 上。Node 1 转发请求数据给 Node 3。
Node 3 完成请求数据的索引过程,存入主分片 0。然后并行转发数据给分配有 shard 0 的副本分片的 Node 1 和 Node 2。当收到任一节点汇报副本分片数据写入成功,Node 3 即返回给初始的接收节点 Node 1,宣布数据写入成功。Node 1 返回成功响应给客户端。
wait_for_active_shards
2 个副本分片只要有 1 个成功,就可以返回给客户端了
one 写完主分片就返回,等同于 async
all 等所有副本分片都写完才能返回。
timeout 如果集群出现异常,有些分片当前不可用,默认等待 1 分钟看分片能否恢复。可以使用 ?timeout=30s 来调整
有些较大的索引,可以在做 forcemerge 前,先把副本全部取消掉,等 optimize 完后,再重新开启副本,节约单个 segment 的重复归并消耗。
curl -XPUT http://127.0.0.1:9200/logstash-mweibo-2015.05.02/_settings -d '{
"index": { "number_of_replicas" : 0 }
}'
shard 的 allocate 控制
由 ES 自动决定 ,以下几种情况会触发分配
新建索引
删除索引
新增副本
节点增减引发的数据均衡
cluster.routing.allocation.enable
all 默认
primaries
new_primaries
none 拒绝分片分配
集群升级时会使用该参数
cluster.routing.allocation.allow_rebalance
该参数用来控制什么时候允许数据均衡
indices_all_active 要求所有分片都正常启动成功以后,才可以进行数据均衡操作
cluster.routing.allocation.cluster_concurrent_rebalance
控制集群内同时运行的数据均衡任务个数。默认是 2 个。如果有节点增减,且集群负载压力不高的时候,可以适当加大。
cluster.routing.allocation.node_initial_primaries_recoveries
该参数用来控制节点重启时,允许同时恢复几个主分片。默认是 4 个。如果节点是多磁盘,且 IO 压力不大,可以适当加大。
cluster.routing.allocation.node_concurrent_recoveries
允许同时运行的数据恢复任务。默认是 2 个。
所以,节点重启时,可以看到主分片迅速恢复完成,副本分片的恢复却很慢。
除了副本分片本身数据要通过网络复制以外,并发线程本身也减少了一半。
这种设置也是有道理的,主分片一定是本地恢复,副本分片却需要走网络,带宽是有限的。
indices.recovery.concurrent_streams
该参数用来控制节点从网络复制恢复副本分片时的数据流个数。默认是 3 个。可以配合上一条配置一起加大。
indices.recovery.max_bytes_per_sec
该参数用来控制节点恢复时的速率。默认是 40MB。可以加大。
其他的分片分配策略。比如以 tag 和 rack_id 作为区分等
根据磁盘使用情况
cluster.info.update.interva
ES 会定时(默认 30 秒)检查各节点的数据目录磁盘使用情况。
cluster.routing.allocation.disk.watermark.low
超出该阈值 (默认 85%) ,新索引分片不会再分配到该节点上。
cluster.routing.allocation.disk.watermark.high
超出该阈值 (默认 90%) ,就会触发该节点现存分片的数据均衡,把数据挪到其他节点上去。
磁盘使用水位
curl -XPUT localhost:9200/_cluster/settings -d '{
"transient" : {
"cluster.routing.allocation.disk.watermark.low" : "85%",
"cluster.routing.allocation.disk.watermark.high" : "10gb",
"cluster.info.update.interval" : "1m"
}
}'
热索引分片不均
数据均衡策略以各节点的分片总数(indices_all_active)作为基准。
对于 Elastic Stack 场景,一般压力集中在新索引的数据写入方面。
正常运行的时候,也没有问题。但是当集群扩容时,新加入集群的节点,分片总数远远低于其他节点。
这时候如果有新索引创建,ES 的默认策略会导致新索引的所有主分片几乎全分配在这台新节点上。
整个集群的写入压力,压在一个节点上,结果很可能是这个节点直接被压死,集群出现异常。
预先计算好索引的分片数后,配置好单节点分片的限额。
一个 5 节点的集群,索引主分片 10 个,副本 1 份。则平均下来每个节点应该有 4 个分片,那么就配置:
# curl -s -XPUT http://127.0.0.1:9200/logstash-2015.05.08/_settings -d '{
"index": { "routing.allocation.total_shards_per_node" : "5" }
}'
注意,这里配置的是 5 而不是 4。因为需要预防有机器故障,分片发生迁移的情况。如果写的是 4,那么分片迁移会失败。
cluster.routing.allocation.balance.shard
节点上分配分片的权重,默认为 0.45。数值越大越倾向于在节点层面均衡分片。
cluster.routing.allocation.balance.index
每个索引往单个节点上分配分片的权重,默认为 0.55。数值越大越倾向于在索引层面均衡分片。
cluster.routing.allocation.balance.threshold
大于阈值则触发均衡操作。默认为1。
(indexBalance (node.numShards(index) – avgShardsPerNode(index)) + shardBalance (node.numShards() – avgShardsPerNode)) <=> weightthreshold
可以采取加大 cluster.routing.allocation.balance.index,
甚至设置 cluster.routing.allocation.balance.shard 为 0 来尽量采用索引内的节点均衡。
通过 reroute 接口,手动分片分配
reroute 接口支持五种指令:allocate_replica, allocate_stale_primary, allocate_empty_primary,move 和 cancel。
常用的一般是 allocate 和 move
因为负载过高等原因,有时候个别分片可能长期处于 UNASSIGNED 状态,
可以手动分配分片到指定节点上。默认情况下只允许手动分配副本分片(即使用 allocate_replica),
如果要分配主分片,需要单独加一个 accept_data_loss 选项
curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
"commands" : [ {
"allocate_stale_primary" :
{
"index" : "logstash-2015.05.27", "shard" : 61, "node" : "10.19.0.77", "accept_data_loss" : true
}
}
]
}'
allocate_stale_primary 表示准备分配到的节点上可能有老版本的历史数据,
运行时需要提前确认一下是哪个节点上保留有这个分片的实际目录,且目录大小最大。
然后手动分配到这个节点上。以此减少数据丢失。
因为负载过高,磁盘利用率过高,服务器下线,更换磁盘等原因,可以会需要从节点上移走部分分片:
curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
"commands" : [ {
"move" :
{
"index" : "logstash-2015.05.22", "shard" : 0, "from_node" : "10.19.0.81", "to_node" : "10.19.0.104"
}
}
]
}'
手工 reroute 失败,响应中会带上失败的原因
从 5.0 版本开始 ,新增 allocation explain 接口,专门用来解释指定分片的具体失败原因
节点下线
curl -XPUT 127.0.0.1:9200/_cluster/settings -d '{ "transient" :{ "cluster.routing.allocation.exclude._ip" : "10.0.0.1" } }'
自动把这个 IP 上的所有分片,都自动转移到其他节点上。等到转移完成,这个空节点就可以毫无影响的下线了。
冷热数据的读写分离
stale 不新鲜的
1 N 台机器做热数据的存储, 上面只放当天的数据。这 N 台热数据节点上面的 elasticsearc.yml 中配置 node.attr.tag: hot
2 之前的数据放在另外的 M 台机器上。这 M 台冷数据节点中配置 node.attr.tag: stale
3 模板中控制对新建索引添加 hot 标签
{ "order" : 0, "template" : "*", "settings" : { "index.routing.allocation.include.tag" : "hot" } }
4 每天计划任务更新索引的配置, 将 tag 更改为 stale, 索引会自动迁移到 M 台冷数据节点
curl -XPUT http://127.0.0.1:9200/indexname/_settings -d'
{ "index": { "routing": { "allocation": { "include": { "tag": "stale" } } } } }'
集群自动发现
ES 是一个 P2P 类型(使用 gossip 协议)的分布式系统,
除了集群状态管理以外,其他所有的请求都可以发送到集群内任意一台节点上,
这个节点可以自己找到需要转发的节点,并且直接跟这些节点通信。
所有配置了相同 cluster.name 的节点都自动归属到一个集群中。
从 2.0 版本开始,默认的自动发现方式改为了单播(unicast)方式。
考虑到节点有时候因为高负载,慢 GC 等原因可能会有偶尔没及时响应 ping 包的可能,
一般建议稍微加大 Fault Detection 的超时时间。
基于安全考虑,默认只监听本地 lo 地址
network.host: "192.168.0.2"
discovery.zen.minimum_master_nodes: 3
discovery.zen.ping_timeout: 100s
discovery.zen.fd.ping_timeout: 100s
discovery.zen.ping.unicast.hosts: ["10.19.0.97","10.19.0.98","10.19.0.99","10.19.0.100"]
discovery.zen.ping_timeout
仅在加入或者选举 master 主节点的时候才起作用
discovery.zen.fd.ping_timeout
在稳定运行的集群中,master 检测所有节点,以及节点检测 master 是否可用超时。
fd fault detection
运行间隔和重试次数
discovery.zen.fd.ping_interval: 10s
discovery.zen.fd.ping_retries: 10
上一篇
下一篇
elasticsearch aerospike kafka副本数设置
kafka副本机制
网络杠精定律
ELKstack中文指南之elasticsearch接口使用
时区知识点整理
YAML简单介绍