阅读 1283

Elasticsearch生产环境部署及配置规划深入剖析-搜索系统线上实战

本套技术专栏作者(秦凯新)专注于大数据及容器云核心技术解密,具备5年工业级IOT大数据云平台建设经验,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

1. ES部署须知

1.1 包结构

es安装包的目录结构大致如下:

  • bin:存放es的一些可执行脚本,比如用于启动进程的elasticsearch命令,以及用于安装插件的elasticsearch-plugin插件
  • conf:用于存放es的配置文件,比如elasticsearch.yml
  • data:用于存放es的数据文件,就是每个索引的shard的数据文件
  • logs:用于存放es的日志文件
  • plugins:用于存放es的插件
  • script:用于存放一些脚本文件

1.2 zen discovery集群发现机制

  • 默认情况下,es进程会绑定在自己的回环地址上,也就是127.0.0.1,然后扫描本机上的9300~9305端口号,尝试跟那些端口上启动的其他es进程进行通信,然后组成一个集群。这对于在本机上搭建es集群的开发环境是很方便的。但是对于生产环境下的集群是不行的,需要将每台es进程绑定在一个非回环的ip地址上,才能跟其他节点进行通信,同时需要使用集群发现机制来跟其他节点上的es node进行通信。

      elasticsearch.yml
      network.host:服务主机ip
      http.port:9200
    复制代码
  • 在生产环境中的多台机器上部署es集群,就涉及到了es的discovery机制,也就是集群中各个节点互相发现然后组成一个集群的机制,同时discovery机制也负责es集群的master选举。

  • ES是一种peer to peer,也就是p2p点对点的分布式系统架构,不是hadoop生态普遍采用的那种master-slave主从架构的分布式系统。集群中的每个node是直接跟其他节点进行通信的,而不是hadoop生态系统中的那种master-slave分布式系统架构。几乎所有的API操作,比如index,delete,search,等等,都不是说client跟master通信,而是client跟任何一个node进行通信,那个node再将请求转发给对应的node来进行执行。

  • 两个角色,master node,data node。正常情况下,就只有一个master node。master node的责任就是负责维护整个集群的状态信息,也就是一些集群元数据信息,同时在node加入集群或者从集群中下线时,重新分配shard,或者是创建或删除了一个索引。包括每次cluster state如果有改变的化,那么master都会负责将集群状态同步给所有的node。

  • master node负责接收所有的cluster state相关的变化信息,然后将这个改变后的最新的cluster state推动给集群中所有的data node,集群中所有的node都有一份完整的cluster state。只不过master node负责维护而已。其他的node,除了master之外的node,就是负责数据的存储和读写的,写入索引,搜索数据,data node。

  • 如果要让多个node组成一个es集群,首先第一个要设置的参数,就是cluster.name,多个node的cluster.name如果一样,才满足组成一个集群的基本条件。这个cluster.name的默认值是elasticsearch,在生产环境中,一定要修改这个值,否则可能会导致未知的node无端加入集群,造成集群运行异常。

      elasticsearch.yml
      cluster.name:cluster-elasticearch-prod
      node.name:node-01
    复制代码
  • 而es中默认的discovery机制,就是zen discovery机制,zen discovery机制提供了unicast discovery集群发现机制,集群发现时的节点间通信是依赖的transport module,也就是es底层的网络通信模块和协议。

  • es默认配置为使用unicast集群发现机制,以让经过特殊配置的节点可以组成一个集群,而不是随便哪个节点都可以组成一个集群。但是默认配置下,unicast是本机,也就是localhost,因此只能在一台机器上启动多个node来组成一个集群。

  • 虽然es还是会提供multicast plugin作为一个发现机制,但是已经不建议在生产环境中使用了。虽然我们可能想要multicast的简单性,就是所有的node可以再接收到一条multicast ping之后就立即自动加入集群。但是multicast机制有很多的问题,而且很脆弱,比如网络有轻微的调整,就可能导致节点无法发现对方。

  • 因此现在建议在生产环境中用unicast机制,提供一个es种子node作为中转路由节点就可以了。

1.3 zen discovery集群设置规划

  • 给集群规划出专门的master eligible node和data node,

  • master node,master eligible node,data node

  • 你配置的时候,是配置多个node变成master eligible node,但是只是说,从这些master eligible node选举一个node出来作为master node,其他master eligible node只是接下来有那个master node故障的时候,接替他的资格,但是还是作为data node去使用的

  • 一般建议master eligible node给3个即可:node.master: true,node.data: false 剩下的node都设置为data node:node.master: false,node.data: true

  • 但是如果一个小集群,就10个以内的节点,那就所有节点都可以作为master eligible node以及data node即可,超过10个node的集群再单独拆分master和data node吧,如果你的节点数量小于10个,小集群,那所有的node,就不要做额外的配置了,master eligible node,同时也是data node

  • 默认情况下,es会将自己绑定到127.0.0.1上,对于运行一个单节点的开发模式下的es是ok的。但是为了让节点间可以互相通信以组成一个集群,需要让节点绑定到一个ip地址上,非会换的地址,一般会配置:network.host: 192.168.1.10。一旦我们配置了network.host,那么es就会认为我们从开发模式迁移到生产模式,同时会启用一系列的bootstrap check。

  • 本套技术专栏作者(秦凯新)专注于大数据及容器云核心技术解密,具备5年工业级IOT大数据云平台建设经验,可提供全栈的数据云平台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

1.4 zen discovery发现机制原理

1.4.1 ping机制

ping是一个node用discovery机制来发现其他node的一个过程。

1.4.2 unicast机制

  • unicast discovery集群发现机制是要求配置一个主机列表,用来作为gossip(流言式)通信协议的路由器。这些机器如果通过hostname来指定,那么在ping的时候会被解析为ip地址。unicast discovery机制最重要的两个配置如下所示:

  • hosts:用逗号分割的主机列表

  • hosts.resolve_timeout:hostname被DNS解析为ip地址的timeout等待时长

  • 简单来说,如果要让多个节点发现对方并且组成一个集群,那么就得有一个中间的公共节点,然后不同的节点就发送请求到这些公共节点,接着通过这些公共节点交换各自的信息,进而让所有的node感知到其他的node存在,并且进行通信,最后组成一个集群。这就是基于gossip流言式通信协议的unicast集群发现机制。

  • 当一个node与unicast node list中的一个成员通信之后,就会接收到一份完整的集群状态,这里会列出集群中所有的node。接着那个node再通过cluster state跟master通信,并且加入集群中。这就意味着,我们的unicast list node是不需要列出集群中的所有节点的。只要提供少数几个node,比如3个,让新的node可以连接上即可。如果我们给集群中分配了几个节点作为专门的master节点,那么只要列出我们那三个专门的master节点即可。

      elasticsearch.yml
      discovery.zen.ping.unicast.hosts: ["host1", "host2"]
    复制代码

