ElasticSearch集群的规划和具体设置。

分享的是携程机票ElasticSearch集群的规划和具体设置,内容相对细致,同时也会涉及到集群的监控分享。

一、整体架构

为什么采用ES作为搜索引擎呢?在做任何事情的时候,不要一上来就急着了解怎么做这件事情,而是去想想这件事情为什么值得去做。

这个是比较通用的数据的流程,一般会通过Kafka分离产生数据的应用程序和后面的平台,通过ETL落到不同的地方,按照优先级和冷热程度采取不同的存储方式。一般来说,冷数据存放到HDFS,如果温数据、或者热数据会采用Database以及Cache,目前分布式Cache还没有明显的强者出现,这将会成为未来的一个竞争点。

一旦数据落地,我们会做两方面的应用,第一个方面的应用是传统BI,比如会产生各种各样的报表,报表的受众是更高的决策层和管理层,他们看了之后,会有相应的业务调整和更高层面的规划或转变。这个使用路径比较传统的,在数据仓库时代就已经存在了。现在有一种新兴的场景就是利用大数据进行快速决策,数据不是喂给人的,数据分析结果由程序来消费,其实是再次的反馈到数据源头即应用程序中,让他们基于快速分析后的结果,调整已有策略,这样就形成了一个数据使用的循环。

这样我们从它的输入到输出会形成一种闭环,而且这个闭环全部是机器参与的,这也是为什么去研究这种大规模的,或者快速决策的原因所在。如果数据最终还会给人本身来看的话,就没有必要更新那么快,因为一秒钟刷新一次或者10秒钟刷新一次对人是没有意义的,因为我们脑子不可能一直转那么快,基于数据一直的做调整也是不现实的,但是对机器来讲,就完全没有问题。

二、集群规划

这是大体上的一个规划,当然,从左到右有一个结点,这个节点本身不存在数据的,你可以简单地认为它只是负责查询的入口。第二层用来承载具体的数据,然后这些数据的搜索本身会发生在这里。最后一层是MASTER的节点,主要是管理元数据,元数据包含有集群中的机器信息,以及写入到我的数据节点上的这些索引设置信息、索引Schema都是由Master管理。

我这里是以ES5.X版本为依据的,大家看ES文档,我这上面有一个节点没有写,就是没有写它的Ingest节点,它可以在数据真正写入到Index之前做一些转换。

三、集群配置

下面要讲的设置就非常具体了,从三个层面来讲:第一个有关Linux的系统配置,第二是集群层面的参数设置,最后会涉及到存储到集群上的索引设置。

1、OS参数设置

像OS这个参数设置,首先提到的是内存相关的参数,由于ES采用Mapping机制,将文件映射到内存,在系统级别有一些相关的参数要设置。另一个就是文件数,假设我们所有都设置到最大65535。

这个设置之后还需要在下面加入加入login这个文件,这里讲得非常具体,可以说是一个教程。

这里我只是做了一个示例,在Ext4文件系统中,每一次访问一个文件或者目录时,其实OS级别会记录访问时间,如果只是在海量文件的情况,上述的记录信息就会对IO有影响。有一篇文章提到,关闭文件访问时间信息之后,系统IO性能可以提升20%—30%。

我们知道Linux里面文件信息,不是直接改一次之后就写入到磁盘,它会先有一个文件的缓存,文件的缓存什么情况下会被写入到disk里面?有两个相应的系统参数可以设置的,一个是vm.dirty_background_ratio,一个是vm.dirty_ratio,一旦缓存占据内存超过百分比(默认值是20%)之后,内核就停止其它方面的操作,而只做文件的缓存吐到disk的操作,这时效果有点像Java里进行垃圾回收一样,对外界停止响应。 vm.dirty_ratio就是当它缓存量达到20%时,它就其它的什么都不干了,只做数据同步到disk一件。

内存不够时,会使用swap空间, 内存很大的话,可以不用创建swap空间。默认值是60,但是我们把它设置为零的话,是跟swap off效果一样。但为了避免内核出现OOM, 只是将其设置为1。

2、ElasticSearch参数设置

刚才两个讲的都是系统级别的设置,一个是内存,另一个是系统级别的IO,下面讲的是针对ES—JVM的设置。

这里建议,不管物理内存有多大,分配给Elasticsearch的只设成32G,同时后面如果出现OOM,进程直接退出。

