本文主要介绍了es部署相关的硬件配置、jvm参数以及在部署过程中根据自己的数据情况进行集群规划的建议。一般来说,如果我们刚开始用es, 都是先在自己的笔记本电脑上,或者是几个虚拟机组成的小集群上,安装一个es,然后开始学习和试用其中的功能。但是如果我们要将es部署到生产环境中, 那么是由很多额外的事情要做的。需要考虑我们部署的机器的内存、CPU、磁盘、JVM等各种资源和配置。

1 内存

es是很吃内存的,es吃的主要不是你的jvm的内存,一般来说es用jvm heap(堆内存)还是用的比较少的,它主要吃的是你的机器的内存。es底层基于 lucene,lucene是基于磁盘文件来读写和保存你的索引数据,倒排索引,正排索引。lucene的特点就是会基于os filesystem cache,会尽量将频繁 访问的磁盘文件的数据在操作系统的内存中进行缓存,然后尽量提升磁盘文件读写的性能。开发过程中,有时候经常感觉到es的性能不太理想,es的性能 80%取决于你的机器,除了分配给jvm heap内存以外,还剩下多少内存。剩下的内存会留给es的磁盘索引文件做缓存,如果os cache能够缓存更多的磁盘 文件数据,索引文件的数据,索引读写的性能都会高很多,特别是检索方面。

如果你的大量的索引文件在os cache中放不下,还是停留在磁盘上,那么搜索、聚合的时候大量的都是读写磁盘文件,性能就低了,前后两者差别一个数 量级,比如说前者是ms级,后者是s级。

如果说es上千万数据的搜索时要耗费10s+,那么说明你的请求大量读写磁盘了。如果在es生产环境中,哪种资源最容易耗尽,那么就是内存了。排序和聚合 都会耗费掉很多内存,所以给es进程分配足够的jvm heap内存是很重要的。除了给jvm heap分配内存,还需要给予足够的内存给os filesystem cache。 因为lucene用的数据结构都是给予磁盘的格式,es是通过os cache来进行高性能的磁盘文件读写的。

关于机器的内存相关的知识,后面会有很深入的讲解,这里先简单提一下,一般而言,除非说你的数据量很小,比如就是一些os系统,各种信息管理系统, 要做一个内部的检索引擎,几万,几十万,几百万的数据量,对机器的资源配置要求还是蛮低的。一般而言,如果你的数据量过亿,几亿,几十亿。那么 其实建议你的每台机器都给64G的内存的量。

如果一个机器有64G的内存,那么是比较理想的状态,但是32GB和16GB的内存也是ok的。具体的内存数量还是根据数据量来决定,也不要给的刚刚好, 尽量给出一倍的buffer。但是如果一个机器的内存数量小于8G,那么就不太适合生产环境了,因为我们可能就需要很多小内存的机器来搭建集群,这样 会大大加大运维的复杂度,管理起来特别麻烦。而大于64G的机器也不是很有必要。

2 CPU

大多数es集群对于cpu的要求都会比较低一些,因此一台机器有多少个cpu core其实对生产环境的es集群部署相对来说没有那么的重要了,至少没有内存 来的重要。要用多核处理器的,一般来说2个cpu core~8个cpu core都是可以的。此外,如果要选择是较少的cpu core但是cpu性能很高,还是较多的 cpu core但是cpu性能较为一般,那么肯定是选择性能较为一般但是更多的cpu core。因为更多的cpu core可以提供更强的并发处理能力,远比单个cpu 性能高带来的效果更加明显。

3 磁盘

对于es的生产环境来说,磁盘是非常重要的,尤其是对那些大量写入的es集群,比如互联网公司将每天的实时日志数据以高并发的速度写入es集群。在 服务器上,磁盘是最慢的那个资源,所以对于大量写入的es集群来说,会很容易因为磁盘的读写性能造成整个集群的性能瓶颈。如果我们能够使用SSD 固态硬盘,而不是机械硬盘,那么当然是最好的,SSD的性能比机械硬盘可以高很多倍,可以让es的读写性能都高很多倍。所以,如果公司出的起钱大量 使用固态硬盘,那么当然是最好的。

如果我们在用SSD硬盘的化,那么需要检查我们的I/O scheduler,需要正确的配置IO scheduler。当我们将数据写入磁盘时,IO scheduler会决定 什么时候数据才会真正的写入磁盘,而不是停留在os cache内存缓冲中。大多数机器上,默认的IO scheduler是cfq,也就是completely fair queuing。 这个scheduler会给每个进程都分配一些时间分片,time slice,然后会优化每个进程的数据如何写入磁盘中,优化的思路主要 是根据磁盘的物理布局 来决定如何将数据写入磁盘,进而提升写入磁盘的性能。这是针对机械硬盘做出的优化,因为机械硬盘是一种旋转存储介质,是通过机械旋转磁盘+磁头 进行磁盘读写的机制。

但是scheduler的这种默认的执行机制,对于SSD来说是不太高效的,因为SSD跟机械硬盘是不一样的,SSD不涉及到机械磁盘旋转和磁头读取这种传统的 读写机制。对于SSD来说,应该用deadline/noop scheduler。deadline scheduler会基于写操作被pending了多长时间来进行写磁盘优化, 而noop scheduler就是一个简单的FIFO队列先进先出的机制。调整io scheduler可以带来很大的性能提升,甚至可以达到数百倍。

如果我们没有办法使用SSD,只能使用机械硬盘,那么至少得尽量正确读写速度最快的磁盘,比如高性能的服务器磁盘。此外,使用RAID 0也是一种提升 磁盘读写速度的高效的方式,无论是对于机械硬盘,还是SSD,都一样。RAID 0也被称之为条带式存储机制,striping,在RAID各种级别中性能是最高的。 RAID 0的基本原理,是把连续的数据分散存储到多个磁盘上进行读写,也就是对数据进行条带式存储。这样系统的磁盘读写请求就可以被分散到多个磁盘 上并行执行。但是没有必要使用镜像或者RAID的其他模式,因为我们不需要通过RAID来实现数据高可用存储,es的replica副本机制本身已经实现了数据 高可用存储。

最后,我们要避免跟网络相关的存储模式,network-attached storage,NAS,比如基于网络的分布式存储模式。虽然很多供应商都说他们的NAS解决 方案性能非常高,而且比本地存储的可靠性更高。但是实际上用起来会有很多性能和可靠性上的风险,一般因为网络传输会造成较高的延时,同时还有 单点故障的风险。

4 网络

对于es这种分布式系统来说,快速而且可靠的网络是非常的重要的。因为高速网络通信可以让es的节点间通信达到低延时的效果,高带宽可以让shard的 移动和恢复,以及分配等操作更加的快速。现代的数据中心的网络对于大多数的集群来说,性能都足够高了。比如千兆网卡,这都是可以的。但是要避免 一个集群横跨多个数据中心,比如异地多机房部署一个集群,因为那样的话跨机房,跨地域的传输会导致网络通信和数据传输性能较差。es集群是一种p2p 模式的分布式系统架构,不是master-slave主从分布式系统。在es集群中,所有的node都是相等的,任意两个node间的互相通信都是很频繁和正常的。 因此如果部署在异地多机房,那么可能会导致node间频繁跨地域进行通信,通信延时会非常高,甚至造成集群运行频繁不正常。

就跟NAS存储模式一样,很多供应商都说跨地域的多数据中心是非常可靠的,而且低延时的。一般来说,可能的确是这样,但是一旦发生了网络故障, 那么集群就完了。通常来说,跨地域多机房部署一个es集群带来的效益,远远低于维护这样的集群所带来的额外成本。

5 自建集群 vs 云部署

现在一般很容易就可以拿到高性能的机器来部署集群:很多高性能的机器可以有上百G的内存资源,还有几十个cpu core。但是同时我们也可以再云供应 商上,比如阿里云,租用大量的小资源的虚拟机。那么对于自己购买昂贵高性能服务器自建集群,以及租用云机器来部署,该选择哪种方案呢?

如果你自己购买5台,比如说,8核64G的物理机,搭建es集群,或者是,上阿里云或其他云服务,购买了2核4G,16台,虚拟机,搭建es集群,你上阿里云, 也可以买到大资源量的虚拟机,4/8/16核64G。一般来说,对于es集群而言,是建议拥有少数机器,但是每个机器的资源都非常多,尽量避免拥有大量的 少资源的虚拟机,这样就会导致一个机器上部署一个es进行就会导致大量资源浪费,部署多个es节点会导致es管理稍微有点复杂。因为对于运维和管理 来说,管理5个物理机组成的es集群,远远比管理100个虚拟机组成的es集群要简单的多。同时即使是自建集群,也要尽量避免那种超大资源量的超级服 务器,因为那样可能造成资源无法完全利用,然后在一个物理机上部署多个es节点,这会导致我们的集群管理更加的复杂。

6 JVM

对于最新的es版本,一般多建议用最新的jvm版本,除非es明确说明要用哪个jdk版本。es和lucene都是一种满足特殊需求的软件,lucene的单元测试和 集成测试中,经常会发现jvm自身的一些bug。这些bug涵盖的范围很广,因此尽量用最新的jvm版本,bug会少一些。就目前es 5.x版本而言,建议用jdk 8, 而不是jdk 7,同时jdk 6已经不再被支持了。

如果我们用java编写es应用程序,而且在使用transport client或者node client,要确保运行我们的应用程序的jvm版本跟es服务器运行的jvm版本 是一样的。在es中,有些java的本地序列化机制都被使用了,比如ip地址,异常信息,等等。而jvm可能在不同的minor版本之间修改序列化格式,所以 如果client和server的jvm版本不一致,可能有序列化的问题。

同时官方推荐,绝对不要随便调整jvm的设置。虽然jvm有几百个配置选项,而且我们可以手动调优jvm的几乎方方面面。同时遇到一个性能场景的时候, 每个人都会第一时间想到去调优jvm,但是es官方还是推荐我们不要随便调节jvm参数。因为es是一个非常复杂的分布式软件系统,而且es的默认jvm配置 都是基于真实业务场景中长期的实践得到的。随便调节jvm配置反而有可能导致集群性能变得更加差,以及出现一些未知的问题。反而是很多情况下,将 自定义的jvm配置全部删除,性能是保持的最好的。

7 容量规划

在规划你的es集群的时候,一般要规划你需要多少台服务器,每台服务器要有多少资源,能够支撑你预计的多大的数据量。但是这个东西其实不是一概而论 的,要视具体的读写场景,包括你执行多么复杂的操作,读写QPS来决定的。不过一般而言,对于很多的中小型公司,都是建议es集群承载的数据量在 10亿规模以内。用最合理的技术做最合理的事情。这里可以给出几个在国内es非常适合的几个场景,es是做搜索的,当然可以做某个系统的搜索引擎。 比如网站或者app的搜索引擎,或者是某些软件系统的搜索引擎,此外es还可以用来做数据分析。那么针对这几个不同的场景,都可以给出具体建议。 比如做网站或者app的搜索引擎,一般数据量会相对来说大一些,但是通常而言,一个网站或者app的内容都是有限的,不会无限膨胀,通常数据量从百万 级到亿级不等,因此用于搜索的数据都放在es中是合理的。

然后一些软件系统或者特殊项目的搜索引擎,根据项目情况不同,数据量也是从百万量级到几十亿,甚至几百亿,或者每日增量几亿,都有可能,那么此时 就要根据具体的业务场景来决定了。如果数据量特别大,日增量都几亿规模,那么其实建议不要将每天全量的数据都写入es中,es也不适合这种无限规模 膨胀的场景。es是很耗费内存的,无限膨胀的数据量,会导致我们无法提供足够的资源来支撑这么大的数据量。可以考虑是不是就将部分热数据,比如 最近几天的数据,放到es中做高频高性能搜索,然后将大量的很少访问的冷数据放大数据系统做离线批量处理,比如hadoop系统里面。

比如说,你预计一下,你的数据量有多大,需要多少台机器,每台机器要多少资源,来支撑,可以达到多大的性能。如果你有10亿的数据量想要达到1s以内。 如果你想要es达到ms级的化,你必须要有足够的os cache去缓存几乎大部分的索引数据。如果你预算到你有10亿的数据量,那么计算每条数据大概多大, 比如有多少个字节,比如每条数据是1k,那么10亿的数据量需要100G的存储。如果用5台机器部署,64G,8核,这个时候总的内存量在300G左右,那么300G 的话去支撑100G的总数据量,300G一般有一半要分给es jvm heap,还有150G去支撑100G的数据,虽然数据量是100G,但是它落地到磁盘文件加入很多 es自己的信息,100G数据的话可能会膨胀到200G,200G落地磁盘的数据,物理内存剩余的只有150G,可能还有一些操作系统,还有其他的损耗100G。 200G落地磁盘的数据,100G物理内存可以用来做os cache,50%的概率是基于os cache做磁盘索引文件的读写,几秒,很正常了。

根据我们的实践经验而言,一般来说,除非是你的机器的内存资源,完全可以容纳所有的落地的磁盘文件的os cache,ms,否则的话,如果不是的话, 会大量走磁盘,几秒同时如果数据量在10亿以内的规模,那么一般而言,如果提供5台以上的机器,每台机器的配置到8核64G的配置,一般而言都能hold 住。当然,这个也看具体的使用场景,如果你读写特别频繁,或者查询特别复杂,那么可能还需要更多的机器资源。如果你要承载更大的数据量,那么就 相应的提供更多的机器和资源。

要提升你的es的性能,最重要的,还是说规划合理的数据量,物理内存资源大小,os cache

参考

  1. es顶尖高手