1.4.3 unicast机制总体流程

(1)初步配置好后,各个节点,首先通过network.host绑定到了非回环的ip地址,从而可以跟其他节点通信
(2)通过discovery.zen.ping.unicast.hosts配置了一批unicast中间路由的node
(3)所有node都可以发送ping消息到路由node,再从路由node获取cluster state回来
(4)接着所有node会选举出一个master
(5)所有node都会跟master进行通信,然后加入master的集群
(6)要求cluster.name必须一样,才能组成一个集群
(7)node.name就标识出了每个node我们自己设置的一个名称
复制代码

1.4.4 master选举

  • 在ping发现过程中,为集群选举出一个master也是很重要的,es集群会自动完成这个操作。这里建议设置discovery.zen.ping_timeout参数(默认是3s),如果因为网络慢或者拥塞,导致master选举超时,那么可以增加这个参数,确保集群启动的稳定性。

  • 在完成一个集群的master选举之后,每次一个新的node加入集群,都会发送一个join request到master node,可以设置discovery.zen.join_timeout保证node稳定加入集群,增加join的timeout等待时长,如果一次join不上,默认会重试20次。

  • 如果master node被停止了,或者自己宕机了,那么集群中的node会再次进行一次ping过程,并且选举出一个新的master。如果discovery.zen.master_election.ignore_non_master_pings设置为了true,那么会强制区分master候选节点,如果node的node.master设置为了false,还来发送ping请求参与master选举,那么这些node会被忽略掉,因为他们没有资格参与。

  • discovery.zen.minimum_master_nodes参数用于设置对于一个新选举的master,要求必须有多少个master候选node去连接那个新选举的master。而且还用于设置一个集群中必须拥有的master候选node。如果这些要求没有被满足,那么master node就会被停止,然后会重新选举一个新的master。这个参数必须设置为我们的master候选node的quorum数量。一般避免说只有两个master候选node,因为2的quorum还是2。如果在那个情况下,任何一个master候选节点宕机了,集群就无法正常运作了。

  • 本套技术专栏作者(秦凯新)专注于大数据及容器云核心技术解密,具备5年工业级IOT大数据云平台建设经验,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系

1.4.5 集群故障的探查

  • es有两种集群故障探查机制,第一种是通过master进行的,master会ping集群中所有的其他node,确保它们是否是存活着的。第二种,每个node都会去ping master node来确保master node是存活的,否则就会发起一个选举过程。

  • 有下面三个参数用来配置集群故障的探查过程:

      ping_interval:每隔多长时间会ping一次node,默认是1s
      ping_timeout:每次ping的timeout等待时长是多长时间,默认是30s
      ping_retries:如果一个node被ping多少次都失败了,就会认为node故障,默认是3次
    复制代码

1.4.6 集群状态更新

  • master node是集群中唯一一个可以对cluster state进行更新的node。master node每次会处理一个集群状态的更新事件,应用这次状态更新,然后将更新后的状态发布到集群中所有的node上去。每个node都会接收publish message,ack这个message,但是不会应用这个更新。如果master没有在discovery.zen.commit_timeout指定的时间内(默认是30s),从至少discovery.zen.minimum_master_nodes个节点获取ack响应,那么这次cluster state change事件就会被reject,不会应用。

  • 但是一旦在指定时间内,指定数量的node都返回了ack消息,那么cluster state就会被commit,然后一个message会被发送给所有的node。所有的node接收到那个commit message之后,接着才会将之前接收到的集群状态应用到自己本地的状态副本中去。

  • 接着master会等待所有节点再次响应是否更新自己本地副本状态成功,在一个等待超时时长内,如果接收到了响应,那么就会继续处理内存queue中保存的下一个更新状态。discovery.zen.publish_timeout默认是30s,这个超时等待时长是从plublish cluster state开始计算的。

1.4.6 master宕机阻塞策略配置

  • 如果要让集群正常运转,那么必须有一个master,还有discovery.zen.minimum_master_nodes指定数量的master候选node,都在运行。discovery.zen.no_master_block可以控制当master宕机时,什么样的操作应该被拒绝。有下面两个选项:

      all:一旦master宕机,那么所有的操作都会被拒绝
      write:这是默认的选项,所有的写操作都会被拒绝,但是读操作是被允许的
    复制代码

2 默认参数调优

3.1 集群名称和节点名称

默认情况下,es会启动一个名称为elasticsearch的集群。通常建议一定要将自己的集群名称重新进行命名,主要是避免公司网络环境中,也许某个开发人员的开发机会无意中加入你的集群。比如说将你的集群名称命名为elasticsearch_production。在elasticsearch.yml中,可以设置集群名称:cluster.name: elasticsearch_production。

3.2 默认参数

es的默认参数是非常好的,适合绝大多数的情况,尤其是一些性能相关的配置。因此刚开始部署一个生产环境下的es集群时,几乎所有的配置参数都可以用默认的设置。有很多的生产环境场景下,都是因为es集群管理人员自己去调整es的某些配置,结果导致集群出现了严重的故障,那些es集群管理员甚至还以为做出那些调节可以将es性能提升一百倍以上。但是,采用SSD盘不会差。

