15.集群知识(MySQL+Redis+ElasticSearch+RabbitMQ)

集群简介

集群的目标

高可用:主机宕机对业务无影响。
	宕机原因:网卡、路由器、机房、CPU负载过高、内存溢出、自然灾害等不可预期的原因导致,也称单点问题
	解决方案:【选主式(双主、raft选举)】重新创建主节点

单点性能限制:当单点数据量过大导致性能降低,所以需要多台分担共同存储整个集群数据,并且做好互相备份保证即使单点故障,也能在其他节点找到数据
	解决方案:【分片式(分库分表)】

数据备份容灾:单点故障后,存储的数据仍然可以在别的地方拉起
	解决方案:【主从复制】

压力分担:避免单点压力过高,例如单节点几千亿条数据读取很慢,分离操作,各单点完成自己的工作完成整个工作
	解决方案:【读写分离】
	
主从复制、读写分离可以一起实现	

集群的基础形式

在这里插入图片描述

主从式:
	主从复制:从节点复制主节点数据,保持一致(mysql)
	主从调度:所有请求由主节点调度,挑一个从节点响应请求(k8s)

分片式:(可以看作有多套主从构成分片)
	数据分片存储,突破单点限制
	分片之间互相备份,保证数据不丢失
	客户端分片:由客户端计算实际请求的分片地址(mycat)
    服务端分片:由服务端计算实际请求的分片地址(redis)
例:订单表,按地区分片,按时间分表

选主式:
	为了容灾选主:
	为了调度选主:

MySQL

mysql存在多种集群方案

1.实现方案

在这里插入图片描述

1.1.双主复制-MMM

在这里插入图片描述

主主复制管理器
1、两个主机master1,master2,其中master1作为write vip,两个主机 数据复制。当第一个主机宕机,第二个主机晋升为主机,且客户端的使用的mysql写ip不用改变,monitor会将写ip的地址转换给master2【ip飘移】
2、master1写,master2和slave作为读
3、monitor:监控器,监控IP集。
4、VIP集:虚拟ip集,每个结点都有自己的IP。

优点:高可用问题
缺点:数据丢失【例如master1宕机还没来得及复制的数据】

主从复制、读写分离

1.2.从节点替补-MHA

在这里插入图片描述

1.3.InnoDB Cluster

在这里插入图片描述

MySQL Router:调度节点,如果Primary宕机,选择一个从节点作为主节点
jdbc连接MySQL Router,不直接连接集群。

在这里插入图片描述

2.docker快速模拟 InnoDB Cluster 主从同步+只读/只写

一句话总结:
	启动二进制日志,配置可读可写,配置需要同步、忽略的数据库
	分配允许同步的账号,从库链接主库并配置好需要同步的二进制日志
	
只读/只写 是读写分离的基础
InnoDB Cluster有单主模式、双主模式

1、下载mysql镜像

2、创建Master实例并启动,指定密码为root
docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql/master/conf:/etc/mysql \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

参数说明
-p 3307:3306:将容器的3306端口映射到主机的3307端口
-v/mydata/mysal/master/conf:/etc/mysql:将配置文件夹挂在到主机
-v/mydata/mysal/master/log:/var/log/mysal:将日志文件夹挂载到主机
-v/mydata/mysal/master/data:/ar/lib/mysal:将配置文件夹挂载到主机
-e MYSQL_ROOT_PASSWORD=root:初始化root用户的密码

3、创建slave实例并启动
docker run -p 3317:3306 --name mysql-slaver-01 \
-v /mydata/mysql/slaver/conf:/etc/mysql \
-v /mydata/mysql/slaver/log:/var/log/mysql \
-v /mydata/mysql/slaver/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

4、修改master配置
vi /mydata/mysql/master/conf/my.cnf
【注意:1.skip-name-resolve一定要加,不然连接mysql会很慢;
      2.主从复制主要是通过日志进行的,所以需要指定哪些数据库需要记录日志,哪些数据库不需要记录日志
      3.配置从库只读】

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

server-id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=gulimall_oms
binlog-do-db=gulimall_pms
binlog-do-db=gulimall_sms
binlog-do-db=gulimall_ums
binlog-do-db=gulimall_wms
binlog-do-db=gulimall_admin

replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=performance_schema
replicate-ignore-db=information_schema

