集群层

· 节点总数不应该太多,一般来说,最大集群规模最好控制在100个节点左右。
· 单个分片不要超过50GB,最大集群分片总数控制在几十万的级别。搜索对 CPU、内存、磁盘的性能要求都很高,要达到比较低的延迟就需要较好的硬件资源。
. ES不建议为JVM配置超过32GB的内存,超过32GB时,Java内存指针压缩失效,浪费一些内存,降低了CPU性能,GC压力也较大。因此推荐设置为31GB:
-Xmx31g -Xms31g
当物理主机内存在64GB以上,并且拥有多个数据盘,不做raid的情况下,部署ES节点时有多种选择:
(1)部署单个节点,JVM内存配置不超过32GB,配置全部数据盘。这种部署模式的缺点是多余的物理内存只能被cache使用,而且只要存在一个坏盘,节点重启会无法启动。(2)部署单个节点,JVM内存配置超过32GB,配置全部数据盘。接受指针压缩失效和更长时间的GC等负面影响。(3)有多少个数据盘就部署多少个节点,每个节点配置单个数据路径。优点是可以统一配置,缺点是节点数较多,集群管理负担大,只适用于集群规模较小的场景。(4)使用内存大小除以64GB来确定要部署的节点数,每个节点配置一部分数据盘,优点是利用率最高,缺点是部署复杂。
移除节点
我们将node-1下线:
PUT _cluster/settings{"transient" : {"cluster.routing.allocation.exclude._name" : "node-1"}}执行命令后,分片开始迁移,我们可以通过_cat/shard API来查看该节点的分片是否迁移完毕。当节点维护完毕,重新上线之后,需要取消排除设置,以便后续的分片可以分配到node-1节点上。PUT _cluster/settings{"transient" : {"cluster.routing.allocation.exclude._name" : ""}}
独立部署主节点
将主节点和数据节点分离部署最大的好处是 Master 切换过程可以迅速完成,有机会跳过gateway和分片重新分配的过程。

节点层

不要为bulk和search分配过大的队列,队列并非越大越好,队列缓存的数据越多,GC压力越大,默认的队列大小基本够用了,即使在压力测试的场景中,默认队列大小也足以支持。
搜索操作很依赖对系统cache的命中,标准的建议是把50%的可用内存作为ES的堆内存,为Lucene保留剩下的50%,用作系统cache。

系统层