3.3 文件路径

  • 默认情况下,es会将plugin,log,还有data ,config,file都放在es的安装目录中。这有一个问题,就是在进行es升级的时候,可能会导致这些目录被覆盖掉。导致我们丢失之前安装好的plugin,已有的log,还有已有的数据,以及配置好的配置文件。

  • 所以一般建议在生产环境中,必须将这些重要的文件路径,都重新设置一下,放在es安装目录之外。path.data用于设置数据文件的目录,path.logs用于设置日志文件的目录,path.plugins用于设置插件存放的目录。

  • path.data可以指定多个目录,用逗号分隔即可。如果多个目录在不同的磁盘上,那么这就是一个最简单的RAID 0的方式,将数据在本地进行条带化存储了,可以提升整体的磁盘读写性能。es会自动将数据在多个磁盘的多个目录中条带化存储数据。

  • 一般建议的目录地址是:

      mkdir -p /var/log/elasticsearch
      mkdir -p /var/data/elasticsearch
      mkdir -p /var/plugin/elasticsearch
      mkdir -p /etc/elasticsearch
    
      elasticsearch.yml
      path.logs: /var/log/elasticsearch
      path.data: /var/data/elasticsearch
      path.plugins: /var/plugin/elasticsearch
    
      config:/etc/elasticsearch
    复制代码
  • 在RAID 0的存储级别下,每个磁盘上会存储一部分数据,但是如果一个磁盘故障了,那么可能导致这台机器上的部分数据就丢失了。如果我们的es是有replica的,那么在其他机器上还是会有一份副本的。

  • 如果data file指定了多个目录,为了尽量减少数据丢失的风险,es会将某个shard的数据都分配到一个磁盘上去。这就意味着每个shard都仅仅会放在一个磁盘上。es不会将一个shard的数据条带化存储到多个磁盘上去,因为如果一个磁盘丢失了,就会导致整个shard数据丢失。

  • 但是这又引入了性能的问题,如果我们给一个机器添加更多的磁盘来提升单个索引的读写性能,是没有效果的。因为这个索引在这个机器上的shard仅仅存在于一个磁盘上。因此data file指定多个目录,仅仅对于你的一台机器上存储了多个index的多个shard时,才会有效果的。因为不同index的shard可能就被存储到不同的磁盘上去了,对多个index的shard读写可以走不同磁盘,提升了性能。

  • 虽然multiple data path是一个很有用的功能,但是es毕竟不是一个专门的RAID软件。如果我们要对RAID存储策略进行更多的配置,提高存储的健壮性以及灵活性,还是要用专门的RAID软件来进行机器的磁盘数据存储,而不是用multiple data path策略。综上所述,multiple data path功能在实际的生产环境中,其实是较少使用的。

3.4 配置文件目录

es有两个配置文件,elasticsearch.yml,用于配置es,还有一个log4j.properties用来配置es日志打印。这些文件都被放在config目录下,默认就是ES_HOME/config。可以通过下面的命令来重新设置:

./bin/elasticsearch -Epath.conf=/path/to/my/config/。
复制代码

配置文件的格式是yaml格式的,比如下面这种格式:

path:
    data: /var/lib/elasticsearch
    logs: /var/log/elasticsearch
	
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
复制代码

3.5 日志配置

  • es使用log4j2来记录日志,log4j2可以通过log4j2.properties文件来进行配置。比如下面的这份配置文件:

      appender.rolling.type = RollingFile 
      appender.rolling.name = rolling
      appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log 
      appender.rolling.layout.type = PatternLayout
      appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
      appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}.log 
      appender.rolling.policies.type = Policies
      appender.rolling.policies.time.type = TimeBasedTriggeringPolicy 
      appender.rolling.policies.time.interval = 1 
      appender.rolling.policies.time.modulate = true 
    
      appender.rolling.type = RollingFile,就配置了appender类型是RollingFile
      
      appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log,就配置了日志路径是/var/log/elasticsearch/production.log
      
      appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}.log,就配置了将日志每天写一份到/var/log/elasticsearch/production-2017-01-01.log文件中
      
      appender.rolling.policies.time.type = TimeBasedTriggeringPolic,这里配置了用基于时间的roll策略
      
      appender.rolling.policies.time.interval = 1,这个设置了每天一份日志文件
      
      appender.rolling.policies.time.modulate = true,这个设置了根据自然天来划分文件,而不是24小时
    复制代码
  • 还可以配置将日志文件保留一段时间内,同时删除之前的日志文件

     appender.rolling.strategy.type = DefaultRolloverStrategy 
     appender.rolling.strategy.action.type = Delete 
     appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path} 
     appender.rolling.strategy.action.condition.type = IfLastModified 
     appender.rolling.strategy.action.condition.age = 7D 
     appender.rolling.strategy.action.PathConditions.type = IfFileName 
     appender.rolling.strategy.action.PathConditions.glob = ${sys:es.logs.cluster_name}-* 
    
     第一行是配置了默认的DefaultRolloverStrategy
     第二行是配置了Delete action,在rollover之后,就会删除文件
     第三行是配置了es log的基础路径
     第四行是配置了rollover发生的条件,是基于IfLastModified
     第五行是配置了保留的天数,这里是7天
     第六行是配置了删除匹配7天前的文件
     第七行是配置了一个删除文件的格式,这样就只是删除过期日志文件,但是不要删除慢查询日志
    复制代码

3.6 脑裂产生避免

  • discovery.zen.minimum_master_nodes参数对于集群的可靠性来说,是非常重要的。这个设置可以预防脑裂问题。如果因为网络的故障,导致一个集群被划分成了两片,每片都有多个node,以及一个master,那么集群中就出现了两个master了。但是因为master是集群中非常重要的一个角色,主宰了集群状态的维护,以及shard的分配,因此如果有两个master的化,可能会导致破坏数据。那么那个参数的作用,就是告诉es直到有足够的master候选节点时,才可以选举出一个master,否则就不要选举出一个master。这个参数必须被设置为集群中master候选节点的quorum数量,也就是大多数。至于quorum的算法,就是:master候选节点数量 / 2 + 1。比如我们有10个节点,都能维护数据,也可以是master候选节点,那么quorum就是10 / 2 + 1 = 6。如果我们有三个master候选节点,还有100个数据节点,那么quorum就是3 / 2 + 1 = 2

  • 综上所述,一个生产环境的es集群,至少要有3个节点,同时将这个参数设置为quorum,也就是2。

  • discovery.zen.minimum_master_nodes设置为2,如何避免脑裂呢?比如我们有3个节点,quorum是2.现在网络故障,1个节点在一个网络区域,另外2个节点在另外一个网络区域,不同的网络区域内无法通信。这个时候有两种情况情况:

      (1)如果master是单独的那个节点,另外2个节点是master候选节点,那么此时那个单独的master节点因为没有指定数量
           的候选master node在自己当前所在的集群内,因此就会取消当前master的角色,尝试重新选举,但是无法选举成功
           。然后另外一个网络区域内的node因为无法连接到master,就会发起重新选举,因为有两个master候选节点,满足
           了quorum,因此可以成功选举出一个master。此时集群中就会还是只有一个master。
      
      (2)如果master和另外一个node在一个网络区域内,然后一个node单独在一个网络区域内。那么此时那个单独的node因
           为连接不上master,会尝试发起选举,但是因为master候选节点数量不到quorum,因此无法选举出master。而另外
           一个网络区域内,原先的那个master还会继续工作。这也可以保证集群内只有一个master节点。
    
    综上所述,通过在elasticsearch.yml中配置discovery.zen.minimum_master_nodes: 2,就可以避免脑裂问题的产生。
    复制代码
  • 因为es集群是可以动态增加和下线节点的,所以可能随时会改变quorum。所以这个参数也是可以通过api随时修改的,特别是在节点上线和下线的时候,都需要作出对应的修改。而且一旦修改过后,这个配置就会持久化保存下来。

      PUT /_cluster/settings
      {
          "persistent" : {
              "discovery.zen.minimum_master_nodes" : 2
          }
      }
    复制代码