5、修改salver配置
vi /mydata/mysql/slaver/conf/my.cnf
注意:skip-name-resolve一定要加,不然连接mysql会很慢

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

server-id=2
log-bin=mysql-bin
read-only=1
binlog-do-db=gulimall_oms
binlog-do-db=gulimall_pms
binlog-do-db=gulimall_sms
binlog-do-db=gulimall_ums
binlog-do-db=gulimall_wms
binlog-do-db=gulimall_admin

replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=performance_schema
replicate-ignore-db=information_schema

6、重启:docker restart mysql-master mysql-slaver-01
master授权用户,允许同步master数据

1、进入master容器
docker exec -it mysql-master /bin/bash

2、mysql -uroot -p root
	1)授权root可以远程访问(与主从无关,方便我们可以使用客户端连接mysql)
	grant all privileges on *.* to 'root'@'%' IDENTIFIED BY 'root' with grant option;
	flush privileges;

	2)添加同步用户,链接master数据库,在master授权一个 复制权限的 用户
	GRANT REPLICATION SLAVE ON *.* TO 'backup'@'%' IDENTIFIED BY '123456';

3、查看master状态
show master status;
	记录File名字:mysql-bin.000001,后面会用到

在这里插入图片描述

配置slaver同步master数据

1、进入slaver容器
docker exec -it mysql-slaver-01 /bin/bash

2、mysql -uroot -p root
	1)授权root可以远程访问(主从无关,方便我们可以远程链接mysql)
	grant all privileges on *.* to 'root'@'%' IDENTIFIED BY 'root' with grant option;
	flush privileges;
	2)给当前从库配置主库
	change master to master_host='192.168.56.10',master_user='backup',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=0,master_port=3307;
	
3、启动从库同步
start slave;

4、查看从库状态
show slave status;

3.shardingsphere快速模拟 分库分表+读写分离

doc:https://shardingsphere.apache.org/document/current/cn/overview/what-is-ss/
配置文档:https://blog.csdn.net/qq_44826685/article/details/106190720
官网proxy文档:https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-proxy/
下载proxy:https://shardingsphere.apache.org/document/current/cn/downloads/
下载mysql:https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar

shardingsphere是一个生态圈,由 JDBC、Proxy 和 Sidecar(规划中) 3 款产品组成
sharding-jdbc看做客户端驱动

在这里插入图片描述

经过sharding-proxy实现分库分表后的效果:

在这里插入图片描述

以上示意图为两主两从(4个容器)
现使用简单实现1主1从(2个容器,其中在1个主master容器中创建2个数据库,模拟2个主库)

	
实现:【参照doc】
1、安装proxy 5.1.2版本
	1.1.下载tar包:https://shardingsphere.apache.org/document/current/cn/downloads/
	并在windows环境解压
	
	1.2.下载mysql 驱动包:https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar,拷贝到sharding-proxy 的lib文件夹
	=========================================================================================
2、配置认证信息+属性配置 server.yaml

rules:
  - !AUTHORITY
    users:
      - root@%:root
    provider:
      type: ALL_PERMITTED

props:
  kernel-executor-size: 16  # Infinite by default.
  sql-show: true

=========================================================================================
3、分库分表+读写分离 相关配置
	1)分库分表:数据分片【两个库在同一个主机上】 config-sharding.yaml
		一:分库分表是相对于写的概念,所以是主库。下面两个数据源都是配的主库【可以在不同节点,当前demo放在同一个节点下(同一mysql容器),在同一个容器中创建了两个数据库】
		二:微服务连上sharding_db这个中间件而不是直接连接数据库
		三:主键采用雪花算法,不可以自增
        四:绑定表订单表和订单表项的关系,不需要跨库联查
  		五:根据user_id分库,根据order_id分表
  		
databaseName: sharding_db
#
dataSources:
  ds_0:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
  ds_1:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
#
rules:
- !SHARDING
  tables:
    t_order:
      actualDataNodes: ds_${0..1}.t_order_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    none:

  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${order_id % 2}

  keyGenerators:
    snowflake:
      type: SNOWFLAKE
    
    2)读写分离config-master_slave.yaml
        一:主从同步是InnoDB Cluster中配置【my.cnf】,读写分离是在sharding-proxy配置
		二:有几套分库分表,就配置几套读写分离
