目录
- 一、MySQL集群
- 1、mysql集群原理
- 2、Docker安装模拟MySQL主从复制集群
- 1、下载mysql镜像
- 2、创建Master实例并启动
- 3、创建 Slave 实例并启动
- 4、为 master 授权用户来同步数据
- 1、进入 master 容器
- 2、进入 mysql 内部 (mysql –uroot -p)
- 3、查看 master 状态
- 5、配置 slaver 同步 master 数据
- 1、进入 slaver 容器
- 2、进入 mysql 内部(mysql –uroot -p)
- 3、MyCat 或者 ShardingSphere
- 1、下载安装 Sharding-Proxy
- 2、配置数据分片+读写分离
- 3、server.yaml 文件
- 4、k8s 有状态服务部署
- 六、Redis 集群
- 1、redis 集群形式
- 2、高可用方式
- 3、部署 Cluster
- 4、k8s 部署 redis
- 七、Elasticsearch 集群
- 1、集群原理
- 2、集群健康
- 3、分片
- 4、新增节点
- 5、水平扩容-启动第三个节点
- 6、应对故障
- 7、问题与解决
- 8、集群结构
- 1、集群结构
- 2、集群搭建
- 0、准备 docker 网络
- 1、3-Master 节点创建
- 2、3-Data-Node 创建
- 3、测试集群
- 3、k8s 上部署
- 八、RabbitMQ 集群
- 1、集群形式
- 1、搭建集群
- 2、节点加入集群
- 3、实现镜像集群
- 2、集群测试
- 3、k8s 上部署
- 九、Jenkins
- 1、Jenkins
- 2、Jenkins 流水线
- 3、k8s 部署 nacos
- 4、k8s 部署 sentinel
- 5、k8s 部署 zipkin
- 十、K8S部署应用
- 1、k8s部署应用流程
- 2、生产环境配置抽取
- 3、创建微服务Dockerfile
- 4、创建微服务k8s部署描述文件
- 5、理解targetPort、port、nodePort
- 6、流水线第一步拉取gitee代码&参数化构建&环境变量
- 7、流水线第二步Sonar代码质量分析
- 8、流水线第三步构建&推送镜像
- 9、流水线第四步编写完成
- 10、部署-移植数据库
- 11、流水线部署所有微服务
- 12、部署整合阿里云镜像仓库
- 13、Jenkins修改阿里云镜像仓库
- 14、流水线部署gateway
- 15、流水线部署auth-server
- 16、部署cart
- 17、部署coupon
- 18、修改为共有仓库
- 19、部署前置nginx
- 20、创建网关与应用路由
- 21、部署前端vue项目
- 22、滚动更新部署admin-vue-app
- 23、线上预警和监控
一、MySQL集群
1、mysql集群原理
MySQL-MMM是Master-MasterReplicationManagerforMySQL(mysql主主复制管理器)的简称,是Google的开源项目。
(Perl脚本)。MMM基于MySQL Replication做的扩展架构,主要用来监控mysql主主复制并做失败转移。其原理是将真实数据库节点的IP(RIP)映射为虚拟IP(VIP)集。mysql-mmm的监管端会提供多个虚拟IP(VIP),包括一个可写VIP,多个可读VIP,通过监管的管理,这些IP会绑定在可用mysql之上,当某一台mysql宕机时,监管会将VIP 迁移至其他mysql。在整个监管过程中,需要在mysql中添加相关授权用户,以便让mysql可以支持监理机的维护。授权的用户包括一个mmm_monitor用户和一个mmm_agent用户,如果想使用mmm的备份工具则还要添加一个mmm_tools用户。
MHA(MasterHighAvailability)目前在MySQL高可用方面是一个相对成熟的解决方案,由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作(以2019年的眼光来说太慢了),并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
InnoDBCluster支持自动Failover、强一致性、读写分离、读库高可用、读请求负载均衡,横向扩展的特性,是比较完备的一套方案。但是部署起来复杂,想要解决router 单点问题好需要新增组件,如没有其他更好的方案可考虑该方案。InnoDBCluster主要由MySQLShell、MySQLRouter和MySQL服务器集群组成,三者协同工作,共同为MySQL提供完整的高可用性解决方案。MySQLShell对管理人员提供管理接口,可以很方便的对集群进行配置和管理,MySQLRouter可以根据部署的集群状况自动的初始化,是客户端连接实例。如果有节点down机,集群会自动更新配置。集群包含单点写入和多点写入两种模式。在单主模式下,如果主节点down掉,从节点自动替换上来,MySQLRouter会自动探测,并将客户端连接到新节点。
2、Docker安装模拟MySQL主从复制集群
1、下载mysql镜像
2、创建Master实例并启动
dockerrun-p3307:3306--namemysql-master\-v/mydata/mysql/master/log:/var/log/mysql\
-v/mydata/mysql/master/data:/var/lib/mysql\
-v/mydata/mysql/master/conf:/etc/mysql\
-eMYSQL_ROOT_PASSWORD=root\
-dmysql:5.7
参数说明
-p3307:3306:将容器的3306端口映射到主机的3307端口
-v/mydata/mysql/master/conf:/etc/mysql:将配置文件夹挂在到主机
-v/mydata/mysql/master/log:/var/log/mysql:将日志文件夹挂载到主机
-v/mydata/mysql/master/data:/var/lib/mysql/:将配置文件夹挂载到主机-eMYSQL_ROOT_PASSWORD=root:初始化root用户的密码
修改master基本配置
vim/mydata/mysql/master/conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SETcollation_connection=utf8_unicode_ci'
init_connect='SETNAMESutf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
注意:skip-name-resolve一定要加,不然连接mysql会超级慢
添加master主从复制部分配置server_id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=zhenyanmall_ums
binlog-do-db=zhenyanmall_pms
binlog-do-db=zhenyanmall_oms
binlog-do-db=zhenyanmall_sms
binlog-do-db=zhenyanmall_wms
binlog-do-db=zhenyanmall_admin
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重启 master
3、创建 Slave 实例并启动
docker run -p 3317:3306 --name mysql-slaver-01 \ -v /mydata/mysql/slaver/log:/var/log/mysql \ -v /mydata/mysql/slaver/data:/var/lib/mysql \ -v /mydata/mysql/slaver/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7
修改 slave 基本配置
vim /mydata/mysql/slaver/conf/my.cnf
[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
添加 master 主从复制部分配置
server_id=2
log-bin=mysql-bin
read-only=1
binlog-do-db=zhenyanmall_ums
binlog-do-db=zhenyanmall_pms
binlog-do-db=zhenyanmall_oms
binlog-do-db=zhenyanmall_sms
binlog-do-db=zhenyanmall_wms
binlog-do-db=zhenyanmall_admin
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重启 slaver
4、为 master 授权用户来同步数据
1、进入 master 容器
docker exec -it mysql /bin/bash
2、进入 mysql 内部 (mysql –uroot -p)
1)、授权 root 可以远程访问( 主从无关,为了方便我们远程连接 mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;
2)、添加用来同步的用户
GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';
3、查看 master 状态
show master status\G;
5、配置 slaver 同步 master 数据
1、进入 slaver 容器
docker exec -it mysql-slaver-01 /bin/bash
2、进入 mysql 内部(mysql –uroot -p)
1)、授权 root 可以远程访问( 主从无关,为了方便我们远程连接 mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;flush privileges;
2)、设置主库连接
change master to master_host='mysql-master.zhenyanmall',master_user='backup',master_password='123456',master_log_file='mysql-bin.000003',master_log_pos=0,master_port=3306;
3)、启动从库同步
start slave;
4)、查看从库状态
show slave status\G;
至此主从配置完成;
总结:
1)、主从数据库在自己配置文件中声明需要同步哪个数据库,忽略哪个数据库等信息。并且 server-id 不能一样
2)、主库授权某个账号密码来同步自己的数据
3)、从库使用这个账号密码连接主库来同步数据
测试:
在主库里面创建表,添加、修改、删除数据,
从库同步主库的操作
3、MyCat 或者 ShardingSphere
前面测试了数据库的主从同步问题,但是不能解决单表性能问题,所以要对数据进行分片存储,每个mysql只存一片数据,进行分库分表.
设置一个自增主键,第一个服务器设置自增id开始是1,每次步长是2,第二个服务器是从2增长,每次步长也是2,所以服务器1存的是1,3,5,所有的数据都是奇数列,服务器2存的是2,4,6,所有的数据都是偶数列,以后要查哪个去相应的节点里面进行查询即可。但是这种方式不好维护,最终也没有人使用这种方式。
使用分库分表需要使用一些中间件,比如mycat和 ShardingSphere.
shardingSphere: http://shardingsphere.apache.org/index_zh.html
auto_increment_offset: 1 从几开始增长
auto_increment_increment: 2 每次的步长
1、下载安装 Sharding-Proxy
镜像方式
docker pull apache/sharding-proxy docker run -d -v /mydata/sharding-proxy/conf:/opt/sharding-proxy/conf -v /mydata/sharding-proxy/lib:/opt/sharding-proxy/lib --env PORT=3308 -p13308:3308 apache/sharding-proxy:latest
压缩包下载
https://shardingsphere.apache.org/document/current/cn/downloads/
2、配置数据分片+读写分离
config-mallshard.yaml
schemaName: sharding_db
dataSources:
ds0:
url: jdbc:mysql://192.168.56.10:3307/ds0
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 65
ds0_slave0:
url: jdbc:mysql://192.168.56.10:3317/ds0
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 65
ds1:
url: jdbc:mysql://192.168.56.10:3307/ds1
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 65
ds1_slave0:
url: jdbc:mysql://192.168.56.10:3317/ds1
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 65
shardingRule:
tables:
t_order:
actualDataNodes: ds${0..1}.t_order${0..1}
databaseStrategy:
inline:
shardingColumn: user_id
algorithmExpression: ds${user_id % 2}
tableStrategy:
inline:
shardingColumn: order_id
algorithmExpression: t_order${order_id % 2}
keyGenerator:
type: SNOWFLAKE
column: order_id
t_order_item:
actualDataNodes: ds${0..1}.t_order_item${0..1}
databaseStrategy:
inline:
shardingColumn: user_id
algorithmExpression: ds${user_id % 2}
tableStrategy:
inline:
shardingColumn: order_id
algorithmExpression: t_order_item${order_id % 2}
keyGenerator:
type: SNOWFLAKE
column: order_item_id
bindingTables: - t_order,t_order_item
broadcastTables: - t_config
defaultDataSourceName: ds0
defaultTableStrategy:
none:
masterSlaveRules:
ms_ds0:
masterDataSourceName: ds0
slaveDataSourceNames: - ds0_slave0
loadBalanceAlgorithmType: ROUND_ROBIN
ms_ds1:
masterDataSourceName: ds1
slaveDataSourceNames: - ds1_slave0
loadBalanceAlgorithmType: ROUND_ROBIN
创建测试表
CREATE TABLE `t_order` (
`order_id` bigint(20) NOT NULL, `user_id` int(11) NOT NULL, `status` varchar(50) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `t_order_item` (
`order_item_id` bigint(20) NOT NULL, `order_id` bigint(20) NOT NULL, `user_id` int(11) NOT NULL, `content` varchar(255) COLLATE utf8_bin DEFAULT NULL, `status` varchar(50) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
3、server.yaml 文件
authentication:
users:
root:
password: root
sharding:
password: sharding
authorizedSchemas: sharding_db
4、k8s 有状态服务部署
可以使用 kubesphere,快速搭建 MySQL 环境。
有状态服务抽取配置为 ConfigMap
有状态服务必须使用 pvc 持久化数据
服务集群内访问使用 DNS 提供的稳定域名
六、Redis 集群
1、redis 集群形式
1、数据分区方案
1、客户端分区
客户端分区方案 的代表为 Redis Sharding,Redis Sharding 是 Redis Cluster 出来之前,业界普遍使用的 Redis 多实例集群 方法。Java 的 Redis 客户端驱动库 Jedis,支持 RedisSharding 功能,即 ShardedJedis 以及 结合缓存池 的 ShardedJedisPool。
优点
不使用 第三方中间件,分区逻辑 可控,配置 简单,节点之间无关联,容易 线性扩展,灵活性强。
缺点
客户端 无法 动态增删 服务节点,客户端需要自行维护 分发逻辑,客户端之间 无连接共享,会造成 连接浪费。
2、代理分区
代理分区常用方案有 Twemproxy 和 Codis。
3、redis-cluster
2、高可用方式
1、Sentinel( 哨兵机制)支持高可用
前面介绍了主从机制,但是从运维角度来看,主节点出现了问题我们还需要通过人工干预的方式把从节点设为主节点,还要通知应用程序更新主节点地址,这种方式非常繁琐笨重, 而且主节点的读写能力都十分有限,有没有较好的办法解决这两个问题,哨兵机制就是针对第
一个问题的有效解决方案,第二个问题则有赖于集群!哨兵的作用就是监控 Redis 系统的运行状况,其功能主要是包括以下三个:
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的 Master 和 Slave 是否运作正常。
提醒(Notification): 当被监控的某个 Redis 出现问题时, 哨兵(sentinel) 可以通过 API向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当主数据库出现故障时自动将从数据库转换为主数据库。
哨兵的原理
Redis 哨兵的三个定时任务,Redis 哨兵判定一个 Redis 节点故障不可达主要就是通过三个定时监控任务来完成的:
每隔 10 秒每个哨兵节点会向主节点和从节点发送"info replication" 命令来获取最新的拓扑结构
每隔 2 秒每个哨兵节点会向 Redis 节点的_sentinel_:hello 频道发送自己对主节点是否故障的判断以及自身的节点信息,并且其他的哨兵节点也会订阅这个频道来了解其他哨兵节点的信息以及对主节点的判断
每隔 1 秒每个哨兵会向主节点、从节点、其他的哨兵节点发送一个 “ping” 命令来做心跳检测
如果在定时 Job3 检测不到节点的心跳,会判断为“主观下线”。如果该节点还是主节点那么还会通知到其他的哨兵对该主节点进行心跳检测,这时主观下线的票数超过了数时,那么这个主节点确实就可能是故障不可达了,这时就由原来的主观下线变为了“客观下
线”。
故障转移和 Leader 选举
如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个 leader,这里面采用的选举算法为 Raft。选举出来的哨兵 leader 就要来完成故障转移工作,也就是在从节点中选出一个节点来当新的主节点,这部分的具体流程可参考引用. 《深入理解 Redis 哨兵搭建及原理》。
2、Redis-Cluster
https://redis.io/topics/cluster-tutorial/
Redis 的官方多机部署方案,Redis Cluster。一组 Redis Cluster 是由多个 Redis 实例组成,官方推荐我们使用 6 实例,其中 3 个为主节点,3 个为从结点。一旦有主节点发生故障的时候,Redis Cluster 可以选举出对应的从结点成为新的主节点,继续对外服务,从而保证服务的高可用性。那么对于客户端来说,知道知道对应的 key 是要路由到哪一个节点呢?Redis Cluster把所有的数据划分为 16384 个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的 Redis 实例,对于 Redis 实例来说,他们只会存储部分的 Redis 数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。
1、槽
Redis 集群的功能限制;Redis 集群相对 单机 在功能上存在一些限制,需要 开发人员 提前了解,在使用时做好规避。JAVA CRC16 校验算法
key 批量操作 支持有限。
类似 mset、mget 操作,目前只支持对具有相同 slot 值的 key 执行 批量操作。对于 映射为不同 slot 值的 key 由于执行 mget、mget 等操作可能存在于多个节点上,因此不被支持。
key 事务操作 支持有限。
只支持 多 key 在 同一节点上 的 事务操作,当多个 key 分布在 不同 的节点上时 无法 使用事务功能。
key 作为 数据分区 的最小粒度
不能将一个 大的键值 对象如 hash、list 等映射到 不同的节点。
不支持 多数据库空间
单机 下的 Redis 可以支持 16 个数据库(db0 ~ db15),集群模式 下只能使用 一个 数据库空间,即 db0。
复制结构 只支持一层
从节点 只能复制 主节点,不支持 嵌套树状复制 结构。
命令大多会重定向,耗时多
2、一致性 hash 一致性哈希 可以很好的解决 稳定性问题,可以将所有的 存储节点 排列在 收尾相接 的Hash 环上,每个 key 在计算 Hash 后会 顺时针 找到 临接 的 存储节点 存放。而当有节点 加入 或 退出 时,仅影响该节点在 Hash 环上 顺时针相邻 的 后续节点。
Hash 倾斜
如果节点很少,容易出现倾斜,负载不均衡问题。一致性哈希算法,引入了虚拟节点,在整个环上,均衡增加若干个节点。比如 a1,a2,b1,b2,c1,c2,a1 和 a2 都是属于 A 节点的。解决 hash 倾斜问题
3、部署 Cluster
1、创建 6 个 redis 节点
3 主 3 从方式,从为了同步备份,主进行 slot 数据分片
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} \ -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
docker stop $(docker ps -a |grep redis-700 | awk '{ print $1}')
docker rm $(docker ps -a |grep redis-700 | awk '{ print $1}')
2、使用 redis 建立集群
docker exec -it redis-7001 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
3、测试集群效果
随便进入某个 redis 容器
docker exec -it redis-7002 /bin/bash
使用 redis-cli 的 cluster 方式进行连接
redis-cli -c -h 192.168.56.10 -p 7006
cluster info; 获取集群信息
cluster nodes;获取集群节点
Get/Set 命令测试,将会重定向
节点宕机,slave 会自动提升为 master,master 开启后变为 slave
4、k8s 部署 redis
参照有状态部署即可
七、Elasticsearch 集群
1、集群原理
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、单节点
一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。
当一个节点被选举成为 主节点时, 它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。任何节点都可以成为主节点。我们的示例集群就只有一个节点,所以它同时也成为了主节点。
作为用户,我们可以将请求发送到 集群中的任何节点 ,包括主节点。 每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回給客户端。 Elasticsearch 对这一切的管理都是透明的。
2、集群健康
Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是 集群健康 , 它在 status 字段中展示为 green 、 yellow 或者 red 。
GET /_cluster/health
status 字段指示着当前集群在总体上是否工作正常。它的三种颜色含义如下:
green:所有的主分片和副本分片都正常运行。
yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行。
red:有主分片没能正常运行。
3、分片
一个 分片 是一个底层的 工作单元 ,它仅保存了全部数据中的一部分。我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。分片就认为是一个数据区
一个分片可以是 主 分片或者 副本 分片。索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改。
让我们在包含一个空节点的集群内创建名为 blogs 的索引。 索引在默认情况下会被分配 5 个主分片, 但是为了演示目的,我们将分配 3 个主分片和一份副本(每个主分片拥有一个副本分片):
PUT /blogs{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}}
此时集群的健康状况为 yellow 则表示全部 主分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态。 实际上,所有 3 个副本分片都是 unassigned —— 它们都没有被分配到任何节点。在同一个节点上既保存原始数据又保存副本是没有意义的,因为一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。
当前我们的集群是正常运行的,但是在硬件故障时有丢失数据的风险。
4、新增节点
当你在同一台机器上启动了第二个节点时,只要它和第一个节点有同样的 cluster.name 配置,它就会自动发现集群并加入到其中。 但是在不同机器上启动节点的时候,为了加入到同一集群,你需要配置一个可连接到的单播主机列表。 详细信息请查看最好使用单播代替组播
此时,cluster-health 现在展示的状态为 green ,这表示所有 6 个分片(包括 3 个主分片和3 个副本分片)都在正常运行。我们的集群现在不仅仅是正常运行的,并且还处于 始终可用 的状态。
5、水平扩容-启动第三个节点
Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点,现在每个节点上都拥有 2 个分片,而不是之前的 3 个。 这表示每个节点的硬件资源(CPU, RAM, I/O)将被更少的分片所共享,每个分片的性能将会得到提升。
在运行中的集群上是可以动态调整副本分片数目的,我们可以按需伸缩集群。让我们把副本数从默认的 1 增加到 2
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
blogs 索引现在拥有 9 个分片:3 个主分片和 6 个副本分片。 这意味着我们可以将集群扩容到 9 个节点,每个节点上一个分片。相比原来 3 个节点时,集群搜索性能可以提升 3 倍。
6、应对故障
我们关闭的节点是一个主节点。而集群必须拥有一个主节点来保证正常工作,所以发生的第一件事情就是选举一个新的主节点: Node 2 。
在我们关闭 Node 1 的同时也失去了主分片 1 和 2 ,并且在缺失主分片的时候索引也不能正常工作。 如果此时来检查集群的状况,我们看到的状态将会为 red :不是所有主分片都在正常工作。
幸运的是,在其它节点上存在着这两个主分片的完整副本, 所以新的主节点立即将这些分片在 Node 2 和 Node 3 上对应的副本分片提升为主分片, 此时集群的状态将会为 yellow 。 这个提升主分片的过程是瞬间发生的,如同按下一个开关一般。
为什么我们集群状态是 yellow 而不是 green 呢? 虽然我们拥有所有的三个主分片,但是同时设置了每个主分片需要对应 2 份副本分片,而此时只存在一份副本分片。 所以集群不能为 green 的状态,不过我们不必过于担心:如果我们同样关闭了 Node 2 ,我们的程序 依然 可以保持在不丢任何数据的情况下运行,因为 Node 3 为每一个分片都保留着一份副本。
如果我们重新启动 Node 1 ,集群可以将缺失的副本分片再次进行分配。如果 Node 1依然拥有着之前的分片,它将尝试去重用它们,同时仅从主分片复制发生了修改的数据文件。
7、问题与解决
1、主节点
主节点负责创建索引、删除索引、分配分片、追踪集群中的节点状态等工作。Elasticsearch中的主节点的工作量相对较轻,用户的请求可以发往集群中任何一个节点,由该节点负责分发和返回结果,而不需要经过主节点转发。而主节点是由候选主节点通过 ZenDiscovery 机
制选举出来的,所以要想成为主节点,首先要先成为候选主节点。
2、候选主节点
在 elasticsearch 集群初始化或者主节点宕机的情况下,由候选主节点中选举其中一个作为主节点。指定候选主节点的配置为:node.master: true。
当主节点负载压力过大,或者集中环境中的网络问题,导致其他节点与主节点通讯的时候,主节点没来的及响应,这样的话,某些节点就认为主节点宕机,重新选择新的主节点,这样的话整个集群的工作就有问题了,比如我们集群中有 10 个节点,其中 7 个候选主节点,1个候选主节点成为了主节点,这种情况是正常的情况。但是如果现在出现了我们上面所说的主节点响应不及时,导致其他某些节点认为主节点宕机而重选主节点,那就有问题了,这剩下的 6 个候选主节点可能有 3 个候选主节点去重选主节点,最后集群中就出现了两个主节点的情况,这种情况官方成为“脑裂现象”;
集群中不同的节点对于 master 的选择出现了分歧,出现了多个master 竞争,导致主分片和副本的识别也发生了分歧,对一些分歧中的分片标识为了坏片。
3、数据节点
数据节点负责数据的存储和相关具体操作,比如 CRUD、搜索、聚合。所以,数据节点对机器配置要求比较高,首先需要有足够的磁盘空间来存储数据,其次数据操作对系统 CPU、Memory 和 IO 的性能消耗都很大。通常随着集群的扩大,需要增加更多的数据节点来提高可用性。指定数据节点的配置:node.data: true。
elasticsearch 是允许一个节点既做候选主节点也做数据节点的,但是数据节点的负载较重,所以需要考虑将二者分离开,设置专用的候选主节点和数据节点,避免因数据节点负载重导致主节点不响应。
4、客户端节点
客户端节点就是既不做候选主节点也不做数据节点的节点,只负责请求的分发、汇总等等,但是这样的工作,其实任何一个节点都可以完成,因为在 elasticsearch 中一个集群内的节点都可以执行任何请求,其会负责将请求转发给对应的节点进行处理。所以单独增加这样的节
点更多是为了负载均衡。指定该节点的配置为:
node.master: false
node.data: false
5、脑裂”问题可能的成因
1.网络问题:集群间的网络延迟导致一些节点访问不到 master,认为 master 挂掉了从而选举出新的 master,并对 master 上的分片和副本标红,分配新的主分片
2.节点负载:主节点的角色既为 master 又为 data,访问量较大时可能会导致 ES 停止响应造成大面积延迟,此时其他节点得不到主节点的响应认为主节点挂掉了,会重新选取主节点。
3.内存回收:data 节点上的 ES 进程占用的内存较大,引发 JVM 的大规模内存回收,造成 ES进程失去响应。
脑裂问题解决方案:
角色分离:即 master 节点与 data 节点分离,限制角色;数据节点是需要承担存储和搜索的工作的,压力会很大。所以如果该节点同时作为候选主节点和数据节点,
那么一旦选上它作为主节点了,这时主节点的工作压力将会非常大,出现脑裂现象的概率就增加了。
减少误判:配置主节点的响应时间,在默认情况下,主节点 3 秒没有响应,其他节
点就认为主节点宕机了,那我们可以把该时间设置的长一点,该配置是:
discovery.zen.ping_timeout: 5
选举触发:discovery.zen.minimum_master_nodes:1(默认是 1),该属性定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。
一 个 有 10 节 点 的 集 群 , 且 每 个 节 点 都 有 成 为 主 节 点 的 资 格 ,discovery.zen.minimum_master_nodes 参数设置为 6。
正常情况下,10 个节点,互相连接,大于 6,就可以形成一个集群。
若某个时刻,其中有 3 个节点断开连接。剩下 7 个节点,大于 6,继续运行之前的集群。而断开的 3 个节点,小于 6,不能形成一个集群。
该参数就是为了防止”脑裂”的产生。
建议设置为(候选主节点数 / 2) + 1,
8、集群结构
1、集群结构
以三台物理机为例。在这三台物理机上,搭建了 6 个 ES 的节点,三个 data 节点,三个 master节点(每台物理机分别起了一个 data 和一个 master),3 个 master 节点,目的是达到(n/2)+1 等于 2 的要求,这样挂掉一台 master 后(不考虑 data),n 等于 2,满足参数,其他两个 master 节点都认为 master 挂掉之后开始重新选举,
master 节点上
node.master = true
node.data = false
discovery.zen.minimum_master_nodes = 2
data 节点上
node.master = false
node.data = true
2、集群搭建
所有之前先运行:sysctl -w vm.max_map_count=262144
我们只是测试,所以临时修改。永久修改使用下面
#防止 JVM 报错
echo vm.max_map_count=262144 >> /etc/sysctl.conf
sysctl -p
0、准备 docker 网络
Docker 创建容器时默认采用 bridge 网络,自行分配 ip,不允许自己指定。
在实际部署中,我们需要指定容器 ip,不允许其自行分配 ip,尤其是搭建集群时,固定 ip是必须的。
我们可以创建自己的 bridge 网络 : mynet,创建容器的时候指定网络为 mynet 并指定 ip即可。
查看网络模式 docker network ls
;
创建一个新的 bridge 网络
docker network create --driver bridge --subnet=172.18.12.0/16 --gateway=172.18.1.1
mynet
查看网络信息
docker network inspect mynet
以后使用–network=mynet --ip 172.18.12.x 指定 ip
1、3-Master 节点创建
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.minimum_master_nodes: 2 #设置这个参数来保证集群中的节点可以知道其
它 N 个有 master 资格的节点。官方推荐(N/2)+1
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: ["172.18.12.21:9301", "172.18.12.22:9302", "172.18.12.23:9303"] #设置集
群中的 Master 节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7
的新增配置
cluster.initial_master_nodes: ["172.18.12.21"] #新集群初始时的候选主节点,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \ -p 920${port}:920${port} -p 930${port}:930${port} \ --network=mynet --ip 172.18.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \ -v
/mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/el
asticsearch.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
docker stop $(docker ps -a |grep elasticsearch-node-* | awk '{ print $1}')
docker rm $(docker ps -a |grep elasticsearch-node-* | awk '{ print $1}')
2、3-Data-Node 创建
for port in $(seq 4 6); \
do \
mkdir -p /mydata/elasticsearch/node-${port}/config
mkdir -p /mydata/elasticsearch/node-${port}/data
chmod -R 777 /mydata/elasticsearch/node-${port}
cat << EOF >/mydata/elasticsearch/node-${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
#network.publish_host: 192.168.56.10 #互相通信 ip,要设置为本机可被外界访问的 ip,否则
无法通信
http.host: 0.0.0.0 #所有 http 均可访问
http.port: 920${port}
transport.tcp.port: 930${port}
#discovery.zen.minimum_master_nodes: 2 #设置这个参数来保证集群中的节点可以知道其
它 N 个有 master 资格的节点。官方推荐(N/2)+1
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: ["172.18.12.21:9301", "172.18.12.22:9302", "172.18.12.23:9303"] #设置集
群中的 Master 节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7
的新增配置
cluster.initial_master_nodes: ["172.18.12.21"] #新集群初始时的候选主节点,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \ -p 920${port}:920${port} -p 930${port}:930${port} \ --network=mynet --ip 172.18.12.2${port} \ -e ES_JAVA_OPTS="-Xms300m -Xmx300m" \ -v
/mydata/elasticsearch/node-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/ela
sticsearch.yml \ -v /mydata/elasticsearch/node-${port}/data:/usr/share/elasticsearch/data \ -v /mydata/elasticsearch/node-${port}/plugins:/usr/share/elasticsearch/plugins \ -d elasticsearch:7.4.2
done
3、测试集群
http://192.168.56.10:9201/_nodes/process?pretty 查看节点状况
http://192.168.56.10:9201/_cluster/stats?pretty 查看集群状态
http://192.168.56.10:9201/_cluster/health?pretty 查看集群健康状况
http://192.168.56.10:9202/_cat/nodes 查看各个节点信息
$ curl localhost:9200/_cat
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}
3、k8s 上部署
有状态服务
jvm.options -Xms100m
-Xmx512m
八、RabbitMQ 集群
1、集群形式
RabbiMQ 是用 Erlang 开发的,集群非常方便,因为 Erlang 天生就是一门分布式语言,但其本身并不支持负载均衡。
RabbitMQ 集群中节点包括内存节点(RAM)、磁盘节点(Disk,消息持久化),集群中至少有一个 Disk 节点。
普通模式(默认)
对于普通模式,集群中各节点有相同的队列结构,但消息只会存在于集群中的一个节点。对于消费者来说,若消息进入 A 节点的 Queue 中,当从 B 节点拉取时,RabbitMQ 会将消息从 A 中取出,并经过 B 发送给消费者。
应用场景:该模式各适合于消息无需持久化的场合,如日志队列。当队列非持久化,且创建该队列的节点宕机,客户端才可以重连集群其他节点,并重新创建队列。若为持久化,只能等故障节点恢复。
镜像模式
与普通模式不同之处是消息实体会主动在镜像节点间同步,而不是在取数据时临时拉取,高可用;该模式下,mirror queue 有一套选举算法,即 1 个 master、n 个 slaver,生产者、消费者的请求都会转至 master。
应用场景:可靠性要求较高场合,如下单、库存队列。
缺点:若镜像队列过多,且消息体量大,集群内部网络带宽将会被此种同步通讯所消耗。
(1)镜像集群也是基于普通集群,即只有先搭建普通集群,然后才能设置镜像队列。
(2)若消费过程中,master 挂掉,则选举新 master,若未来得及确认,则可能会重复消费
1、搭建集群
mkdir /mydata/rabbitmq
cd rabbitmq/
mkdir rabbitmq01 rabbitmq02 rabbitmq03
docker run -d --hostname rabbitmq01 --name rabbitmq01 -v
/mydata/rabbitmq/rabbitmq01:/var/lib/rabbitmq -p 15673:15672 -p 5673:5672 -e
RABBITMQ_ERLANG_COOKIE='wxn' 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='wxn' --link rabbitmq01:rabbitmq01
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='wxn' --link rabbitmq01:rabbitmq01 --link
rabbitmq02:rabbitmq02 rabbitmq:management
--hostname 设置容器的主机名
RABBITMQ_ERLANG_COOKIE 节点认证作用,部署集成时 需要同步该值
2、节点加入集群
docker exec -it rabbitmq01 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
Exit
进入第二个节点
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 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbitmq01
rabbitmqctl start_app
exit
3、实现镜像集群
docker exec -it rabbitmq01 bash
rabbitmqctl set_policy -p / ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}' 可以使用 rabbitmqctl list_policies -p /;查看 vhost/下面的所有 policy
在 cluster 中任意节点启用策略,策略会自动同步到集群节点
rabbitmqctl set_policy-p/ha-all"^"’{“ha-mode”:“all”}’
策略模式 all 即复制到所有节点,包含新增节点,策略正则表达式为 “^” 表示所有匹配所有队列名称。“^hello”表示只匹配名为 hello 开始的队列
2、集群测试
随便在 mq 上创建一个队列,发送一个消息,保证整个集群其他节点都有这个消息。如果
master 宕机,其他节点也能成为新的 master
3、k8s 上部署
九、Jenkins
1、Jenkins
官方文档 https://jenkins.io/zh/doc/pipeline/tour/getting-started/
Jenkins 是开源 CI&CD 软件领导者, 提供超过 1000 个插件来支持构建、部署、自动化, 满足任何项目的需要。
2、Jenkins 流水线
https://jenkins.io/zh/doc/book/pipeline
3、k8s 部署 nacos
docker run --env MODE=standalone --name nacos \ -v /mydata/nacos/conf:/home/nacos/conf -d -p 8848:8848 nacos/nacos-server:1.1.4
4、k8s 部署 sentinel
可以制作一个镜像并启动它,暴露访问
docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard:1.6.3
5、k8s 部署 zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
或者
docker run --env STORAGE_TYPE=elasticsearch --env ES_HOSTS=192.168.56.10:9200
openzipkin/zipkin