在服务器系统上,无论物理内存多么小,哪怕只有1GB,都应该关闭交换分区。当服务程序在交换分区上缓慢运行时,往往会产生更多不可预期的错误,因此当一个申请内存的操作如果真的遇到物理内存不足时,宁可让它直接失败。
如果ES与其他服务混合部署,当系统产生OOM的时候,ES有可能会无辜被“杀”。为了避免这种情况,我们可以在用户态调节一些进程参数来让某些进程不容易被OOM Killer“杀掉”。例如,我们不希望ES进程被“杀”,可以设置进程的oom_score_adj参数为-17(越小越不容易被杀):
$jps1849 Elasticsearch
$cat /proc/1849/oom_score_adj0
$sudo echo -17 > /proc/1849/oom_score_adj可以将这个信息写到ES的启动脚本中自动执行。
优化内核参数
调节内核参数可以通过两种方式:
(1)临时设置,系统重启后失效。通过 sysctl -w 来设置,例如:sysctl -w net.ipv4.tcp_timestamps=1,命令执行后该参数立即生效。
(2)永久设置,将参数写入配置文件/etc/sysctl.conf,然后执行sysctl -p使其生效。

  1. TCP相关参数
    net.ipv4.tcp_syn_retries默认值为6,参考值为2。主机作为客户端,对外发起TCP连接时,即三次握手的第一步,内核发送SYN报文的重试次数,超过这个次数后放弃连接。内网环境通信良好,因此可以适度降低此值。net.ipv4.tcp_synack_retries默认值为5,参考值为2。主机作为服务端,接受TCP连接时,在三次握手的第二步,向客户端发送SYN+ACK报文的重试次数,超过这个次数后放弃连接。内网环境中可适度降低此值。net.ipv4.tcp_timestamps默认值为1,参考值为1。是否开启时间戳,开启后可以更精确地计算RTT,一些其他特性也依赖时间戳字段。net.ipv4.tcp_tw_reuse默认值为0,建议值为1。是否允许将处于TIME_WAIT状态的socket用于新的TCP连接。这对于降低TIME_WAIT数据很有效。该参数只有在开启tcp_timestamps的情况下才会生效。net.ipv4.tcp_tw_recycle默认值为0,参考值为0。是否开启TIME_WAIT套接字的快速回收,这是比tcp_tw_reuse更激进的一种方式,它同样依赖tcp_timestamps选项。强烈建议不要开启tcp_tw_recycle,原因有两点,一是TIME_WAIT是十分必要的状态,避免关闭中的连接与新建连接之间的数据混淆,二是tcp_tw_recycle选项在NAT环境下会导致一些新建连接被拒绝,因为NAT下每个主机存在时差,这体现在套接字中的时间戳字段,服务端会发现某个IP上的本应递增的时间戳出现降低的情况,时间戳相对降低的报文将被丢弃。net.core.somaxconn默认值为128,参考值为2048。定义了系统中每一个端口上最大的监听队列的长度。当服务端监听了某个端口时,操作系统内部完成对客户端连接请求的三次握手。这些已建立的连接存储在一个队列中,等待accept调用取走。本选项就是定义这个队列的长度。该队列实际大小取决于listen调用传入的第二个参数:backlog和本选项的最小值:min(backlog,somaxconn)。ES需要建立许多连接,当集群节点数比较大,集群完全重启时可能会在瞬间建立大量连接,默认的连接队列长度可能不够用,因此适当提高此值。net.ipv4.tcp_max_syn_backlog默认值为128,参考值为8192。内核会服务端的连接建立两个队列:· 已完成三次握手,连接已建立,等待accept的队列,全局长度由somaxconn定义。· 三次握手执行到第二步,等待客户端返回ACK,这些未完成的连接单独放到一个队列中,由tcp_max_syn_backlog定义队列大小。由于可能会有较多的连接数,我们适度增加“未完成连接”的队列大小。net.ipv4.tcp_max_tw_buckets默认值为4096,参考值为180000。定义系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数,则TIME_WAIT套接字将立刻被清除并打印警告信息。如果系统被TIME_WAIT过多问题困扰,则可以调节tcp_max_tw_buckets、tcp_tw_reuse、tcp_timestamps三个选项来缓解。TIME_WAIT状态产生在TCP会话关闭时主动关闭的一端,如果想从根本上解决问题,则让客户端主动关闭连接,而非服务端。net.ipv4.tcp_max_orphans默认值为4096,参考值为262144。定义最大孤儿套接字(未附加到任何用户文件句柄的套接字)数量。如果孤儿套接字数量超过此值,则这些连接立即“reset”,并显示警告信息。该值可以简单地抵御DOS攻击,但不能通过降低此值来抵御DOS。为了应对高负载,应该提高此值。
  2. TCP的接收窗口(RWND)
    TCP采用两个基本原则决定何时发送及发送多少数据:· 流量控制,为了确保接收者可以接收数据。· 拥塞控制,为了管理网络带宽。流量控制通过在接收方指定接收窗口大小来实现。接收窗口用于接收端告诉发送端,自己还有多大的缓冲区可以接收数据。发送端参考这个值来发送数据,就不会导致客户端处理不过来。接收窗口的大小可以通过内核参数来调整,其理想值是 BDP(bandwidth-delay product):服务端可以发出的未被客户端确认的数据量,也就是在网络上缓存的数据量。
    例如,在千兆的网络上,RTT为10毫秒,那么BDP=(1000/8)×0.01s=1.25MB。在这种情况下,如果想最大限度地提升TCP吞吐量,则RWND大小不应小于1.25MB。
    可以通过下面的选项调整RWND:net.ipv4.tcp_rmem = 默认情况下,系统会在最大值和最小值之间自动调整缓冲区大小,是否自动调整通过tcp_moderate_rcvbuf选项来决定。在开启缓冲自动调整的情况下,可以把最大值设置为BDP。
    TCP 使用2个字节记录窗口大小,因此最大值为64KB,如果超过这个值,则需要使用tcp_window_scaling机制,通过下面的设置开启(默认启用):
    net.ipv4.tcp_window_scaling = 1RWND和CWND可能是让系统达到最大吞吐量的两个限制因素,接下来我们讨论CWND。
  3. TCP的拥塞窗口(CWND)
    TCP的滑动窗口机制依据接收端的能力来进行流控,并不能感知网络延迟等网络因素。拥塞控制机制会评估网络能承受的负荷,避免过量数据发送到网络中,拥塞程度会涉及主机、路由器等网络上的所有因素。
    慢启动的意思是对于刚建立的连接,开始发送数据时,一点点提速,而不是一下子使用很大的带宽。慢启动是指数上升的过程,直到CWND≥ssthresh,进入拥塞避免算法。
    本节我们讨论的问题就是调节初始拥塞窗口(INITCWND)的大小。适度增加INITCWND可以降低HTTP响应延迟,可以参考Google的论文:An Argument for Increasing TCP's Initial Congestion Window。例如,HTTP要返回的内容为20K,MSS的大小为1460,整个内容需要传送15个MSS。当INITCWND为3时,服务端先发送3个MSS,1460×3=4380字节,待客户端ACK后,根据指数增加算法,第二次发送9个MSS,1460×9=13140字节,第三次发送3个MSS的剩余字节。整个传输过程经过了3次RTT。如果INITCWND设置为15,则只需要一次RTT就可以完成传输。
  4. vm相关参数
    写缓存可以提升I/O速度,但存在数据丢失的风险。例如,在尚未刷盘的时候主机断电。
    系统当前page cache信息可以通过/proc/meminfo文件查看。下面我们讨论一下写缓存的细节和控制策略。从page cache刷到磁盘有以下三种时机:
    · 可用物理内存低于特定阈值时,为了给系统腾出空闲内存;
    · 脏页驻留时间超过特定阈值时,为了避免脏页无限期驻留内存;
    · 被用户的sync()或fsync()触发。由系统执行的刷盘有两种写入策略:
    · 异步执行刷盘,不阻塞用户I/O;
    · 同步执行刷盘,用户I/O被阻塞,直到脏页低于某个阈值。
    在一般情况下,系统先执行第一种策略,当脏页数据量过大,异步执行来不及完成刷盘时,切换到同步方式。我们可以通过内核参数调整脏数据的刷盘阈值:
    · vm.dirty_background_ratio,默认值为10。该参数定义了一个百分比。当内存中的脏数据超过这个百分比后,系统使用异步方式刷盘。
    · vm.dirty_ratio,默认值为30。同样定义了一个百分比,当内存中的脏数据超过这个百分比后,系统使用同步方式刷盘,写请求被阻塞,直到脏数据低于dirty_ratio。如果还高于 dirty_background_ratio,则切换到异步方式刷盘。因此 dirty_ratio 应高于dirty_background_ratio。除了通过百分比控制,还可以指定字节大小,类似的参数有:dirty_background_bytesdirty_bytes
    · vm.dirty_expire_centisecs,默认值为3000(30秒),单位为百分之1秒,定义脏数据的过期时间,超过这个时间后,脏数据被异步刷盘。
    · vm.dirty_writeback_centisecs,默认值为500(5秒),单位为百分之1秒,系统周期性地启动线程来检查是否需要刷盘,该选项定义这个间隔时间。可以通过下面的命令查看系统当前的脏页数量:cat /proc/vmstat | egrep "dirty|writeback"nr_dirty 951nr_writeback 0nr_writeback_temp 0输出显示有951个脏页等待写到磁盘。默认情况下每页大小为4KB。另外,也可以在/proc/meminfo文件中看到这些信息。
    如果数据安全性要求没有那么高,想要多“cache”一些数据,让读取更容易命中,则可以增加脏数据占比和过期时间:
    vm.dirty_background_ratio = 30vm.dirty_ratio = 60vm.dirty_expire_centisecs = 6000反之则可以降低它们。如果只希望写入过程不要被系统的同步刷盘策略影响,则可以让系统多容纳脏数据,但早一些触发异步刷盘。这样也可以让I/O更平滑:vm.dirty_background_ratio = 5vm.dirty_ratio = 60
    5. 禁用透明大页(Transparent Hugepages)
    可以通过下面的命令检查其是否开启:
    cat /sys/kernel/mm/transparent_hugepage/enabled[always] madvise neveralways代表开启,通过下面的命令将其禁用(系统重启后失效):echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled