本周在数据库研发和运营组做了关于ELK的分享,这个分享主要是居于ES部分做的相关理论和测试的结论。下面是对此次分享的文字版整理,希望对研究学习ElasticSearch的朋友们有帮助。
分享的主要内容如下:
先来说一下去调研ES的初衷,是为了确认ElasticSearch是否能比较好地解决目前监控DB遇到的几个问题,如下图所示:
监控DB目前面临的三个问题分别是:
容量瓶颈
监控DB的数据量越来越大,单个表压缩后有的已经接近100G(一天的数据),目前采用的是MySQL来存储,使用的TokuDB引擎。MySQL的扩容型并不好,因此无法快速的进行数据的扩容,目前的做法更多的是对过期的历史数据进行清理。但是需要保留月初、月末以及节假日的数据。
性能瓶颈
监控有很多聚合的查询,在单表特别大的情况下,一个聚合SQL需要很长时间才能查询出结果。无法很好展现监控的实时效果。给业务的体验也很糟糕。
稳定性
如果监控DB出现问题,会导致线上监控曲线掉底,业务侧会以为是自己线上出现了问题,这会给业务带来很大的困扰,因此对监控DB的稳定性要求很高。坑队友的事情监控DB还是尽量少干。
下面就来单独介绍各个部分的内容:
一、ELK简介
(一)ELK的涵义
ELK其实是由三个组建组成,分别是ElasticSearch、Logstash以及Kibana。
1、E代表ElasticSearch,如下图所示:
正上图说的那样,ELasticSearch是整个ELK的心脏,它负责索引的创建、搜索、分析以及数据的存储等工作,这个组将在后面做详细介绍。
2、L代表Logstash,如下图所示:
Logstash是用来做数据采集、接收、处理和转发的工具,它讲采集来的数据经过分析和处理以后,将数据发送到ElasticSearch存储。它本身支持非常多的数据源。
3、K代表Kibana,如下图所示:
Kibana的主要功能是负责将ES中数据进行炫酷的展示。
整理概括一下整个ELK就是:
Logstash负责数据采集、分析和处理,然后将数据发送给ElasticSearch做进一步的存储、分析和搜索,最后Kibana讲ElasticSearch中的数据炫酷地展示出来。
(二)ELk常用架构
ELK的常用架构如下图所示(偷懒盗个图):
使用Logstash Shipper来在机器上采集相关的数据或者日志,你可以理解为logstash的一个agent
中间使用redis做队列,也有很多的公司使用kafka来代替redis。
(三)ELK在业界的使用情况
目前ELK比较活,社区也很活跃,有很业务都在使用,主要分为三类应用:
1、全文检索
比如github和维基百科
2、日志监控类
比如腾讯云监控、斗鱼日志分析平台
3、数据分析和查询
比如:DELL,sprint
此外国外还有一些公司用ES来存储地理位置数据,比如Foursquare公司,结合搜索和地理位置两者提供更优质的服务。
二、ES技术细节
ES技术细节部分主要介绍如下几个方面:
(一)、ES的特性
1、Base on Apache Lucense
Lucense是高性能的搜索引擎库,提供了查询引擎、搜索引擎和文本分析引擎。但是使用Lucense成本很高,需要掌握很多关于搜索的知识。而ES使用Lucense作为底层架构,在其上做了大量的易用性、扩展性、容灾以及性能方面的工作,使得用户经过很少的配置就可以快速ES进行数据存储和检索。
2、Distributed and horizontally scalable
ES是分布式的,可以水平扩展,比如添加节点的时候能自动均衡数据。
3、Full-text search and powerful search
ES支持前文支持全文索引,并且搜索功能非常强大。
4、Document & Json
ES是基于文档的强大组件,交互数据全部采用Json标准格式。
5、Restful API
6、Open Source
7、Query DSL
ES提供了基于JSON的query DSL查询语言,传统的SQL语句很容易转化成query DSL。后面做的关于MySQL和ES的性能比对也是将标准SQL改写成query DSL实现的。
(二)、ES集群组成和名词解析
1、名称解析
a、Cluster
ES由个data节点和1个master节点构成ES 集群,ES集群具有容灾能力,官方建议的也是使用ES集群的方式来运维ES。
b、Node
Node是ES的节点,一般集群会有1个master节点,多个data节点,ES节点有如下几种类型:
master节点
master的功能是维护ES集群的元数据,比如创建删除索引;监控其他的节点,比如对故障节点进行剔除和协调故障恢复工作;此外master节点还负责分片具体分配给哪些节点。因此在扩容和这故障的时候,分片迁移到哪台机器上也需要master来协调。
需要注意的是所有的涉及到路由变化的操作都必须master来做。
建议:master非常重要,比较大的集群建议讲master独立部署
data节点
data节点负责数据的存储和检索。
Coordinating节点
Coordinating节点不负责数据的存储,只负责请求的转发,有点类似于负载均衡器
Tribal节点
tribal节点成为部落节点,通过它能够查询不通集群的ES数据,有点类似于spider的功能。
c、Shard
Shard是分片的意思,一般一个很大的表为了保证其扩展能力都会水平切分为多个分片,类似于mysql的水平分表的概念。每个分片只存储自己那部分的数据和索引信息,全部的分片数据的集合就是全量的数据。
因为分片建立以后,如果后面要增加分片,需要全量导入数据,因此分片必须在创建索引之前就规划好。具体的可以从索引的数据量、集群节点的个数和预计集群的规模等方面进行合理的评估。
d、Replica
Replica副本,ES官方建议至少1副本,否则容易出现数据丢失的风险。在ES中副本主要有2个作用:
其一是提供数据安全性保障,其二副本也能够分担读的请求,提高ES的性能。
e、Index
Index是索引的意思,和关系型数据库中的索引很不一样。ES中Index的概念类似于关系型数据库中的database。
f、Type
Type是分类的意思,和关系型数据库中table的概念比较类似。为提高性能,建议最好是一个Index就存储一个Type的数据就好。
g、Mapping
Mapping的概念和关系型数据库中的字段类型比较类似,如下ES中定义的Type字段类型:
h、Document
ES是文档型的组建,Document类似于关系型数据库的一行。在ES中就是一个文档。
2、集群组成
从上图中可以看到,ES集群是由多个节点组成,上图中有1个master节点和2个data节点组成,并且创建了1个索引,索引有4个数据分片和1个副本组成。Translog为ES提供高性能以及数据安全保障。
(三)、ES的写逻辑
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的操作。
(四)、ES的读逻辑
ES的读逻辑如下图所示:
ES查询的时候如果指定了routing相关的值,就会只扫描确定的1个或者少数文档,如果没有指定routing相关的值就需要扫描所有的分片。因此还会涉及到查询的拆分和合并的步骤。详情如下:
a、查询请求发送到任意一个节点
b、如果指定了routing的相关值,根据shard = hash(routing) % number_of_primary_shards公式就能直接计算出请求的数据所在的分片,然后将请求发送到对应的分片就OK。如果指定routing的相关值,那么会发送到对应查询涉及到的所有分片(这就是请求拆分)。
c、如果查询只涉及到1个分片,查询的分片所在的机器返回查询结果到初始请求的节点,初始请求节点再将数据返回给业务。而如果查询涉及到多个分片,初始节点就会将请发送给多个分片并发查询,此时查询的分片所在的机器返回查询结果到初始请求的节点后,初始节点还需要再进行结果的合并。初始节点将合并后的数据返回个业务。
(五)、ES的容灾
ES有很完善的容灾机制,候选master一般有多个,data节点也有多个,因此节点异常的时候通过将访问切换到别的节点来容灾。具体流程包含如下几个流程:
1、故障发现
故障发现如下图所示:
从上图中可以看出,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次
#备注,以上参数可以根据自己的网络情况和业务需求进行调整。
2、节点切换
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个副本,但是datanode1只分配了3个主分片。这是因为ES认为如果副本和主分片在1台机器上和没有副本的效果一样,当那台机器异常的时候,数据一样丢失。因此ES没有在那台机器上分配副本分片。
2、扩容一个节点后的ES Cluster
从上图中,可以看到添加1个节点后,data节点2分配了2个副本。
3、再扩容一个节点后的ES Cluster
从上图中可以看到,data节点1上的P1被移动到了data节点3,data节点2上的R3被移动到了data节点3,这是因为添加节点后,ES会自动均衡数据。
三、ES让人惊喜的功能
做为一个运维人员,在学习ES的时候,遇到了很多让人惊喜的功能,整理出来和大家共享:
(一)、ES的GROUP功能
ES的group功能和HBase的group功能类似,可以将某些节点放到某一个GROUP中,从而实现业务之间的隔离。比如想讲重点业务和普通业务隔离开来,就可以将重点业务放到指定的某个组,这个组不存在过保的设备,负载也比较低。而将普通业务放到普通的组中,这各组的设备由于比较老,故障率会比较搞,组内的机器负载也会高一些。如下图所示:
图中有两个组,分别是GroupA和GroupB,其中GroupA中保存这某些索引,GroupB中也保存着某些分片。ES有专门的参数控制索引可以存储在某个Group或则节点,具体的参数如下:
cluster.routing.allocation.awareness.attributes
cluster.routing.allocation.include
cluster.routing.allocation.require
cluster.routing.allocation.exclude
(二)、ES部落节点功能
ES从1.0版本开始支持使用部落节点(tribe node),所谓的部落节点,就是作为联合客户端提供访问多个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流控
Indices.store.throttle.max_bytes_per_sec
索引级别限流
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",
"index.search.slowlog.threshold.fetch.debug": "500ms",
"index.indexing.slowlog.threshold.index.info": "5s"
}
上面设置的意思如下:
查询慢于 10 秒输出一个 WARN 日志。
获取慢于 500 毫秒输出一个 DEBUG 日志。
索引慢于 5 秒输出一个 INFO 日志。
(五)、ES的发现热点功能
ES有个查询集群热点线程的功能,这个功能在集群突然变慢的场景下特别有用,它将帮助你找到消耗资源最多的线程。热点线程的使用方法如下:
curl 'http://localhost:9200/_nodes/hot_threads'
返回的结果中含有线程所在的节点信息、线程消耗资源的情况、线程名称以及相关的堆栈信息,如下图所示:
四、ES的性能
ES的性能主要从两个维度来评估
(一)、ES VS InfluxDB
1、单节点ES和InfluxDB写入性能对比(数据来自:http://km.oa.com/articles/show/334237?kmref=search&from_page=1&no=1)
结论:ES单节点写入性能最高在19w,InfluxDB在15w。在并发数超过20时,ES与InfluxDB的写入性能均呈现出下降趋势。
2、单节点ES和InfluxDB读性能对比(数据来自:http://km.oa.com/articles/show/334237?kmref=search&from_page=1&no=1)
结论:ES查询性能整体比InfluxDB好很多,当并发数较高时(40),ES查询性能比InfluxDB高出近4倍,在2w左右。在并发线程数达到50时,InfluxDB出现链接错误,拒绝查询请求。
备注:测试结果只所以和influxDB官方测试数据比较大,我因为TEG侧对es本身和influx的测试工具都做了很多优化,主要的优化如下:
es优化:关闭不必要的字段,routing,调整刷盘策略、shard数量等
influxDB测试工具优化:支持routing、在保证查询结果一致的情况下尽量优化查询语句
(二)、ES VS MySQL
这部分的测试是采用人工写的SQL以及线上慢的SQL像结合的方式,测试结果如下:
备注:MySQL测试数据采用的是innodb引擎,并采用50%的压缩比。
从性能来看ES要比MySQL要好,尤其在聚合的场景下。
五、ES替代监控DB评估
1、性能评估
从线上实际SQL评估,ES的性能要比MySQL的性能好100倍以上,性能方面应该不是瓶颈。
2、容量评估
优化前ES实际占用容量和MySQL差不多,优化后ES占用的容量为MySQL的40%左右。
3、可用性评估
ES本身有很好的伸缩机制和容灾机制,从目前的容灾测试来看,可用性能达到要求。
4、成本评估
目前监控DB的瓶颈主要是在容量瓶颈,因此存储量下降50%的情况下,设备量能下降到原来的50%,即成本下降50%。
5、研发评估
ES目前无权限认证(TEG已经添加了ES的权限认证功能)
不支持事务目前监控侧也暂时没问题。此外还有很大的部分需要研发侧的评估,因为采用ES后如下两个地方会有很大的变动:
数据上报部分需要改写
查询部分SQL以及格式处理需要改写
六、感谢
特别感谢TEG同事@johngqjiang的指点,顺便广告一下,TEG基于ES上开发的时序数据库CTSDB已经开始大规模试用,需要试用的同事可以找johngqjiang进一步沟通。