elasticsearch 原理
一.ES简介:
1. 名称解析
- Cluster
ES由个data节点和1个master节点构成ES 集群,ES集群具有容灾能力,官方建议的也是使用ES集群的方式来运维ES。 - Node
Node是ES的节点,一般集群会有1个master节点,多个data节点,ES节点有如下几种类型:
master节点
master的功能是维护ES集群的元数据,比如创建删除索引;监控其他的节点,比如对故障节点进行剔除和协调故障恢复工作;此外master节点还负责分片具体分配给哪些节点。因此在扩容和这故障的时候,分片迁移到哪台机器上也需要master来协调。
需要注意的是所有的涉及到路由变化的操作都必须master来做。
建议:master非常重要,比较大的集群建议讲master独立部署
data节点
data节点负责数据的存储和检索。
Coordinating节点
Coordinating节点不负责数据的存储,只负责请求的转发,有点类似于负载均衡器 - Shard
Shard是分片的意思,一般一个很大的表为了保证其扩展能力都会水平切分为多个分片,类似于mysql的水平分表的概念。每个分片只存储自己那部分的数据和索引信息,全部的分片数据的集合就是全量的数据。
因为分片建立以后,如果后面要增加分片,需要全量导入数据,因此分片必须在创建索引之前就规划好。具体的可以从索引的数据量、集群节点的个数和预计集群的规模等方面进行合理的评估。 - Replica
Replica副本,ES官方建议至少1副本,否则容易出现数据丢失的风险。在ES中副本主要有2个作用:
其一是提供数据安全性保障,其二副本也能够分担读的请求,提高ES的性能。 - Index
Index是索引的意思,和关系型数据库中的索引很不一样。ES中Index的概念类似于关系型数据库中的database。 - Type
Type是分类的意思,和关系型数据库中table的概念比较类似。为提高性能,建议最好是一个Index就存储一个Type的数据就好。 - Mapping
Mapping的概念和关系型数据库中的字段类型比较类似 - Document
ES是文档型的组建,Document类似于关系型数据库的一行。在ES中就是一个文档。 - gateway
gateway 代表 elasticsearch 索引的持久化存储方式,elasticsearch 默认是先把索引存放到内存中去,当内存满了的时候再持久化到硬盘里。当这个 elasticsearch 集群关闭或者再次重新启动时就会从 gateway 中读取索引数据。elasticsearch 支持多种类型的 gateway,有本地文件系统(默认),分布式文件系统,Hadoop 的 HDFS 和 amazon 的 s3 云存储服务。
2. 集群组成
从上图中可以看到,ES集群是由多个节点组成,上图中有1个master节点和2个data节点组成,并且创建了1个索引,索引有4个数据分片和1个副本组成。Translog为ES提供高性能以及数据安全保障。
二. 读写逻辑
1.写
ES的写入简图ES的写操作分为两类,一类是涉及到路由变更的索引创建和删除(简称为索引的写入),另一类是基于文档的创建、更新和删除(简称为文档的写入)。
下面单独来进行介绍:
1.索引的写入
无论是索引的创建还是删除,都必须在master上进行。因此,如果写入的请求是发到了非master节点,该节点会讲对应的创建或者删除的请求转发给master,master会创建并修改元数据和路由信息,并将对应的修改同步到其他的候选的master机器上,至少需要需要一半以上的候选master返回后才算写入成功。
2.文档的写入
文档的写入的前提是所有的写入都必须先发送到主分片上,大致的
步骤为:
a.文档写入请求发送到任意的一个节点
b. 节点根据shard = hash(routing) % number_of_primary_shards确定数据所在的分片以及根据元数据确认主分片是在哪台机器
c. 在主分片上执行写入操作和translog写入操作,并且将请求发送到副本上进行写入和translog写入
d. 默认是同步操作,必须主分片和副本分片都些成功财返回结果,也可以人为调整为异步操作,不过会有数据安全性问题。
注意:默认ES提供近实时的搜索,也就是说文档写入或者更新后不是马上就能搜索出最新的变更,默认需要过1秒reflush后才能看到,如果业务对实时性要求非常高,也可以将reflush的相关的参数设置为request,即有新的请求就执行reflush的操作,这种方式性能会比较差。此外你还可以调用reflush的API手动进行reflush的操作。
2.读
ES的读逻辑ES查询的时候如果指定了routing相关的值,就会只扫描确定的1个或者少数文档,如果没有指定routing相关的值就需要扫描所有的分片。因此还会涉及到查询的拆分和合并的步骤。详情如下:
-
查询请求发送到任意一个节点
-
如果指定了routing的相关值,根据shard = hash(routing) % number_of_primary_shards公式就能直接计算出请求的数据所在的分片,然后将请求发送到对应的分片就OK。如果指定routing的相关值,那么会发送到对应查询涉及到的所有分片(这就是请求拆分)。
-
如果查询只涉及到1个分片,查询的分片所在的机器返回查询结果到初始请求的节点,初始请求节点再将数据返回给业务。而如果查询涉及到多个分片,初始节点就会将请发送给多个分片并发查询,此时查询的分片所在的机器返回查询结果到初始请求的节点后,初始节点还需要再进行结果的合并。初始节点将合并后的数据返回个业务。
三.ES的容灾
ES有很完善的容灾机制,候选master一般有多个,data节点也有多个,因此节点异常的时候通过将访问切换到别的节点来容灾。具体流程包含如下几个流程:
-
故障发现
故障发现如下图所示:
从上图中可以看出,Master会去ping各个其他的节点,图中只画了datanode节点。而其他的节点也会去ping master节点,确认master节点是否正常。默认ping规则如下:
Discovery.zen.fd.ping_interval=1s #默认每隔1秒探测1次
Discovery.zen.fd.ping_timeout=30s #默认ping探测的超时时间为30秒
Discovery.zen.fd.ping_retry=3 #默认重试3次
- 节点切换
master节点切换
当其他节点探测到master异常并达到重试次数后,候选节点会进行竞争,选master的具体规则如下:
a. 每次选举每个节点会把自己所知道的候选master节点根据nodeid进行一次排序,然后选出第1个节点,暂且人为它是master节点;
b. 如果对某个节点的投票数达到 候选master数/2+1 个并且该节点也选举自己为master,那么这个节点即为master。否则重新选举;
(备注:之所以节点的投票数需要达到候选master数/2+1,是为了防止脑裂的问题发生)
data节点切换
当master节点检测到某个data节点有异常的时候,做的操作大致如下:
a.master剔除该data节点,如果ES数据配置了1份副本保存,此时不存在数据丢失的风险,集群状态为yelllow。如果数据没有配置副本保存,则存在数据丢失,集群状态为red。
b.master对找出异常的data节点对应的所有的数据分片,如果是主分片,则将其他节点上的副本分片提升为主分片,全部主分片恢复后,异常data节点涉及的数据读写都恢复正常。
c.业务恢复正常以后,master会将异常节点的数据迁移到正常的节点
d.全部数据迁移完成后,集群状态恢复为green
四、ES的扩容
ES设计成能让你灵活地扩缩容模型,当你添加或者减少data节点的时候,ES会自动的对数据进行均衡。如下几个简图能让你几秒钟了解ES的扩容问题,下面几个图的索引设置为number_of_shards=3 && number_of_replicas=1,即索引为3个分片并且每个分片有1个副本。
1.一个节点的ES Cluster
1 * node
从上图中可以看到虽然设置了1个副本,但是datanode1只分配了3个主分片。这是因为ES认为如果副本和主分片在1台机器上和没有副本的效果一样,当那台机器异常的时候,数据一样丢失。因此ES没有在那台机器上分配副本分片。
2.扩容一个节点后的ES Cluster
从上图中,可以看到添加1个节点后,data节点2分配了2个副本。
3、再扩容一个节点后的ES Cluster
3 * node从上图中可以看到,data节点1上的P1被移动到了data节点3,data节点2上的R3被移动到了data节点3,这是因为添加节点后,ES会自动均衡数据。
五. ES让人惊喜的功能
1. ES的NODE GROUP功能
ES的group功能和HBase的group功能类似,可以将某些节点放到某一个GROUP中,从而实现业务之间的隔离。比如想讲重点业务和普通业务隔离开来,就可以将重点业务放到指定的某个组,这个组不存在过保的设备,负载也比较低。而将普通业务放到普通的组中,这各组的设备由于比较老,故障率会比较搞,组内的机器负载也会高一些。如下图所示:
image图中有两个组,分别是GroupA和GroupB,其中GroupA中保存这某些索引,GroupB中也保存着某些分片。ES有专门的参数控制索引可以存储在某个Group或则节点,具体的参数如下:
cluster.routing.allocation.awareness.attributes
cluster.routing.allocation.include
cluster.routing.allocation.require
cluster.routing.allocation.exclude
2. ES部落节点功能
部落节点,就是作为联合客户端提供访问多个ElasticSearch集群的能力。业务只需要访问部落节点,就可以获取多个ES集群的数据。并且可以通过部落节点写入数据,写入数据的时候部落节点会将写入请求转发到后端的集群节点进行数据写入。但是不支持创建索引的操作。注意:如果部落节点对应后端的ES集群含有相同的索引名称就会出现莫名其妙的问题,因为ES的默认行为是从中选择一个。也就是说如果后端2个集群含有相同的索引名字,那么知会有一个索引会被访问到。
示意图
六. ES的IO流控功能
ES还有个比较好的功能就是IO流控的功能,这个功能对于分布式存储是非常必要的,比如可以限制文件合并的时候的IO,从而使系统更平稳地运行。ES主要有节点级和索引级两个限流机制。分别介绍如下:
节点级别限流
Indices.store.throttle.type (none/merge/all)
可以选择为none/merge/all三个值,意义分别如下:
none为不流控
merge为对合并做IO流控
all为对所有的操作做IO流控
索引级别限流
Index.store.throttle.type(none/merge/all/node)
Index.store.throttle.max_bytes_per_sec
七. ES的慢日志功能
ES有类似于MySql的慢查询功能,可以记录下慢的操作,从而让运维人员能通过慢的操作找到问题所在。默认情况下,慢日志是不开启的,有三种动作可以定义,分别是query、fetch、index三类,如下是一个query的慢日志定义:
PUT /my_index/_settings
{
"index.search.slowlog.threshold.query.warn" : "10s",#查询慢于 10 秒输出一个 WARN 日志。
"index.search.slowlog.threshold.fetch.debug": "500ms",#获取慢于 500 毫秒输出一个 DEBUG 日志。
"index.indexing.slowlog.threshold.index.info": "5s"#索引慢于 5 秒输出一个 INFO 日志。
}
八. ES的发现热点功能
ES有个查询集群热点线程的功能,这个功能在集群突然变慢的场景下特别有用,它将帮助你找到消耗资源最多的线程。热点线程的使用方法如下:
curl 'http://localhost:9200/_nodes/hot_threads'
返回的结果中含有线程所在的节点信息、线程消耗资源的情况、线程名称以及相关的堆栈信息.
::: {node-1}{NtIhTEzeRAaQneW0XMxy5Q}{PSZ2Q2lTRXiQX9BuPoKypQ}{172.16.189.131}{172.16.189.131:9300}{dilm}{ml.machine_memory=3973373952, xpack.installed=true, ml.max_open_jobs=20}
Hot threads at 2020-09-15T12:33:17.786Z, interval=500ms, busiestThreads=3, ignoreIdleThreads=true:
九 . ES的性能
ES VS MySQL
这部分的测试是采用人工写的SQL以及线上慢的SQL像结合的方式,测试结果如下:
image备注:MySQL测试数据采用的是innodb引擎,并采用50%的压缩比。
从性能来看ES要比MySQL要好,尤其在聚合的场景下。
十. ES替代监控DB评估
- 性能评估
从线上实际SQL评估,ES的性能要比MySQL的性能好100倍以上,性能方面应该不是瓶颈。
2.容量评估
优化前ES实际占用容量和MySQL差不多,优化后ES占用的容量为MySQL的40%左右。 - 可用性评估
ES本身有很好的伸缩机制和容灾机制,从目前的容灾测试来看,可用性能达到要求。 - 成本评估
目前监控DB的瓶颈主要是在容量瓶颈,因此存储量下降50%的情况下,设备量能下降到原来的50%,即成本下降50%。 - 研发评估
ES目前无权限认证(TEG已经添加了ES的权限认证功能)
不支持事务目前监控侧也暂时没问题。此外还有很大的部分需要研发侧的评估,因为采用ES后如下两个地方会有很大的变动:
数据上报部分需要改写
查询部分SQL以及格式处理需要改写