3.7 集群重启时的无意义shard重分配避免

  • shard重新复制,移动,删除,再次移动的过程,会大量的耗费网络和磁盘资源。对于数据量庞大的集群来说,可能导致每次集群重启时,都有TB级别的数据无端移动,可能导致集群启动会耗费很长时间。但是如果所有的节点都可以等待整个集群中的所有节点都完全上线之后,所有的数据都有了以后,再决定是否要复制和移动shard,情况就会好很多。

  • gateway.recover_after_nodes: 8。这个参数可以让es直到有足够的node都上线之后,再开始shard recovery的过程。所以这个参数是跟具体的集群相关的,要根据我们的集群中节点的数量来决定。

  • 此外,还应该设置一个集群中至少要有多少个node,等待那些node的时间:gateway.expected_nodes: 10,gateway.recover_after_time: 5m。

  • 经过上面的配置之后,es集群的行为会变成下面这样,等待至少8个节点在线,然后等待最多5分钟,或者10个节点都在线,开始shard recovery的过程。这样就可以避免少数node启动时,就立即开始shard recovery,消耗大量的网络和磁盘资源,甚至可以将shard recovery过程从数小时缩短为数分钟。

3.8 JVM heap分配策略

  • es默认会给jvm heap分配2个G的大小,对于几乎所有的生产环境来说,这个内存都太小了。如果用这个默认的heap size,那么生产环境的集群肯定表现不会太好。

  • 有两个方式来调节es中的jvm heap size。最简单的就是设置环境变量,ES_HEAP_SIZE。当es进程启动的时候,会读取这个环境变量的值,然后设置为jvm的heap size。举例来说,可以这样来设置:export ES_HEAP_SIZE=10g。此外,还可以在启动es进程的时候,传递一个jvm的option,比如:ES_JAVA_OPTS="-Xms10g -Xmx10g" ./bin/elasticsearch,但是要注意-Xms和-Xmx最小和最大堆内存一定设置的一样,避免运行过程中的jvm heap resize,那会是一个非常耗时的过程。

  • 在老版本的es中,比如es 2.x里面,一般推荐用ES_HEAP_SIZE环境变量的方式来设置jvm heap size。

  • 在新版本的es中,比如es 5.x里面,一般推荐在jvm.options文件里面去设置jvm相关的参数。

  • 虽然heap对于es来说是非常重要的,jvm heap被es用来存放很多内存中的数据结构来提供更快的操作性能。但是还有另外一个内存的用户,那就是lucene。lucene的设计就是要使用底层的os filesystem cache来缓存数据结构。lucene的segment是保存在单独的文件中的。因为这些segment是不可变的,所以这些文件实际上也从来不会改变。这样的话,就可以更好的缓存这些文件,底层的os cache会将hot segment驻留在内存中以供更快的访问。这些segment包括了倒排索引(为了全文检索)以及正排索引(为了聚合操作)。lucene的性能是严重依赖于底层的os的,但是如果我们给了过多的内存到es的jvm heap,那么就没有足够的内存留给lucene。这会极大的影响性能。

  • 一般建议的是,将50%的内存分配给es jvm heap,然后留50%的内存给os cache。留给os cache的内存是不会不使用的,lucene会将剩下的内存全部用光,用来cache segment file。如果我们没有对任何分词的text field进行聚合操作,那么我们就不需要使用fielddata,我们甚至可以考虑给os cache更多的内存,因为fielddata是要用jvm heap。如果我们给jvm heap更少的内存,那么实际上es的性能反而会更好,因为更多的内存留给了lucene用os cache提升索引读写性能,同时es的jvm heap的gc耗时会更少。

  • 不要给jvm分配超过32G内存,如果heap小于32G的化,jvm会用一种技术来压缩对象的指针,object pointer。在java中,所有的对象都会被分配到heap中,然后被一个pointer给引用。object pointer会指向heap中的对象,引用的是二进制格式的地址。

  • 对于32位的系统来说,jvm最大的heap size就是4G,解释一下,32位,0和1值,0和1在32位的组合是2^32次方的字节,除以1024就是多少k,再除以1024就是多少mb,再除以1024就是多少gb,最后算下来就是4G。对于64位的系统来说,heap size可以更大,但是64位的object pointer会耗费更多的空间,因为object pointer更大了。比浪费更多内存空间更恶劣的是,过大的object pointer会在cpu,main memory和LLC、L1等多级缓存间移动数据的时候,吃掉更多的带宽。

  • 所以jvm用了一种技术,叫做compressed oops来解决object pointer耗费过大空间的问题。这个技术的核心思想是,不要让object pointer引用内存中的二进制地址,而是让object pointer引用object offset。这就意味着32位的pointer可以引用400万个对象,而不是400万字节。这也意味着,使用32位的pointer,最大的heap大小可以到32G。此时只要heap size在32G以内,jvm就会自动启用32位的object pointer,因为32位的对象指针,足够引用32G的内存了,就可以用32位的pointer替代64位的pointer。但是32位的pointer比64位的pointer可以耗费更少的内存耗费。

  • 越过了32G这个界限,就是给jvm heap分配了超过32G的内存,因为32位的pointer最多引用32G的内存,超过了32G,就没法用32位pointer。不用32位pointer,就只能用64位pointer,才能引用超过32G的内存空间。此时pointer就会退回到传统的object pointer引用对象的二进制地址的模式,此时object pinter的大小会急剧增长,更多的cpu到内存的带宽会被占据,更多的内存被耗费。实际上,不用compressed oops时,你如果给jvm heap分配了一个40~50G的内存的可用空间,实际上被object pointer可能都要占据十几G的内存空间,可用的空间量,可能跟使用了compressed oops时的32GB内存的可用空间,20多个G,几乎是一样的。

  • 在32G以内的话具体应该设置heap为多大?

      这个是根据具体情况而定的,不是固定死的,根据不同的jvm和平台而变。一般而言,将jvm heap
      size设置为31G比较安全一些。主要是要确保说,你设置的这个jvm heap大小,可以让es启用compressed
      oops这种优化机制。此外,可以给jvm option加入-XX:+PrintFlagsFinal,然后可以打印出来UseCompressedOops
      是否为true。这就可以让我们找到最佳的内存设置。因为可以不断调节内存大小,然后观察是否启用compressed oops。
    
      举例来说,如果在mac os上启动一个java 1.7,同时将heap size设置为32600mb,那么compressed
      oops是会开启的;但是如果设置为32766m,compressed oops就不会开启。
      相反的是,使用jdk 1.8的化,分配32766m,compressed oops是会开启的,设置为32767m,就不会开启。
      所以说,这个东西不是固定的。根据不同的操作系统以及jvm版本而定。
          
      在es启动日志中,我们可以查看compressed oops是否开启,比如下面的字样:
      [2015-12-16 13:53:33,417][INFO ][env] [Illyana Rasputin] heap size [989.8mb], 
      compressed ordinary object pointers [true]。
    复制代码
  • 对于有1TB内存的超大内存机器该如何分配?(一般64G)

    如果我们的机器是一台超级服务器,内存资源甚至达到了1TB,或者512G,128G,该怎么办?首先es官方是建议避免用这种超级服务器来部署es集群的,但是如果我们只有这种机器可以用的话,我们要考虑以下几点:

      (1)我们是否在做大量的全文检索?考虑一下分配4~32G的内存给es进程,同时给lucene留下其余所有的内存用来做
            os filesystem cache。所有的剩余的内存都会用来cache segment file,而且可以提供非常高性能的搜索,
            几乎所有的数据都是可以在内存中缓存的,es集群的性能会非常高
      
      (2)是否在做大量的排序或者聚合操作?聚合操作是不是针对数字、日期或者未分词的string?如果是的化,那么还是
           给es 4~32G的内存即可,其他的留给es filesystem cache,可以将聚合好用的正排索引,doc values放在os cache中
      
      (3)如果在针对分词的string做大量的排序或聚合操作?如果是的化,那么就需要使用fielddata,这就得给jvm
           heap分配更大的内存空间。此时不建议运行一个节点在机器上,而是运行多个节点在一台机器上,那么如果
           我们的服务器有128G的内存,可以运行两个es节点,然后每个节点分配32G的内存,剩下64G留给os  cache。
           如果在一台机器上运行多个es node,建议设置:
           cluster.routing.allocation.same_shard.host: true。这会避免在同一台物理机上分配一个
           primary shard和它的replica shard。
    复制代码

3.9 swapping分配策略

  • 如果频繁的将es进程的内存swap到磁盘上,绝对会是一个服务器的性能杀手。想象一下,内存中的操作都是要求快速完成的,如果需要将内存页的数据从磁盘swap回main memory的化,性能会有多差。如果内存被swap到了磁盘,那么100微秒的操作会瞬间变成10毫秒,那么如果是大量的这种内存操作呢?这会导致性能急剧下降。

  • 因此通常建议彻底关闭机器上的swap,swapoff -a,如果要永久性关闭,需要在/etc/fstab中配置

  • 如果没法完全关闭swap,那么可以尝试调低swappiness,这个值是控制os会如何将内存swap到磁盘的。这会在正常情况下阻止swap,但是在紧急情况下,还是会swap。一般用sysctl来设置,vm.swappiness = 1。如果swappiness也不能设置,那么就需要启用mlockall,这就可以让我们的jvm lock住自己的内存不被swap到磁盘上去,在elasticsearch.yml中可以设置:bootstrap.mlockall: true。

3.10 file descriptor 检查

  • file descriptor是unix操作系统的一种数据结构,用来track打开的文件。在unix操作系统中,所有东西都是file。比如,file可以是物理文件,虚拟文件,或者网络socket。es需要大量的file descriptor,比如说每个shard都由多个segment和其他文件组成,还有跟其他节点之间的网络通信连接。

  • 因为es要使用大量的file descriptor,所以如果file descriptor耗尽的话,会是一场灾难,甚至可能会导致数据丢失。尽量给es的file descriptor提升到65536,甚至更高,可以在/etc/security/limits.conf中,设置nofile为65536。

      1)修改当前交互终端的limit值 
      
      查询当前终端的文件句柄数: ulimit -n 回车,一般的系统默认的1024. 
      
      修改文件句柄数为65535,ulimit -n 65535.此时系统的文件句柄数为65535. 
      
      2)将ulimit 值添加到/etc/profile文件中(适用于有root权限登录的系统) 
      
      为了每次系统重新启动时,都可以获取更大的ulimit值,将ulimit 加入到/etc/profile 文件底部。 
      
      echo ulimit -n 65535 >>/etc/profile 
      
      source /etc/profile    #加载修改后的profile 
      
      ulimit -n     #显示65535,修改完毕!
      
      3)OK,好多朋友都以为大功告成了,可以突然发现自己再次登录进来的时候,ulimit的值还是1024,这是为什么呢? 
      关键的原因是你登录的用户是什么身份,是不是root用户,由于服务器的root用户权限很大,一般是不能用来登录的,都是通过自己本人的登录权限进行登录,并通过sudo方式切换到root用户下进行工作。 用户登录的时候执行sh脚本的顺序: 
      /etc/profile.d/file 
      /etc/profile 
      /etc/bashrc 
      /mingjie/.bashrc 
      /mingjie/.bash_profile 
      
      由于ulimit -n的脚本命令加载在第二部分,用户登录时由于权限原因在第二步还不能完成ulimit的修改,所以ulimit的值还是系统默认的1024。 
      
      解决办法: 
      修改linux的软硬件限制文件/etc/security/limits.conf. 
      
      在文件尾部添加如下代码: 
      * soft nofile 10240
      * hard nofile 10240
    
      4) /etc/security/limits.conf
         elasticsearch hard nofile 65536
      
      5) 可以用上面这行代码检查每个node上的file descriptor数量
      GET _nodes/stats/process?filter_path=**.max_file_descriptors
      
       {
        "cluster_name": "elasticsearch",
        "nodes": {
          "nLd81iLsRcqmah-cuHAbaQ": {
            "timestamp": 1471516160318,
            "name": "Marsha Rosenberg",
            "transport_address": "127.0.0.1:9300",
            "host": "127.0.0.1",
            "ip": [
              "127.0.0.1:9300",
              "NONE"
            ],
            "process": {
              "timestamp": 1471516160318,
              "open_file_descriptors": 155,
              "max_file_descriptors": 10240, 
              "cpu": {
                "percent": 0,
                "total_in_millis": 25084
              },
              "mem": {
                "total_virtual_in_bytes": 5221900288
              }
            }
          }
        }
      }
    复制代码