创建两个文件
############################config-readwrite-splitting.yaml############################
databaseName: sharding_db_0
#
dataSources:
  master_0_ds:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
  slave_ds_0:
    url: jdbc:mysql://192.168.56.10:3317/demo_ds_0?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

rules:
- !READWRITE_SPLITTING
  dataSources:
    readwrite_ds:
      type: Static
      props:
        write-data-source-name: master_0_ds
        read-data-source-names: slave_ds_0
      loadBalancerName: random
  loadBalancers:
    random:
      type: RANDOM
  
############################config-readwrite-splitting1.yaml############################
databaseName: sharding_db_1
#
dataSources:
  master_1_ds:
    url: jdbc:mysql://192.168.56.10:3307/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
  slave_ds_1:
    url: jdbc:mysql://192.168.56.10:3317/demo_ds_1?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

rules:
- !READWRITE_SPLITTING
  dataSources:
    readwrite_ds:
      type: Static
      props:
        write-data-source-name: master_1_ds
        read-data-source-names: slave_ds_1
      loadBalancerName: random
  loadBalancers:
    random:
      type: RANDOM

=========================================================================================
4、创建相关容器+数据库
	一:容器之前创建好了,参照集群实现
	1)docker stop mysql-master mysql-slaver-01
	2)修改配置文件
主库配置,需要同步的两个主库【分库分表的主库】
vi /mydata/mysql/master/conf/my.cnf
添加:
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1

从库配置,需要同步的两个主库
vi /mydata/mysql/slaver/conf/my.cnf

添加:
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1

=========================================================================================
5、docker start mysql-master mysql-slaver-01
创建数据库demo_ds_0和demo_ds_1

=========================================================================================
6、启动sharding-proxy中间件
	直接在文件夹目录输入cmd就可以在当前目录打开一个cmd窗口
	start.bat 3388

=========================================================================================
7、navicat新建连接,127.0.0.1:3388【这里使用navicat11,否则不会显示代理库】

=========================================================================================
8、创建测试表
在proxy代理库端创建表 t_order和t_order_item表

