文章目录


白话Elasticsearch63-生产集群部署之硬件配置、jvm以及集群规划建议_硬件配置


概述

继续跟中华石杉老师学习ES,第63篇

 ​


内存

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的。具体的内存数量还是根据数据量来决定。但是如果一个机器的内存数量小于8G,那么就不太适合生产环境了,因为我们可能就需要很多小内存的机器来搭建集群。而大于64G的机器也不是很有必要。


CPU

大多数的es集群对于cpu的要求都会比较低一些,因此一台机器有多少个cpu core其实对生产环境的es集群部署相对来说没有那么的重要了,至少没有内存来的重要。当然,肯定是要用多核处理器的,一般来说2个cpu core~8个cpu core都是可以的。

此外,如果要选择是较少的cpu core但是cpu性能很高,还是较多的cpu core但是cpu性能较为一般,那么肯定是选择性能较为一般但是更多的cpu core。因为更多的cpu core可以提供更强的并发处理能力,远比单个cpu性能高带来的效果更加明显。


磁盘

对于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解决方案性能非常高,而且比本地存储的可靠性更高。但是实际上用起来会有很多性能和可靠性上的风险,一般因为网络传输会造成较高的延时,同时还有单点故障的风险。


网络

对于es这种分布式系统来说,快速而且可靠的网络是非常的重要的。

因为高速网络通信可以让es的节点间通信达到低延时的效果,高带宽可以让shard的移动和恢复,以及分配等操作更加的快速

现代的数据中心的网络对于大多数的集群来说,性能都足够高了。比如千兆网卡,这都是可以的。

但是要避免一个集群横跨多个数据中心,比如异地多机房部署一个集群,因为那样的话跨机房,跨地域的传输会导致网络通信和数据传输性能较差。es集群是一种p2p模式的分布式系统架构,不是master-slave主从分布式系统。在es集群中,所有的node都是相等的,任意两个node间的互相通信都是很频繁和正常的。因此如果部署在异地多机房,那么可能会导致node间频繁跨地域进行通信,通信延时会非常高,甚至造成集群运行频繁不正常。

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


自建集群 vs 云部署

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

你是自己购买5台,比如说,8核64G的物理机,搭建es集群

或者是,比如说,上阿里云,或者其他的云服务,购买了2核4G,16台,虚拟机,搭建es集群

你上阿里云,也可以买到大资源量的虚拟机,4/8/16核64G

一般来说,对于es集群而言,是建议拥有少数机器,但是每个机器的资源都非常多,尽量避免拥有大量的少资源的虚拟机。因为对于运维和管理来说,管理5个物理机组成的es集群,远远比管理100个虚拟机组成的es集群要简单的多。

同时即使是自建集群,也要尽量避免那种超大资源量的超级服务器,因为那样可能造成资源无法完全利用,然后在一个物理机上部署多个es节点,这会导致我们的集群管理更加的复杂。


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配置全部删除,性能是保持的最好的。


容量规划

在规划你的es集群的时候,一般要规划你需要多少台服务器,每台服务器要有多少资源,能够支撑你预计的多大的数据量。但是这个东西其实不是一概而论的,要视具体的读写场景,包括你执行多么复杂的操作,读写QPS来决定的。不过一般而言,实际经验,对于很多的中小型公司,都是建议es集群承载的数据量在10亿规模以内。用最合理的技术做最合理的事情。

这里可以给出几个在国内es非常适合的几个场景,es是做搜索的,当然可以做某个系统的搜索引擎。比如网站或者app的搜索引擎,或者是某些软件系统的搜索引擎,此外es还可以用来做数据分析。那么针对这几个不同的场景,都可以给出具体建议。比如做网站或者app的搜索引擎,一般数据量会相对来说大一些,但是通常而言,一个网站或者app的内容都是有限的,不会无限膨胀,通常数据量从百万级到亿级不等,因此用于搜索的数据都放在es中是合理的。

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

比如说,你预计一下,你的数据量有多大,需要多少台机器,每台机器要多少资源,来支撑,可以达到多大的性能

数据量 -> 性能,10亿 -> 要求1s内返回

es达到ms级的化,你必须要有足够的os cache去缓存几乎大部分的索引数据

10亿,每条数据是多大,比如多少个字节,1k -> 假设数据大小为100G

如果有5台,64G,8核,那么总内存就是300G左右 -> 100G的总数据量,300G的内存,一般要分给es jvm heap,150G (每台32G)-> 那么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