3.11 maximum size virtual memory 检查

  • es使用mmap来将索引映射到es的address space中,这可以让jvm heap外但是内存中的索引数据,可以有非常高速的读写速度。因此es需要拥有unlimited address space。最大虚拟内存大小的检查,会要求es进程有unlimited address space。

      /etc/security/limits.conf,设置as为unlimited
      elasticsearch hard as unlimited
    复制代码

3.12 maximum map count 检查

  • 要高效使用mmap的话,es同样要求创建许多memory-mapped area。因此要求linux内核允许进程拥有至少262144个memory-mapped area,需要通过sysctl设置vm.max_map_count至少超过262144。

3.13 memory lock 检查

  • 如果jvm进行一个major gc的话,那么就会涉及到heap中的每一个内存页,此时如果任何一个内存页被swap到了磁盘上,那么此时就会被swap回内存中。这就会导致很多的磁盘读写开销,而这些磁盘读写开销如果节省下来,可以让es服务更多的请求。有很多方法可以配置系统禁止swap。其中一种方法就是让jvm去lock heap内存在物理内存中,设置bootstrap.memory_lock即可。

      GET _nodes?filter_path=**.mlockall
    复制代码
  • 检查一下,mlockall是否开启,如果是false,那么说明lock memory失败了,而且日志里可能会有unable to lock jvm memory的字样,可能就是因为运行es的用户没有lock memory的权限,此时就需要进行授权

      /etc/security/limits.conf
      设置memlock为unlimited即可完成授权
      elasticsearch hard memlock unlimited
      elasticsearch soft memlock unlimited
    复制代码
  • 另外一个原因导致lock memory失败,可能是因为临时目录,/tmp用noexec option来mount了

      那么就需要设置
      ES_JAVA_OPTS,
      export ES_JAVA_OPTS="$ES_JAVA_OPTS -Djava.io.tmpdir=/path/to/temp/dir"
      或者在jvm.options中设置这个参数
    复制代码

4 ES运行时

4.1 以daemon模式运行

  • 在生产环境中,会使用daemon进程的方式来启动es,而不是直接采用前台进程的方式来启动es,具体命令如下

      ./bin/elasticsearch -d -p pid
      上面命令中的-d option用来指定es以daemon进程方式启动,
      并且-p option指定将进程id记录在指定文件中
    复制代码
  • es启动后,日志信息可以在ES_HOME/logs目录中查看

  • 启动es进程的时候,还可以直接覆盖一些配置,使用-E即可,如下面的命令,通常用于调试集群参数时,方便快速调节参数,查看效果。

  • es是禁止用root用户去启动es进程,可以加一个配置来允许用root去启动。紧急修复方法:

      adduser elasticsearch
      passwd elasticsearch
      
      chown -R elasticsearch /usr/local/elasticsearch
      chown -R elasticsearch /var/log/elasticsearch
      chown -R elasticsearch /var/data/elasticsearch
      chown -R elasticsearch /var/plugin/elasticsearch
      chown -R elasticsearch /etc/elasticsearch
      chown -R elasticsearch /usr/local/tmp
      
      su elasticsearch
      ./elasticsearch -d -Epath.conf=/etc/elasticsearch
    复制代码

4.2 访问ES

  • 一般建议在管理机上安装一个curl工具,可以手工发送rest api请求,可以对启动了es的节点的9200端口,发送一个GET /请求,可以看看es是否启动成功

      curl -XGET elasticsearch02:9200
      curl -XGET elasticsearch02:9200/_cat/nodes?v
    复制代码

4.3 停止es

  • 优雅的关闭es,可以确保es关闭的很干净,并且优雅关闭资源。举例来说,如果node在一个合理的顺序下关闭了,首先会将自己从cluster中优雅移除,fsync translog日志到磁盘中去,然后执行其他相关的cleanup活动。

  • 如果将es用service的方式来运行,那么可以通过server管理功能来停止es。

  • 如果是直接启动es的,可以control-C停止es,或者是发送SEGTERM信号给es进程

      jps | grep Elasticsearch
      
      kill -SIGTERM 15516
    复制代码

5 集群备份恢复

5.1 原理

  • ES replica提供了运行时的高可用保障机制,可以容忍少数节点的故障和部分数据的丢失,但是整体上却不会丢失任何数据,而且不会影响集群运行。但是replica没法进行灾难性的数据保护,比如说机房彻底停电,所有机器全部当即,等等情况。对于这种灾难性的故障,我们就需要对集群中的数据进行备份了,集群中数据的完整备份。

  • 要备份集群数据,就要使用snapshot api。这个api会将集群当前的状态和数据全部存储到一个外部的共享目录中去,比如NAS,或者hdfs。而且备份过程是非常智能的,第一次会备份全量的数据,但是接下来的snapshot就是备份两次snapshot之间的增量数据了。数据是增量进入es集群或者从es中删除的,那么每次做snapshot备份的时候,也会自动在snapshot备份中增量增加数据或者删除部分数据。因此这就意味着每次增量备份的速度都是非常快的。

  • 如果要使用这个功能,我们需要有一个预先准备好的独立于es之外的共享目录,用来保存我们的snapshot备份数据。es支持多种不同的目录类型:shared filesystem,比如NAS;Amazon S3;hdfs;Azure Cloud。不过对于国内的情况而言,其实NAS应该很少用,一般来说,就用hdfs会比较多一些,跟hadoop这种离线大数据技术栈整合起来使用。

5.2 shared filesystem作为仓库类型

  • shared filesystem作为仓库类型,包括了仓库名称以及仓库类型是fs,还有仓库的地址。这个里面就包含了仓库的一些必要的元数据了。可能还有其他的一些参数可以配置,主要是基于我们的node和网络的性能来配置。max_snapshot_bytes_per_sec,这个参数用于指定数据从es灌入仓库的时候,进行限流,默认是20mb/s。max_restore_bytes_per_sec,这个参数用于指定数据从仓库中恢复到es的时候,进行限流,默认也是20mb/s。假如说网络是非常快速的,那么可以提高这两个参数的值,可以加快每次备份和恢复的速度,比如下面:

      POST _snapshot/my_backup/ 
      {
          "type": "fs",
          "settings": {
              "location": "/mount/backups/my_backup",
              "max_snapshot_bytes_per_sec" : "50mb", 
              "max_restore_bytes_per_sec" : "50mb"
          }
      }
    复制代码
  • 创建一个仓库之后,就可以查看这个仓库的信息了:GET /_snapshot/my_backup,或者是查看所有的仓库,GET /_snapshot/_all。可能返回如下的信息:

      {
        "my_backup": {
          "type": "fs",
          "settings": {
            "compress": true,
            "location": "/mount/backups/my_backup"
          }
        }
      }
    复制代码