为什么说要把它改成这个呢?因为我们在使用一个集群时看到,有时因为聚合操作的原因,会导致某一台机器上的JAVA进程出现OOM,但是这个JVM进程还在,并没有退出,退出的话可以通过monit捕捉到,也可以进行重启。如果没有退出,而是一直挂在那的话,就不能提供正常的服务。 此外加上这个参数的话,需要升级一下JDK版本,JDK要求1.8.0_92, 从这个版本开始支持ExitOnOutOfMemoryError参数。

另外一种办法就是如果我们内存不能升级JDK、存在种种现实约束的话,可以在这个时候用另一种方式来实现,在JVM启动参数中加入

-XX:OnOutOfMemoryError="kill -9 %p"。

这里就是讲输入到ElasticSearch里面每个集群的一些参数,一些相对比较主要的一些参数。这里的参数配了一幅图,这幅图最想表明的意思是说,我的参数的配置要使得我从整个集群的角度上来看,它每一台机器上的shard数目基本是相当的。

这里有一点,参数设置能保证shard数目是基本相当的,但并不是保证每一个shard的大小相等,这两者还是有差异的。决定每个集群上shard相等的参数是由这个balance决定,它默认一个是0.5,把它往下调的话,就不可以倾斜;往上调的话对倾斜的容忍度相对比较高。

ElasticSearch是一个高可靠的系统,集群的一个节点挂掉了,另一个节点是可以继续的。挂掉的节点是进行恢复,为了避免恢复工作对集群造成太多影响,主要是避免大的I/O消耗,需要进行参数设置。比如集群中同时在进行恢复的索引可以是多少个,还有就是一个node上能允许shard在做恢复。 这两个参数是cluster_concurrent_rebalance和node_concurrent_recoveries。

如果要缩容、对某一台机器进行维护、将其从集群中拉出来该怎么办?这个时候可以设定exclude名单,名单可以通过ip地址或主机名来指定。一旦设置的exlude名单,该名单上节点中的索引数据被拉到别的机器上面,数据被拉完之后,就可以被这个集群拉出去的机器进行维护,避免维护带来的数据丢失。

3、索引参数设置

这是具体到一个索引参数的设置。在讲具体参数之前,我们可以先讲一下ElasticSearch索引参数的设置、输入以及中间发生的过程。当真正的数据请求到达ElasticSearch节点之后,它一方面会写入到内存中,另外一部分会写入到TransactionLog。

写入到内存并不意味着可以被搜索,要通过Refresh操作,才可以被搜索到。Refresh之后,数据可以被搜索到,此刻数据还在内存中,如果很不巧的话,在这个时候断电,或者出现其它故障不可用了,那么等到这台机器再恢复时,我刚才写的内容就丢失掉了, 因为并没有被持久化到磁盘。 为了持久化这个内容,需要进行一次FLUSH操作, flush的内容会被写到一个segment中。 可想而知,随着时间的推移,系统会产生大量的segments,这些segment需要把它合并成一个大的。不合并成一个大的会怎样呢?不合并成一个大的,就是说每一个segment都会吃掉一些文件句柄,文件句柄数是有限的。另一个带来的就是查询性能下降,因为查询的时候,要对所有segments进行访问,效率就比较低了。

有了刚才讲的三步之后,再来看下面的参数就比较容易好理解了。 Refresh_interval 过多久可以让你查询到,时间越短就可以被越快地检索到,但是意味着我相应的I/O也上去了,在有大批量数据导入时,这个数值会适当的调大。

在我们目前部署的集群中,高峰时候每秒写入量,有十几万。 为了应对这种场景,将refresh_interval设置为100多秒或者90秒以上。

Number_of_shards索引分片的数目,这个数目可以设置得大一些,还有每一个分片的副本,在大批量导入时,由于副本数目是可以动态调整的,副本数也可以先设置为零,等数据全部导入后,再设置为非0值。 副本数可以动态调整,但是分片数目是无法动态调整的,也就是说,除非重建另外一个索引,不然原先设置的是啥样就只能啥样。 这个FLUSH也可以调大,需要的时候可以设置得大一些。

下面就是做segments合并的线程数,如果是spin disk的话,就使用默认值1,如果是SSD的话,可以把它调大一些。 讲到SSD代码的话, 为了进一步优化性能,可以将系统的i/o scheduler设置为noop 。

这里是针对每个Index的Schema设置。假设事先并不能确定索引,大部分我们可以采用动态的template。 上述的动态模板表示的是, 如果字符串小于10915, 就采用keyword来存储。

下面一栏对应特别特别大的字段,如果我们只是存储这个字段的内容,不对这个字段做搜索也不做任何分词,可以将类型设置为object,enabled设置为false,即便包含嵌套信息也不会被解析。

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java