ES原理剖析
特性
es重度使用了文件系统缓存,即:pacache.
es名词解释
Cluster:ES集群,由多个Node组成.
Node:节点,一个es实例就是一个node.
index:索引,一系类Documents的集合.对于存入的数据,都会有一个索引对应.
shard:分片.每个索引都会被分为多个分片,默认是5个.存储在不同的节点上.
replica:副本,容灾.默认会有5个副本.副本和分片不会出现在同一个node上.
新增数据集群调度
对于每条数据,都会给其分配_id,而数据分配到哪个节点就是根据这个参数计算.
根据id定位分片:
//节点0,1,2,3 主分片数
shard = hash(_id) % number_of_primary_shards默认情况下,每个索引会建立5个主分片.

在客户端请求写入数据时,流程如上图.
请求由master节点处理.
mater是node1.
master经过_id计算shard,发现算出来是shard1,则根据集群中的信息寻找shard1存在了node2节点上,将请求转发到node2.
node2数据处理完后,告诉node3进行副本数据同步.
node3数据备份完成后,告知node2.
node2返回master节点node1,从而通知客户端数据写入成功
对于副本,在同步大文件时,可以先取消副本,然后在同步完成后开启,从而减少segment归并时产生的消耗.
# curl -XPUT http://127.0.0.1:9200/索引_2020-04-01/_settings -d '{
"index": { "number_of_replicas" : 0 }
}'新增数据,节点策略

主要有3个阶段
内存阶段
新增数据到内存,同时生成translog事物日志.此时不可被搜索.
refresh阶段
每隔1秒执行一次refresh操作.将内存中的数据生成一个segmanet,存储到文件系统缓存中.此时,数据就可以搜索了.
es提供了主动刷新数据的接口:/_refresh.
如果感觉1s时间刷新太长,可以在更新完数据后,调用此接口进行数据刷新,使其可被搜索.如果在同步大量数据时,在这期间不关心是否可被搜索,提高同步效率,可以使用
# curl -XPOST http://127.0.0.1:9200/索引_2020-04-01/_settings -d'
{ "refresh_interval": "10s" }
'根据情况降低刷新次数.
或者可以在同步历史数据时,将refresh关闭.
# curl -XPUT http://127.0.0.1:9200/索引_2020-04-01 -d'
{
"settings" : {
"refresh_interval": "-1"
}
}'等同步完成后,在手动执行refresh,使其可被搜索.
# curl -XPOST http://127.0.0.1:9200/索引_2020-04-01/_refreshflush阶段
默认每隔30分钟,或者translog文件达到了512MB,就执行一次flush操作.把文件系统缓存中的segment文件,持久化到磁盘.完成后,同时清空translog文件.
对于时间间隔和大小,可以进行设置:
//flush时间间隔
index.translog.flush_threshold_period
//触发flush文件大小
index.translog.flush_threshold_size数据持久化完成.
数据的维护
数据存到系统中了,就需要对数据进行维护,来解决在录入数据时产生的负作用,比如,refresh会每秒生成一个segment文件,如果要对数据检索,就要挨个检查这些文件,显然是及其浪费资源的.为了解决这个问题,使用文件归并策略.
Segment归并
在文件系统缓存中,会根据一些策略对其中的segment文件开启一些线程进行归并.归并完成后刷新到磁盘,将请求从小segment切换到归并后的segment后,删除旧的segment.
相关参数设置:
index.merge.policy.floor_segment
默认2MB,小于这个大小的segment会优先被归并.
index.merge.policy.max_merge_at_once
默认10个.一次默认归并多少个segment.
index.merge.policy.max_merge_at_once_explicit
默认30个.在forcemerge时,一次会归并多少个segment.
index.merge.policy.max_merged_segment
默认5GB.大于这个的segment,不会参与归并.forcemerge除外.
由于归并非常消耗IO和CPU,因此,默认会使用 Math.min(3,Runtime.getRuntime().availableProcessors() / 2)个线程来进行归并.CPU核数大于6时,会启动3个归并线程.
//最大归并线程数量
index.merge.scheduler.max_thread_count数据均衡
为了保护安全,每隔30s会检查下各节点磁盘使用量.如果超过了85%,新索引分配就不会在分配到这个节点.超过了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"
}
}'数据的查询
query阶段
1.新请求到达任一节点,作为协调节点.
2.协调节点将请求分发到该索引的所有主分片或者分片副本(负载均衡).
3.每个分片在本地进行查询,得到id列表和排序值.
4.协调节点收到列表和排序值,合并到自己的优先队列中,进行全局分页排序.
fetch阶段
协调节点根据合并后的id列表,向相关节点发送get请求获取详细数据.
shard分配策略
索引的shard分配到哪个节点上,通常由es自动决定.以下会触发分配动作.
新索引的生成.
索引的删除.
新增副本分片.
节点增减引发的数据均衡.
ES运维
分片数据移动
因为负载过高,磁盘利用率过高,服务器下线,更换磁盘等原因,可以会需要从节点上移走部分分片数据:
curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
"commands" : [ {
"move" :
{
"index" : "索引_2020-04-01", "shard" : 0, "from_node" : "10.19.0.81", "to_node" : "10.19.0.104"
}
}
]
}节点下线
Elasticsearch 集群就会自动把这个 IP 上的所有分片,都自动转移到其他节点上。等到转移完成,这个空节点就可以毫无影响的下线了。
curl -XPUT 127.0.0.1:9200/_cluster/settings -d '{
"transient" :{
"cluster.routing.allocation.exclude._ip" : "10.0.0.1"
}
}'数据冷热分离方案
Elasticsearch 集群一个比较突出的问题是: 用户做一次大的查询的时候, 非常大量的读 IO 以及聚合计算导致机器 Load 升高, CPU 使用率上升, 会影响阻塞到新数据的写入, 这个过程甚至会持续几分钟。所以,可能需要仿照 MySQL 集群一样,做读写分离。
实施方案
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"
}
}
}
}
}'这样,写操作集中在 N 台热数据节点上,大范围的读操作集中在 M 台冷数据节点上。避免了堵塞影响。
Last updated
Was this helpful?