5.3 基于hdfs创建仓库

  • 但是其实如果在国内使用es的话,还是建议跟hadoop生态整合使用,不要用那种shared filesystem。可以用hadoop生态的hdfs分布式文件存储系统。首先先要安装repository-hdfs的插件:bin/elasticsearch-plugin install repository-hdfs,必须在每个节点上都安装,然后重启整个集群。

      kill -SIGTERM 15516
      
      su elasticsearch
      elasticsearch -d -Epath.conf=/etc/elasticsearch
      
      curl -XGET elasticsearch02:9200/_cat/nodes?v
    复制代码
  • 在3个hdfs node上,都加入hdfs-site.xml,禁止权限检查,如果要修改这个配置文件,要先在/usr/local/hadoop/sbin,运行./stop-dfs.sh,停止整个hdfs集群,然后在3个node上,都修改hdfs-site.xml,加入下面的配置,禁止权限的检查

      <property>
        <name>dfs.permissions</name>
        <value>false</value>
      </property>
    复制代码
  • hdfs snapshot/restore plugin是跟最新的hadoop 2.x整合起来使用的,目前是hadoop 2.7.1。所以如果我们使用的hadoop版本跟这个es hdfs plugin的版本不兼容,那么考虑在hdfs plugin的文件夹里,将hadoop相关jar包都替换成我们自己的hadoop版本对应的jar包。即使hadoop已经在es所在机器上也安装了,但是为了安全考虑,还是应该将hadoop jar包放在hdfs plugin的目录中。

      安装好了hdfs plugin之后,就可以创建hdfs仓库了,用如下的命令即可:
      curl -XGET 'http://localhost:9200/_count?pretty' -d '
      {
          "query": {
              "match_all": {}
          }
      }
      '
      
      curl -XPUT 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository' -d '
      {
        "type": "hdfs",
        "settings": {
          "uri": "hdfs://elasticsearch02:9000/",
          "path": "elasticsearch/respositories/my_hdfs_repository",
      	"conf.dfs.client.read.shortcircuit": "false",
      	"max_snapshot_bytes_per_sec" : "50mb", 
          "max_restore_bytes_per_sec" : "50mb"
        }
      }'
    复制代码
  • 验证仓库,如果一个仓库被创建好之后,我们可以立即去验证一下这个仓库是否可以在所有节点上正常使用。verify参数都可以用来做这个事情,比如下面的命令。这个命令会返回一个node列表,证明那些node都验证过了这个仓库是ok的,可以使用的

      curl -XPOST 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/_verify' 
      
      三个节点追加相关授权,才能验证通过:
      /usr/local/elasticsearch/plugins/repository-hdfs/plugin-security.policy
    
        permission java.lang.RuntimePermission "accessDeclaredMembers";
        permission java.lang.RuntimePermission "getClassLoader";
        permission java.lang.RuntimePermission "shutdownHooks";
        permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
        permission javax.security.auth.AuthPermission "doAs";
        permission javax.security.auth.AuthPermission "getSubject";
        permission javax.security.auth.AuthPermission "modifyPrivateCredentials";
        permission java.security.AllPermission;
        permission java.util.PropertyPermission "*", "read,write";
        permission javax.security.auth.PrivateCredentialPermission "org.apache.hadoop.security.Credentials * \"*\"", "read";
       
      三个节点追加相关授权,才能验证通过: 
      /usr/local/elasticsearch/config/jvm.options  
      
      -Djava.security.policy=file:////usr/local/elasticsearch/plugins/repository-hdfs/plugin-security.policy
    复制代码

5.3 对索引进行snapshotting备份

  • 一个仓库可以包含多分snapshot,每个snapshot是一部分索引的备份数据,创建一份snapshot备份时,我们要指定要备份的索引。比如下面这行命令:

      PUT _snapshot/my_hdfs_repository/snapshot_1
      这行命令就会将所有open的索引都放入一个叫做snapshot_1的备份,并且放入my_backup仓库
      中。这个命令会立即返回,然后备份操作会被后台继续进行。
    复制代码
  • 如果我们不希望备份操作以后台方式运行,而是希望在前台发送请求时等待备份操作执行完成,那么可以加一个参数即可,比如下面这样:

      PUT _snapshot/my_backup/snapshot_1?wait_for_completion=true。
    
      执行备份:
      curl -XPUT 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/snapshot_1'
    复制代码
  • 对指定的索引进行snapshotting备份,默认的备份是会备份所有的索引,但是有的时候,可能我们不希望备份所有的索引,有些可能是不重要的数据,而且量很大,没有必要占用我们的hdfs磁盘资源,那么可以指定备份少数重要的数据即可。此时可以使用下面的命令去备份指定的索引:

      PUT _snapshot/my_backup/snapshot_2
      {
          "indices": "index_1,index_2",
      	"ignore_unavailable": true,
      	"include_global_state": false,
      	"partial": true
      }
      
      ignore_unavailable如果设置为true的话,那么那些不存在的index就会被忽略掉,不会进行备份过程中。默认情况下,这个参数是不设置的,那么此时如果某个index丢失了,会导致备份过程失败。设置include_global_state为false,可以阻止cluster的全局state也作为snapshot的一部分被备份。默认情况下,如果某个索引的部分primary shard不可用,那么会导致备份过程失败,那么此时可以将partial设置为true。
    复制代码
  • snapshotting的过程是增量进行的,每次执行snapshotting的时候,es会分析已经存在于仓库中的snapshot对应的index file,然后仅仅备份那些自从上次snapshot之后新创建的或者有过修改的index files。这就允许多个snapshot在仓库中可以用一种紧凑的模式来存储。而且snapshotting过程是不会阻塞所有的es读写操作的,然而,在snapshotting开始之后,写入index中的数据,是不会反应到这次snapshot中的。每次snapshot除了创建一份index的副本之外,还可以保存全局的cluster元数据,里面包含了全局的cluster设置和template。

  • 每次只能执行一次snapshot操作,如果某个shard正在被snapshot备份,那么这个shard此时就不能被移动到其他node上去,这会影响shard rebalance的操作。只有在snapshot结束之后,这个shard才能够被移动到其他的node上去。

