首先说一下我的疑问:就是对于 ES 集群,我们应该如何去配置不同的角色, 另外,不同的角色是不是对系统资源的要求也不一样呢?如果我们对不同角色的节点都给了相同的配置,就一定会造成资源的浪费。 于是看 了很多的文章,去寻找答案 。
另外,这篇文章最后也会分片给出了合理的建议。
# # 补充一下我对集群节点角色规划的理解
最近一段时间在学习一本不错的书《elasticsearch 源码解析源码解析与实战优化 》,有了新的理解,这篇文章我之前转载的别人的。现在补充一下自己的理解,这些理解建立在了解elasticsearch 读写的内部原理以后。
开门见山,我说一下我使用elasticsearch的场景,一个索引的数据量是8亿加,普通查询都是在一秒以内返回的。我对集群角色的规划建议是,是将节点的角色分开,其中包括数据角色的节点,master节点,和协调节点。
首先简单的说一下这些节点的工作内容,其中主节点主要维护了集群的一些信息,在创建索引、某个非master节点挂掉以后、或者重启集群以后,需要有大量的操作。这个时候要花费大量的 cpu,内存,占用IO,其他情况下,正常的读写操作,master节点,干不了太多活儿,所以也不花费太多的资源。所以在分配资源的时候,就不用给他分配太多的资源,比方说配置的堆内存。我给集群的master节点,分配了15G的内存,但是似乎用不太上,感觉给8G就够了。另外的话,我给集群分配的三个master节点(有资格成为master的节点,另外三个节点位于不同的机器上)其次,三个是用来解决脑裂问题的。就是在master节点的机器挂了以后,其他有资格的成为master的可以选举上。
协调节点最好也是单独出来的,然后配合上 j客户端,指定这些协调节点,来接受请求。如果不这样做的话,请求可能要到某个数据节点上去。因为对于读写的过程,数据节点要占用大量的资源。同样,协调节点要汇总这些请求的结果,如果是持续的大量的请求过来,那么相当于是协调节点和数据节点,都要花费资源(CPU IO 内存),形成了一种竞争的关系。所以说将协调节点分开。这样的话,节点,就只需要做一份工作,不需要同事读写数据,又汇总数据。达到职责明切的目的,互相不影响。我对集群的规划是,九个数据节点,三个协调节点,其中每个节点的内存配置是 31G。
我先把结论写在上边了,上边提到的概念不同的,可以继续向下看。
# # 先来看一下不同的节点角色
不考虑使用MachineLearning的情况,ES 的节点角色设置有以下几种:
-
Master(主节点)
集群的主节点,负责集群的编排。对应节点配置中的node.master设为true
-
Data(数据节点)
数据节点,负责数据的搜索与写入。对应节点配置中的node.data设为true
-
Ingest(ingest节点)
负责进行请求的预处理(pipeline)。对应节点配置中的node.ingest设为true
-
coordinate(协调节点)
接收外部请求,并将请求分配到相应应的节点,并对节点返回的数据进行合并处理。当前三个角色的配置都是false的情况下,该节点会承担专门协调的角色。实际情况下,所有节点都具备coordinator请求的能力。
对于小规模的集群,由于设备有限,往往node.master,node.data,node.ingest都设置为true,方便管理。对于较大规模的集群,由于这几个角色对计算资源的要求不同,往往分配单独角色节点以最优化资源利用。
同时,考虑到冷热数据不同的索引需求,一般会将数据节点再按冷热温(Hot,Warm,Cold)进行划分,同时结合索引的生命周期管理(ILM)模块进行搭配使用。(ILM参考:https://www.jianshu.com/p/9f7f39efeda3)
-
Hot节点
处理当前最新数据的写入和查询,一般会配置大内存和固态硬盘,具有较高的磁盘IO,SSD一般会具备200,000到400,000的IOPS,如果以存储量来算,单块SSD能够达到1-2GBps。
相对而言,普通HDD的顺序写入速度大概约240MBps,如果是随机写入则速度更低,可以通过配置Raid0来提示HDD的性能。由于ES本身在逻辑成本实现了高可用,因此不需要再通过搭建raid5的方式提供磁盘的高可用。
-
Warm节点
一般用来存储非最新数据,不会有实时写入的请求,有时候会处理一些查询,索引处于只读状态。一般会使用HDD配合中等配置的内存。
-
Cold节点
Cold节点用来存放归档的数据,以满足一些法律法规。如果数据并没有留存的需求,一般超过一定的时限就会删除相关的索引。Cold节点需要廉价的大容量存储,索引处于关闭状态,没有实时的查询需求。
ES的数据节点往往有较大的负载压力,一般建议节点不要共用硬件设备,一防止因为硬件原因导致多个节点同时离线。
数据写入如下图所示,数据的写入有以下流程:
- coordinator节点接收到外界的写入请求。
- 如果集群有配置ingest pipeline,coordinator节点会将请求发放到ingest节点进行预处理。
- 如果没有配置pipeline或者在预处理结束后,相应节点会根据routing规则决定该请求需要写入到哪个分片(shard)(一般会根据_id值做hash。shard_id = hash(routing) % number_of_shard),并且请求分配到对应节点。
- shard对应节点处理写入请求。
- 写入请求完成后,向副本分片所在节点发出replication请求。
- 副本分片所在节点处理副本写入请求。
put.png
数据搜索对数据进行搜索时,会有不同于写入时的处理流程。不会进行pipeline处理。相关流程为:
- coordinator节点接收到查询请求。
- 在本地找到需要查询的分片后,coordinator节点将请求分配到相关shard所在节点。
- 各shard处理完搜索后,将结果返回给coordinator节点。
- coordinator节点会将各shard返回来的结果进行合并。
- coordinator节点将合并好的结果返回给请求客户端。
ES_analyzer-Query.png
资源可以看出coordinator节点负责处理外界的request,并将相应的操作指派到相应节点上去。在搜索或者聚合的情况下,还要合并从各个节点返回的结果,再将结果返回给客户端。因此可以看出,coordinator节点对于网络带宽,CPU,和内存的要求都较高。对于大规模集群来说,coordinator节点本身负载压力就比较大,不适合在担任其他角色。
ingest节点负责在文档写入之前对数据进行预处理,功能比较单一,主要是CPU和内存。
数据节点负责具体的写入和搜索逻辑,对内存要求比较高,数据节点的CPU能力决定了其可以承载的并发数。同时数据节点也承担了数据的存储职能,对磁盘IO有一定的要求。由于数据在做replication时,会有n倍的流量在集群内部备份节点之间发生,因此数据节点对网络也有一定的要求,这取决于数据的副本数。
下表是各种角色的节点对资源的依赖情况下,仅代表个人观点。
角色CPU内存IO网络coordinator高高一般高ingest一般一般一般一般data一般高高高master一般取决于集群大小一般一般 对数据量进行估算在规划ES集群之前,我们需要问自己几个问题:
- 我的数据是什么样的。
- 每天会有多少新增数据?
- 这些数据需要保留多少天?
- 给这些数据设置几个副本?
- 原始数据在写入ES后大小会有所变化,比如,要建立倒排索引。keyword字段和其他结构化字段会构建doc_values正排索引,这些都会导致落盘后的数据发生变化。
- 我的资源是怎么样的
- 数据节点有多少堆内存
- 我需要留出部分磁盘空间给系统和后台,按5%计算。
- ES默认的磁盘low.watermark是85%,超过该阈值后,将不允许向该节点分配shard。
- 考虑到系统的高可用,需要考虑在一个或多个节点下线的情况下,离线的分片可以得到重新分配。
获得了这些数据后,我们就可以进行计算了。
- 总数据量 = 每天新增原始数据量 * 保留天数 * (副本数+1)*膨胀系数
- 磁盘空间 = 总数据量 / (1-15%-5%) = 总数据量 * 1.25
- 所需节点数 = 磁盘空间 / (节点内存/内存磁盘比)
- 一个经验数字是,使用SSD的Hot类型节点(内存/磁盘)为1/30。使用HDD的Warm类型节点(内存/磁盘)比为1/160。而用来归档,使用廉价硬盘存储的Cold类型节点(内存/磁盘)为1/1000。
- 一个经验数字,所需的磁盘空间一般为原始数据大小的3.38倍。仅供参考,具体使用的磁盘空间。
使用多个类型(Hot,Warm,Cold)分片时,需要按照每个阶段分别进行计算。
对分片数进行估算在进行分片估计时,我们需要先准备以下数据:
- 有多少个索引
- 每个索引设置多少个shard以及几个replication
- 每个索引保留多长时间
- 每个数据节点有多少内存
现在我们有以下一些经验数据:
- 每1GB堆内存最多包含20个分片(每个分片50MB,是一个非常小的值,建议按情况适当提高该数值)
- 每个分片不超过50GB。(一般30-40GB)
可以计算得到:
- 总分片数 = 索引数量 * shard数 * (副本数 + 1)
- 所需节点 = 总分片数 / (节点堆内存[GB]/每GB堆内存承载分片数 )
ES权威指南里提到了一种通过实践的评估方式,可以参考:https://www.elastic.co/guide/cn/elasticsearch/guide/cn/capacity-planning.html
根据搜索量进行估算我们需要预先假设几个数据:
- 峰值每秒请求数。
- 平均请求延时。
我们预先知道每个节点的线程池大小,搜索线程池大小一般配为:
线程池大小 = int(核数 * 3/2) + 1,该公式来源于https://www.elastic.co/guide/cn/elasticsearch/guide/current/dont-touch-these-settings.html
先计算:
- 每线程每秒处理请求数 = 1s/平均请求延时
- 处理峰值请求所需的并发数 = 峰值每秒请求数/每线程每秒处理请求数
- 所需节点数 = 峰值并发数/每节点线程池大小。