CREATE TABLE `t_order` (
  `order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
  `user_id` int(11) NOT NULL COMMENT '用户id',
  `status` varchar(50) DEFAULT NULL COMMENT '状态',
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';

CREATE TABLE `t_order_item` (
  `order_item_id` bigint(20) NOT NULL COMMENT '订单项id',
  `order_id` bigint(20) NOT NULL COMMENT '订单id',
  `user_id` int(11) NOT NULL COMMENT '用户id',
  `content` varchar(255) DEFAULT NULL COMMENT '描述',
  `status` varchar(50) DEFAULT NULL COMMENT '状态',
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单项表';


9.执行insert语句观察结果
INSERT INTO sharding_db.t_order
(user_id, status)
VALUES(1, '1');

INSERT INTO sharding_db.t_order
(user_id, status)
VALUES(2, '1');

INSERT INTO sharding_db.t_order
(user_id, status)
VALUES(3, '1');


解释:根据user_id先分库,再根据order_id分表
	容器3307,demo_ds_0与demo_ds_1为分库关系
	容器3307,demo_ds_0.t_order0与demo_ds_0.t_order1为分表关系
	
	容器3317,demo_ds_0、demo_ds_0分别是3307的从库,数据保持一致

Redis

1.实现方案

1.1.客户端分区(高可用+分片)

客户端Jedis直接堆key作hash或求余获得指定节点存储

客户端分区方案的代表为Redis Sharding,Redis Sharding是Redis Cluster出来之前,业界普遍使用的Redis多实例集群方法。Java的Redis客户端驱动库Jedis,支持 RedisSharding功能,即ShardedJedis,以及结合缓存池的ShardedJedisPool。

优点
不使用第三方中间件,分区逻辑可控,配置简单,节点之间无关联,容易线性扩展,灵活性强。

缺点
客户端无法动态增删服务节点,客户端需要自行维护分发逻辑,客户端之间无连接共享,会造成连接浪费。
不是高可用,redis某节点宕机

1.2.代理分区

与sharding proxy类似
代理分区常用方案有Twemproxy和Codis

1.3.哨兵机制(高可用)

redis-cluster未出现之前,使用哨兵机制

监控(Monitoring):哨兵(sentinel)会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个Redis出现问题时,哨兵(sentinel)可以通过 API向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover)):当主数据库出现故障时自动将从数据库转换为主数据库。【投票选举】

哨兵的原理
Redis,哨兵的三个定时任务,Redis,哨兵判定一个Redis.节点故障不可达主要就是通过三个定时监控任务来完成的:
	1、每隔1秒每个哨兵会向主节点、从节点、其他的哨兵节点发送一个“ping”命令来做心跳检测
	2、每隔2秒每个哨兵节点会向Redis节点的_sentinel_hello频道发送自己对主节点是否故障的判断以及自身的节点信息,并且其他的哨兵节点也会订阅这个频道来了解其他哨兵节点的信息以及对主节点的判断
	3、每隔10秒每个哨兵节点会向主节点和从节点发送"info replication”命令来获取最新的拓扑结构
	
    如果在定时Job1检测不到节点的心跳,会判断为"主观下线"。如果该节点还是主节点那么还会通知到其他的哨兵对该主节点进行y心跳检测,这时主观下线的票数超过了<quorum>数时,那么这个主节点确实就可能是故障不可达了,这时就由原来的主观下线变为了“客观下线"。

	故障转移和Leader选举
如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader,这里面采用的选举算法为Raft。选举出来的哨兵leader就要来完成故障转移工作,也就是在从节点中选出一个节点来当新的主节点,这部分的具体流程可参考引用.

1.4.redis-cluster(高可用+分片)

两种实现,槽和一致性hash

https://redis.io/topics/cluster-tutorial/
	Redis的官方多机部署方案,Redis Cluster。一组Redis Cluster是由多个Redis,实例组成,官方推荐我们使用6实例,其中3个为主节点,3个为从结点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从结点成为新的主节点继续对外服务,从而保证服务的高可用性。那么对于客户端来说,如何知道对应的key是要路由到哪一个节点呢?Redis Cluster把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部分的Redis数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。

0~16383

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一致性hash
一个闭环,计算keyhash与哪一个节点最近。

Hash倾斜
如果节点很少,容易出现倾斜,负载不均衡问题。一致性哈希算法,引入了虚拟节点,在整个环上,均衡增加若干个节点。比如al, a2,b1,b2,c1,c2,a1和a2都是属于A节点的。解决hash倾斜问题

2.docker快速模拟redis集群

在这里插入图片描述

数据分区
3主3从,从为了同步备份,主进行slot数据分片
1、高可用【主机宕机从机替代】
2、数据分片【槽机制】
3、容灾备份【主从备份】
4、单点读取压力分担【这里应该没有读写分离,分开读写操作,让读高效进行】

一、脚本:创建6份配置文件+启动6份redis
for port in $(seq 7001 7006);  \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF > /mydata/redis/node-${port}/conf/redis.conf
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.56.10
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOF

docker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} --restart always \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d redis:5.0.7 redis-server /etc/redis/redis.conf; \
done

二、建立集群,进入一个master节点【每个节点1个副本】
然后从6个节点挑出3个主节点,然后给每个主节点挑一个从节点
docker exec -it redis-7001 /bin/bash 

redis-cli  --cluster create 192.168.56.10:7001 192.168.56.10:7002 192.168.56.10:7003 192.168.56.10:7004 192.168.56.10:7005 192.168.56.10:7006 --cluster-replicas 1

三、测试集群
1、连入集群,要加-c
redis-cli -c -h 192.168.56.10 -p 7001
2、设置一些值查看有什么不同【重定向到其他槽】
set hello 111
set a aaa

四、模拟宕机
1、使用redis客户端连接一个master和slaver,可以查看到数据拷贝现象
2、cluster info:查看当前集群状态
3、cluster nodes:查看集群节点信息
4、模拟宕机docker stop redis-7001
5、cluster info:7001宕机,7006从机晋升主机
6、docker start redis-7001:7001成为7006的从节点

在这里插入图片描述

Elasticsearch

https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/distributed-cluster.html

elasticsearch是天生支持集群的,他不需要依赖其他的服务发现和注册的组件,如zookeeper这些,因为他内置了一个名字叫ZenDiscovery的模块,是elasticsearch,自己实现的一套用于节点发现和选主等功能的组件,所以elasticsearch做起集群来非常简单,不需要太多额外的配置和安装额外的第三方组件。

1.集群原理

单节点

1、主节点用于调控,维护各节点状态信息的
2、任何节点可以做主节点
3、客户端连上任意一个节点都可以完成操作

	一个运行中的Elasticsearch实例称为一个节点,而集群是由一个或者多个拥有相同cluster.name配置的节点组成,它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

	当一个节点被选举成为主节点时,它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。任何节点都可以成为主节点。我们的示例集群就只有一个节点,所以它同时也成为了主节点。

	作为用户,我们可以将请求发送到集群中的任何节点,包括主节点。每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据.并将最终结果返回给客户端。Elasticsearch对这一切的管理都是透明的。

集群健康


get /_cluster/health

status字段指示着当前集群在总体上是否工作正常。它的三种颜色含义如下:
green:所有的主分片和副本分片都正常运行。
yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行。
red:有主分片没能正常运行。

分片

	1、一个分片是一个底层的工作单元﹐它仅保存了全部数据中的一部分。我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。分片就认为是一个数据区
	2、一个分片可以是主分片或者副本分片。索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
	3、在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改。
	4、让我们在包含一个空节点的集群内创建名为 blogs 的索引。索引在默认情况下会被分配5个主分片,但是为了演示目的.我们将分配3个主分片和一份副本(每个主分片拥有一个副本分片):

PUT /blogs{
	"settings" : {
		"number_of_shards" : 3,
		"number_of_replicas" : 1
	}
}
此时集群的健康状况为yellow则表示全部主分片都正常运行(集群可以正常服务所有请求),但是副本分片没有全部处在正常状态。实际上,所有3个副本分片都是unassigned—它们都没有被分配到任何节点。在同一个节点上既保存原始数据又保存副本是没有意义的,因为一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。当前我们的集群是正常运行的,但是在硬件故障时有丢失数据的风险。


【个人理解,此时3个分片是在同一节点上
master节点与主分片不是一个意思,master节点只需要一个。主分片可能存在多个,并有可能存在于不同节点上】

在这里插入图片描述

新增节点

	当你在同一台机器上启动了第二个节点时,只要它和第一个节点有同样的cluster.name配置,它就会自动发现集群并加入到其中。但是在不同机器上启动节点的时候,为了加入到同一集群,你需要配置一个可连接到的单播主机列表。详细信息请查看最好使用单播代替组播

在这里插入图片描述

	此时,cluster-health 现在展示的状态为green,这表示所有6个分片(包括3个主分片和3个副本分片)都在正常运行。我们的集群现在不仅仅是正常运行的,并且还处于始终可用的状态。

重新分配

在这里插入图片描述

1、在第四步的基础上,继续水平扩容增加第三个节点,会重新自动分配

 	Node 1和 Node 2上各有一个分片被迁移到了新的Node 3节点,现在每个节点上都拥有2个分片,而不是之前的3个。这表示每个节点的硬件资源(CPU,RAM.VO)将被更少的分片所共享,每个分片的性能将会得到提升。在运行中的集群上是可以动态调整副本分片数目的,我们可以按需伸缩集群。让我们把副本数从默认的1增加到2

如果调整每个分片拥有两个从分片
PUT /blogs/_settings
{
	"number_of_replicas" : 2
}
会自动调整为以下状态:
1、如果此时Node1宕机,会先选举一个主节点 Node2,此时查看集群状态将是red,主分区P1、P2未正常工作
2、提升副本分区为主分区,集群状态变为yellow
3、为什么是yellow而不是green?因为每个主分区存在两个副本分区才是green


在这里插入图片描述

脑裂现象

1、主节点:
	创建索引、删除索引、分配分片、追踪集群中节点状态等工作【ZenDiscovery机制选举出来,要成为主节点先成为候选节点】
	
2、候选主节点:
	主节点宕机,选举一个候选主节点作为主节点。指定候选主节点的配置为 node.master:true
	
3、脑裂现象
	网路故障,出现两个集群两个主节点【集群中不同的节点对于master的选择出现了分歧,出现了多个master竞争,导致主分片和副本的识别也发生了分歧,对一些分歧中的分片标识为了坏片。】
	解决方案:
	1)角色分离:master与data节点分离,限制角色
		因为data节点如果既要负责master节点又要负责data节点,压力很大导致脑裂概率增加
	2)增加判定宕机时间【减少误判】:主节点判定宕机时间加长【默认3秒】
		discover.zen.ping_timeout: 5
	3)设置选举触发互连节点最小数目:discover.zen.minimum_master_nodes:1(默认是1),该属性定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。建议设置成 (候选主节点数/2)+1
		例:10个候选主节点互相连接,并且discover.zen.minimum_master_nodes:6,此时网络原因导致6个节点连接,其余4个节点连接,则其余4个节点不会形成一个新的集群。
		
4、数据节点
	node.data:true
	主节点和数据节点分开,主节点不存数据
	
5、客户端节点【分担主节点的请求分发、汇总(其实集群内任意节点都可以完成此任务)】
	功能:为了负载均衡
	node.master:false
	node.data:false

2.集群搭建(节点+分片)

这张图画错了,一共6台物理机,一台1个节点

	要求:
		1、6台物理机6个节点,3个master节点3个data节点【角色分离,防止脑裂】
		2、判定时间设为10秒
		3、设置discover.zen.minimum_master_nodes=2,只要一个master宕机,另外两个就可以选举

master节点上
node.master = true
node.data = false
discovery.zen.minimum_master_nodes = 2
总结:只要集群名字是一样的,就会自动加入到同一个集群中
1、先修改jvm线程数,防止启动es报错
sysctl -w vm.max_map_count=262144

2、利用docker模拟6台物理机,创建每一个容器使用一个ip
准备docker网络:
	1)docker network ls:查看docker网络
	2)docker network create --driver bridge --subnet=172.18.12.0/16 --gateway=172.18.1.1 mynet
	3)docker network inspect mynet:查看网络消息
	4)创建容器带上 --network=mynet --ip 172.18.12.x指定ip
	
3、创建节点
创建主节点:
for port in $(seq 1 3); \
do \
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF > /mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name: my-es  #集群的名称,同一个集群该值必须设置成相同的
node.name: es-master-${port}  #该节点的名字
node.master: true  #该节点有机会成为master节点
node.data: false #该节点可以存储数据
network.host: 0.0.0.0
http.host: 0.0.0.0   #所有http均可访问
http.port: 920${port}
transport.tcp.port: 930${port}
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时ping连接的超时时间
discovery.seed_hosts: ["172.19.1.21:9301","172.19.1.22:9302","172.19.1.23:9303"]
cluster.initial_master_nodes: ["172.19.1.21"] #新集群初始时的候选主节点,es7的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--network=mynet --ip 172.19.1.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m"  \
-v /mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml  \
-v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data  \
-v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins  \
-d elasticsearch:7.4.2
done

=====================================
创建数据节点:
for port in $(seq 4 6); \
do \
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF > /mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name: my-es  #集群的名称,同一个集群该值必须设置成相同的
node.name: es-node-${port}  #该节点的名字
node.master: false  #该节点有机会成为master节点
node.data: true #该节点可以存储数据
network.host: 0.0.0.0
http.host: 0.0.0.0   #所有http均可访问
http.port: 920${port}
transport.tcp.port: 930${port}
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时ping连接的超时时间
discovery.seed_hosts: ["172.19.1.21:9301","172.19.1.22:9302","172.19.1.23:9303"]
cluster.initial_master_nodes: ["172.19.1.21"] #新集群初始时的候选主节点,es7的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--network=mynet --ip 172.19.1.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m"  \
-v /mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml  \
-v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data  \
-v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins  \
-d elasticsearch:7.4.2
done

4、访问查看集群相关信息指令:
192.168.56.10/_cluster/health:查看健康状况
192.168.56.10/_cluster/status
192.168.56.10/_cat/health
192.168.56.10/_cat/nodes:查看所有节点,带*是主节点


RabbitMQ

1.集群形式

	RabbiMQ是用Erlang开发的,集群非常方便,因为Erlang,天生就是一门分布式语言,但其本身并不支持负载均衡。需要nginx
	RabbitMQ集群中节点包括内存节点(RAM)、磁盘节点(Disk,消息持久化),集群中至少有一个Disk 节点。
	
	1、由磁盘节点和内存节点组成
	2、至少需要一个磁盘节点

1.1.普通模式
	1、普通模式中集群不会同步消息,只会同步queue、exchange
	
	demo:3个节点A\B\C组成的集群,消费节点C上的队列,如果此时消息在节点A的队列上,集群会将A的信息发送到C的队列上供于消费
	缺点:单点故障无法解决【高可用】
	
	对于普通模式,集群中各节点有相同的队列结构,但消息只会存在于集群中的一个节点。对于消费者来说,若消息进入A节点的Queue中,当从B节点拉取时,RabbitMQ会将消息从A中取出,并经过B发送给消费者。应用场景:该模式各适合于消息无需持久化的场合,如日志队列。当队列非持久化,且创建该队列的节点宕机,客户端才可以重连集群其他节点,并重新创建队列。若为持久化.只能等故障节点恢复。

1.2.镜像模式
	与普通模式不同之处是消息实体会主动在镜像节点间同步,而不是在取数据时临时拉取,高可用;该模式下,mirror queue有一套选举算法,即1个master、n个slaver,生产者、消费者的请求都会转至master。应用场景:可靠性要求较高场合,如下单、库存队列。缺点:若镜像队列过多,且消息体量大,集群内部网络带宽将会被此种同步通讯所消耗。
	优点:解决了高可用,当消息进入节点A的队列,会同步到B\C。当master A节点宕机,B、C会选择一个主节点
	1、镜像模式由主节点接收 生产者和消费者的请求【代理】
	2、镜像模式 依赖于 先搭建一个普通模式,再设置成镜像模式

2.搭建镜像集群

1、创建文件夹
mkdir /mydata/rabbitmq
cd /mydata/rabbitmq
mkdir rabbitmq01 rabbitmq02 rabbitmq03

2、启动3个rabbitmq
--hostname设置容器的主机名
RABBITMQ_ERLANG_COOKIE 节点认证作用,部署集成时需要同步该值

docker run -d --hostname rabbitmq01  --name rabbitmq01 \
-v /mydata/rabbitmq/rabbitmq01:/var/lib/rabbitmq \
-p 15673:15672 -p 5673:5672  \
-e RABBITMQ_ERLANG_COOKIE='dalianpai' rabbitmq:management

docker run -d --hostname rabbitmq02  --name rabbitmq02 \
-v /mydata/rabbitmq/rabbitmq02:/var/lib/rabbitmq \
-p 15674:15672 -p 5674:5672  \
-e RABBITMQ_ERLANG_COOKIE='dalianpai' rabbitmq:management

docker run -d --hostname rabbitmq03  --name rabbitmq03 \
-v /mydata/rabbitmq/rabbitmq03:/var/lib/rabbitmq \
-p 15675:15672 -p 5675:5672  \
-e RABBITMQ_ERLANG_COOKIE='dalianpai' rabbitmq:management


3、节点加入集群
	1)进入个节点完成初始化
	docker exec -it rabbitmq01 /bin/bash
	rabbitmqctl stop_app
	rabbitmqctl reset 【恢复出厂设置】
	rabbitmqctl start_app
	exit
	
	2)将节点2和3加入到集群
	docker exec -it rabbitmq02 /bin/bash
	rabbitmqctl stop_app
	rabbitmqctl reset
	rabbitmqctl join_cluster --ram rabbit@rabbitmq01
	rabbitmqctl start_app
	exit
	
	docker exec -it rabbitmq03 /bin/bash
	rabbitmqctl stop_app
	rabbitmqctl reset
	rabbitmqctl join_cluster --ram rabbit@rabbitmq01
	rabbitmqctl start_app
	exit

	3)访问192.168.56.10:15675查看集群
	随便访问一个就可以15673、15674、15675都可以

4、实现镜像集群
	1)随便进入一个容器
	docker exec -it rabbitmq01 /bin/bash
	设置一个策略,/:当前主机,策略名字是ha,^指的是当前所有主机都是高可用模式[^hello 指hello开头的所有主机],自动同步
	rabbitmqctl set_policy -p / ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'     
	
	exit
	rabbitmqctl  list_policies -p /:查看vhost/下面的所有policy

5、验证集群
	1、创建一个queue
	2、生产一个消息【3个节点都能看到该消息】
	3、消费消息【3个节点的queue上消息都不存在了】

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值