5.4 查看snapshot备份列表

  • 一旦我们在仓库中备份了一些snapshot之后,就可以查看这些snapshot相关的详细信息了,使用这行命令就可以查看指定的snapshot的详细信息:

      GET _snapshot/my_backup/snapshot_2
    复制代码

,当然也可以查看所有的snapshot列表,GET _snapshot/my_backup/_all。

    curl -XGET 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/snapshot_1?pretty'
    
    备份列表:
    {
      "snapshots" : [
        {
          "snapshot" : "snapshot_1",
          "uuid" : "x8DXcrp2S0md-BC9ftYZqw",
          "version_id" : 5050099,
          "version" : "5.5.0",
          "indices" : [
            "my_index"
          ],
          "state" : "SUCCESS",
          "start_time" : "2017-07-08T19:54:54.914Z",
          "start_time_in_millis" : 1499543694914,
          "end_time" : "2017-07-08T19:54:56.886Z",
          "end_time_in_millis" : 1499543696886,
          "duration_in_millis" : 1972,
          "failures" : [ ],
          "shards" : {
            "total" : 5,
            "failed" : 0,
            "successful" : 5
          }
        }
      ]
    }
复制代码

5.5 删除snapshot备份

  • 如果要删除过于陈旧的snapshot备份快照,那么使用下面这行命令即可:DELETE _snapshot/my_backup/snapshot_2。记住,一定要用api去删除snapshot,不要自己手动跑到hdfs里删除这个数据。因为snapshot是增量的,有可能很多snapshot依赖于底层的某一个公共的旧的snapshot segment。但是delete api是理解数据如何增量存储和互相依赖的,所以可以正确的删除那些不用的数据。如果我们自己手工进行hdfs文件删除,可能导致我们的backup数据破损掉,就无法使用了。

      curl -XDELETE 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/snapshot_1'
    复制代码

5.6 监控snapshotting的进度

  • 使用wait_for_completion可以在前台等待备份完成,但是实际上也没什么必要,因为可能要备份的数据量特别大,难道还等待1个小时??看着是不太现实的,所以一般还是在后台运行备份过程,然后使用另外一个监控api来查看备份的进度,首先可以获取一个snapshot ID:GET _snapshot/my_backup/snapshot_3。如果这个snapshot还在备份过程中,此时我们就可以看到一些信息,比如什么时候开始备份的,已经运行了多长时间,等等。然而,这个api用了跟snapshot一样的线程池去执行,如果我们在备份非常大的shard,进度的更新可能会非常之慢。 一个更好的选择是用_status API,

                GET _snapshot/my_backup/snapshot_3/_status,
    复制代码
  • 这个api立即返回最详细的数据。这里我们可以看到总共有几个shard在备份,已经完成了几个,还剩下几个,包括每个索引的shard的备份进度:

5.7 取消snapshotting备份过程

  • 取消一个正在执行的snapshotting备份过程,比如我们发现备份时间过于长,希望先取消然后在晚上再运行,或者是因为不小心误操作发起了一次备份操作,这个时候就可以运行下面这条命令:DELETE _snapshot/my_backup/snapshot_3。也就是立即删除这个snapshot,这个命令会去取消snapshot的过程,同时将备份了一半的仓库中的数据给删除掉。

      curl -XDELETE 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/snapshot_1'
    复制代码

6 集群备份恢复

  • 在es集群故障,导致数据丢失的时候,就可以用_restore api进行数据恢复了。比如下面这行命令:POST _snapshot/my_hdfs_repository/snapshot_1/_restore。这个时候,会将那个snapshot中的所有数据恢复到es中来,如果snapshot_1中包含了5个索引,那么这5个索引都会恢复到集群中来。不过我们也可以选择要从snapshot中恢复哪几个索引。

  • 我们还可以通过一些option来重命名索引,恢复索引的时候将其重命名为其他的名称。在某些场景下,比如我们想恢复一些数据但是不要覆盖现有数据,然后看一下具体情况,用下面的命令即可恢复数据,并且进行重命名操作:

      POST /_snapshot/my_hdfs_repository/snapshot_1/_restore
      {
          "indices": "index_1", 
      	"ignore_unavailable": true,
      	"include_global_state": true,
          "rename_pattern": "index_(.+)", 
          "rename_replacement": "restored_index_$1" 
      }
    复制代码
  • 还可以在恢复的过程中,修改index的一些设置,比如下面的命令:

      POST /_snapshot/my_backup/snapshot_1/_restore
      {
        "indices": "index_1",
        "index_settings": {
          "index.number_of_replicas": 0
        },
        "ignore_index_settings": [
          "index.refresh_interval"
        ]
      }
      
      curl -XDELETE 'http://elasticsearch02:9200/my_index?pretty'
      curl -XGET 'http://elasticsearch02:9200/my_index/my_type/1'
      curl -XPOST 'http://elasticsearch02:9200/_snapshot/my_hdfs_repository/snapshot_1/_restore?pretty'
      curl -XGET 'http://elasticsearch02:9200/my_index/my_type/1'
    复制代码

6.1 集群备份恢复监控restore的进度

  • 从一个仓库中恢复数据,其实内部机制跟从其他的node上恢复一个shard是一样的。如果要监控这个恢复的过程,可以用recovery api,比如:GET restored_index_3/_recovery。如果要看所有索引的恢复进度:GET /_recovery/。可以看到恢复进度的大致的百分比。结果大致如下所示:

      curl -XGET 'http://elasticsearch02:9200/my_index/_recovery?pretty'
    复制代码

6.2 取消恢复过程

如果要取消一个恢复过程,那么需要删除已经被恢复到es中的数据。因为一个恢复过程就只是一个shard恢复,发送一个delete操作删除那个索引即可,比如:DELETE /restored_index_3。如果那个索引正在被恢复,那么这个delete命令就会停止恢复过程,然后删除已经恢复的 所有数据。

    curl -XDELETE 'http://elasticsearch02:9200/my_index'
复制代码

7 总结

生产部署还有很多工作要做,本文从初级思路切入,进行了问题的整合。

本套技术专栏作者(秦凯新)专注于大数据及容器云核心技术解密,具备5年工业级IOT大数据云平台建设经验,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系

秦凯新

关注下面的标签,发现更多相似文章
评论