👨🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:详解SpringCloud微服务技术栈:深入ElasticSearch(3)——数据同步(酒店管理项目)
📚订阅专栏:微服务技术全家桶
希望文章对你们有所帮助
ElasticSearch本身就是分布式的,在这里将要讨论如何用3个docker容器来模拟实现ElasticSearch的集群搭建,并且提出集群会出现的脑裂问题并讨论解决方案。
 但是这里集群的部署需要我们的Linux虚拟机至少拥有4G的内存空间,内存有限就不要做了。
深入ElasticSearch(4)——ES集群
- 集群结构介绍
- 搭建集群
- 集群职责及脑裂
- 分布式新增和查询流程
- 故障转移
集群结构介绍
单机的ElasticSearch做数据存储,会面临两个问题:海量数据存储问题,单点故障问题。
 针对这两个问题,不得不用集群来解决了:
海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点
单点故障问题:将分片数据在不同节点备份(replica),也就是说其主分片和副本分片不能在同一个节点
搭建集群
没有多台电脑,所以这里会利用3个docker容器来模拟3个ES结点。
编写docker-compose文件,里面包含了三个容器结点的部署方案,大致看懂语句的意思是什么:
version: '2.2'
services:
  es01:
    image: elasticsearch:7.12.1 # 镜像
    container_name: es01 # 容器名,与服务es01名称保持一致
    environment:
      - node.name=es01 # 结点名称,与服务es01名称保持一致
      - cluster.name=es-docker-cluster # 集群名称,三个节点的名称都要一样,ES就会自动组装成集群
      - discovery.seed_hosts=es02,es03 # 集群中另外两个结点,docker中可以直接在容器内互联,不一定要ip地址
      - cluster.initial_master_nodes=es01,es02,es03 # 初始化主节点,这三个节点都可以参与主节点的选举
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: elasticsearch:7.12.1
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - data02:/usr/share/elasticsearch/data
    ports:
      - 9201:9200
    networks:
      - elastic
  es03:
    image: elasticsearch:7.12.1
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic
    ports:
      - 9202:9200
volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local
networks:
  elastic:
    driver: bridge
这个docker-compose文件直接可以从百度网盘中下载并上传到虚拟机:
链接:https://pan.baidu.com/s/10By3MR6RYqqMmjBgwDOr7w?pwd=mycu
提取码:mycu
ES运行需要修改一些Linux系统权限,修改/etc/sysctl.conf文件:
vi /etc/sysctl.conf
添加下面内容:
vm.max_map_count = 262144
再执行语句让配置生效:
sysctl -p
最后执行docker-compose up -d执行即可。
集群的状态监控这里不再推荐kibana了,配置比较复杂,推荐使用cerebro来监控ES集群的状态,压缩包从网盘下载:
链接:https://pan.baidu.com/s/1kywnAFGyVbbpRN4weRF8Ag?pwd=laz2
提取码:laz2
下载完就在本地解压,然后进入其中的bin目录,双击其中的cerebro.bat即可启动服务。访问9000端口就可以访问了。
 在这里就可以创建索引库,并且可以直接指定需要分片的数量为3,每个分片锁被备份的数量为1。
集群职责及脑裂
ElasticSearch中节点的角色有4中:
| 节点类型 | 配置参数 | 默认值 | 节点职责 | 
|---|---|---|---|
| master eligible | node.master | true | 作为备选主节点,一旦当选,则:管理和记录集群状态;处理分片在哪个节点;处理创建和删除索引库的请求 | 
| data | node.data | true | 数据节点:存储数据、搜索、聚合、CRUD | 
| ingest | node.ingest | true | 数据存储之前的预处理 | 
| coordinating | 上面3个参数都为false则为coordinating节点 | 无 | 路由请求到其它节点;合并其它节点处理的结果,返回给用户 | 
这种方式把职责分开显然是很好的,但是还是可能会出现问题,即脑裂问题。
 默认情况下,每个节点都是master eligible节点,因此一旦master节点宕机,其它候选节点会选举一个成为主节点。当主节点与其他节点网络故障时,可能会出现脑裂问题。如下:
 
 node1位主节点,原先就是没有故障的,但是和备选主节点node2、node3由于网络阻塞问题没办法互联了,这时候node2或node3可能就会误认为node1宕机了,自动选举出主节点。从而造成了集群中有2个主节点,它们共同执行了系统的业务,当网络恢复正常的时候,访问节点的数据的时候就会发生数据不一致的问题。
为了避免脑裂,需要要求选票超过(eligible节点数量+1)/2才能当选为主,因此eligible节点数量最好是奇数。对应配置项是discovery.zen.minimum_master_nodes,但在ES7.0以后,已经成为默认配置,因此一般不会出现脑裂问题。
分布式新增和查询流程
当新增文档时,应该保存到不同的分片,保证数据均衡,coordinating node可以确定数据该存储到哪个分片中。
 例如,配置好的三台ES,从9200端口中保存3条文档,可以发现9201和9202端口都可以查询到这三条文档,同时三条消息分别分片到了三台不同的机器上。这就是协调结点起到的作用。
 实际上,这个数据分片是利用一个算法来实现的:
  
      
       
        
        
          s 
         
        
          h 
         
        
          a 
         
        
          r 
         
        
          d 
         
        
          = 
         
        
          h 
         
        
          a 
         
        
          s 
         
        
          h 
         
        
          ( 
         
        
          _ 
         
        
          r 
         
        
          o 
         
        
          u 
         
        
          t 
         
        
          i 
         
        
          n 
         
        
          g 
         
        
          ) 
         
        
          % 
         
        
          n 
         
        
          u 
         
        
          m 
         
        
          b 
         
        
          e 
         
        
          r 
         
        
          _ 
         
        
          o 
         
        
          f 
         
        
          _ 
         
        
          s 
         
        
          h 
         
        
          a 
         
        
          r 
         
        
          d 
         
        
          s 
         
        
       
         shard = hash(\_routing) \% number\_of\_shards 
        
       
     shard=hash(_routing)%number_of_shards
_routing默认是文档的id
算法与分片数量有关,因此索引库一旦创建,分片数量不能修改
这样的话,3台机器运算后的结果只会是0、1、2中的一个,从而实现数据的分布式新增。
 
 查询分成2个阶段:
scatter phase:分散阶段,coordinating node会把请求分发到每一个分片
gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户
总结:
 1、分布式新增如何确定分片:coordinating node根据id做hash运算,得到结果对shard数量取余,余数就是对应的分片
 2、分布式查询:分散阶段、聚集阶段
故障转移
故障转移是ES节点一个非常重要的功能,集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据的安全,即为故障转移。
也就是说,当数据节点发生故障时,主节点会监控到这种状态,就会将节点中的所有分片和副本都转移到其它的节点,确保数据的安全。
 而主节点本身宕机的话,EligibleMaster就会选举出新的主节点出来


















