网站开发公司东莞,网站推广计划书具体包含哪些基本内容?,设计师必备的软件,重庆九龙坡营销型网站建设公司哪家专业前言
学习视频#xff1a;Java项目《谷粒商城》架构师级Java项目实战#xff0c;对标阿里P6-P7#xff0c;全网最强学习文档#xff1a; 谷粒商城-个人笔记(基础篇一)谷粒商城-个人笔记(基础篇二)谷粒商城-个人笔记(基础篇三)谷粒商城-个人笔记(高级篇一)谷粒商城-个…前言
学习视频Java项目《谷粒商城》架构师级Java项目实战对标阿里P6-P7全网最强学习文档 谷粒商城-个人笔记(基础篇一)谷粒商城-个人笔记(基础篇二)谷粒商城-个人笔记(基础篇三)谷粒商城-个人笔记(高级篇一)谷粒商城-个人笔记(高级篇二)谷粒商城-个人笔记(高级篇三)谷粒商城-个人笔记(高级篇四)谷粒商城-个人笔记(高级篇五)谷粒商城-个人笔记(集群部署篇一)谷粒商城-个人笔记(集群部署篇二)
3. 接口文档https://easydoc.net/s/78237135/ZUqEdvA4/hKJTcbfd 4. 本内容仅用于个人学习笔记如有侵扰联系删
五、MySQL 集群
0、集群简介 集群的目标 高可用High Availability是当一台服务器停止服务后对于业务及用户毫无影响。 停止服务的原因可能由于网卡、路由器、机房、CPU负载过高、内存溢出、自然灾害等不可预期的原因导致在很多时候也称单点问题。突破数据量限制一台服务器不能储存大量数据需要多台分担每个存储一部分共同存储完整个集群数据。最好能做到互相备份即使单节点故障也能在其他节点找到数据。数据备份容灾单点故障后存储的数据仍然可以在别的地方拉起。压力分担由于多个服务器都能完成各自一部分工作所以尽量的避免了单点压力的存在 集群的基础形式
1、集群原理 以上可以作为企业中常用的数据库解决方案
MySQL-MMM 是 Master-Master Replication Manager for MySQLmysql 主主复制管理器的简称是 Google 的开源项目Perl 脚本。MMM 基于 MySQL Replication 做的扩展架构主要用来监控 mysql 主主复制并做失败转移。其原理是将真实数据库节点的IPRIP映射为虚拟 IPVIP集。 mysql-mmm 的监管端会提供多个虚拟 IPVIP包括一个可写 VIP多个可读 VIP通过监管的管理这些 IP 会绑定在可用 mysql 之上当某一台 mysql 宕机时监管会将 VIP迁移至其他 mysql。在整个监管过程中需要在 mysql 中添加相关授权用户以便让 mysql 可以支持监理机的维护。授权的用户包括一个mmm_monitor 用户和一个 mmm_agent 用户如果想使用 mmm 的备份工具则还要添加一个 mmm_tools 用户。 MHAMaster High Availability目前在 MySQL 高可用方面是一个相对成熟的解决方案, 由日本 DeNA 公司 youshimaton现就职于 Facebook 公司开发是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中MHA 能做到在 0~30 秒之内自动完成数据库的故障切换操作以 2019 年的眼光来说太慢了并且在进行故障切换的过程中MHA 能在最大程度上保证数据的一致性以达到真正意义上的高可用。InnoDB Cluster 支持自动 Failover、强一致性、读写分离、读库高可用、读请求负载均衡横向扩展的特性是比较完备的一套方案。但是部署起来复杂想要解决 router单点问题好需要新增组件如没有其他更好的方案可考虑该方案。 InnoDB Cluster 主要由 MySQL Shell、MySQL Router 和 MySQL 服务器集群组成三者协同工作共同为MySQL 提供完整的高可用性解决方案。MySQL Shell 对管理人员提供管理接口可以很方便的对集群进行配置和管理,MySQL Router 可以根据部署的集群状况自动的初始化是客户端连接实例。如果有节点 down 机集群会自动更新配置。集群包含单点写入和多点写入两种模式。在单主模式下如果主节点 down 掉从节点自动替换上来MySQL Router 会自动探测并将客户端连接到新节点。
2、Docker 安装模拟 MySQL 主从复制集群
2.1、下载 mysql 镜像
docker pull mysql:5.72.2、创建 Master 实例并启动
docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORDroot \
-d mysql:5.7参数说明
-p 3307: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/将配置文件夹挂载到主机-e MYSQL_ROOT_PASSWORDroot初始化 root 用户的密码
修改 master 基本配置
vim /mydata/mysql/master/conf/my.cnf[client]
default-character-setutf8[mysql]
default-character-setutf8[mysqld]
init_connectSET collation_connection utf8_unicode_ci
init_connectSET NAMES utf8
character-set-serverutf8
skip-character-set-client-handshake
skip-name-resolve
# 注意skip-name-resolve 一定要加不然连接 mysql 会超级慢添加 master 主从复制部分配置
vim /mydata/mysql/master/conf/my.cnfserver_id1
log-binmysql-bin
read-only0
binlog-do-dbgulimall_ums
binlog-do-dbgulimall_pms
binlog-do-dbgulimall_oms
binlog-do-dbgulimall_sms
binlog-do-dbgulimall_wms
binlog-do-dbgulimall_admin
replicate-ignore-dbmysql
replicate-ignore-dbsys
replicate-ignore-dbinformation_schema
replicate-ignore-dbperformance_schema重启 master
docker restart mysql-master2.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_PASSWORDroot \
-d mysql:5.7修改 slave 基本配置
vim /mydata/mysql/slaver/conf/my.cnf[client]
default-character-setutf8[mysql]
default-character-setutf8[mysqld]
init_connectSET collation_connection utf8_unicode_ci
init_connectSET NAMES utf8
character-set-serverutf8
skip-character-set-client-handshake
skip-name-resolve添加 master 主从复制部分配置
vim /mydata/mysql/slaver/conf/my.cnfserver_id2
log-binmysql-bin
read-only1
binlog-do-dbgulimall_ums
binlog-do-dbgulimall_pms
binlog-do-dbgulimall_oms
binlog-do-dbgulimall_sms
binlog-do-dbgulimall_wms
binlog-do-dbgulimall_admin
replicate-ignore-dbmysql
replicate-ignore-dbsys
replicate-ignore-dbinformation_schema
replicate-ignore-dbperformance_schema重启 slaver
docker restart mysql-slaver-012.4、为 master 授权用户来他的同步数据
直接用navicat连接mysql-master数据库执行步骤2.2、3就可以
#1、进入 master 容器
docker exec -it mysql /bin/bash
#2、进入 mysql 内部 mysql –uroot -p
#2.1、授权 root 可以远程访问 主从无关为了方便我们远程连接 mysql
grant all privileges on *.* to root% identified by root with grant option;
flush privileges;
#2.2、添加用来同步的用户
GRANT REPLICATION SLAVE ON *.* to backup% identified by 123456;
#3、查看 master 状态
show master status;2.5、配置 slaver 同步 master 数据
#1、进入 slaver 容器
docker exec -it mysql-slaver-01 /bin/bash
#2、进入 mysql 内部mysql –uroot -p
#2.1、授权 root 可以远程访问 主从无关为了方便我们远程连接 mysql
grant all privileges on *.* to root% identified by root with grant option;
flush privileges;
#2.2、设置主库连接
change master to master_host192.168.119.127,master_userbackup,master_password123456,master_log_filemysql-bin.000001,master_log_pos0,master_port3307;
#3、启动从库同步
start slave;
#4、查看从库状态
show slave status;至此主从配置完成
总结
主从数据库在自己配置文件中声明需要同步哪个数据库忽略哪个数据库等信息。并且 server-id 不能一样主库授权某个账号密码来同步自己的数据从库使用这个账号密码连接主库来同步数据
3、MyCat 或者 ShardingSphere
shardingSphere: https://shardingsphere.apache.org/index_zh.html auto_increment_offset: 1 从几开始增长 auto_increment_increment: 2 每次的步长
简介 Apache ShardingSphere 是一款分布式的数据库生态系统 可以将任意数据库转换为分布式数据库并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。
Apache ShardingSphere 设计哲学为 Database Plus旨在构建异构数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力而并非实现一个全新的数据库。 它站在数据库的上层视角关注它们之间的协作多于数据库自身。 ShardingSphere-JDBC ShardingSphere-JDBC 定位为轻量级 Java 框架在 Java 的 JDBC 层提供的额外服务。 ShardingSphere-Proxy ShardingSphere-Proxy 定位为透明化的数据库代理端通过实现数据库二进制协议对异构语言提供支持。 3.1、下载安装 Sharding-Proxy 镜像方式 docker pull apache/sharding-proxydocker run -d -v /mydata/sharding-proxy/conf:/opt/sharding-proxy/conf -v
/mydata/sharding-proxy/lib:/opt/sharding-proxy/lib --env PORT3308 -p13308:3308
apache/sharding-proxy:latest压缩包下载 https://shardingsphere.apache.org/document/current/cn/downloads/
3.2、server.yaml 文件
authentication:users:root:password: rootsharding:password: sharding authorizedSchemas: sharding_db
#
props:
# max.connections.size.per.query: 1
# acceptor.size: 16 # The default value is available processors count * 2.executor.size: 16 # Infinite by default.
# proxy.frontend.flush.threshold: 128 # The default value is 128.
# # LOCAL: Proxy will run with LOCAL transaction.
# # XA: Proxy will run with XA transaction.
# # BASE: Proxy will run with B.A.S.E transaction.
# proxy.transaction.type: LOCAL
# proxy.opentracing.enabled: false
# query.with.cipher.column: truesql.show: false3.3、配置数据分片读写分离 数据分片 - config-sharding.yaml ######################################################################################################
#
# If you want to connect to MySQL, you should manually copy MySQL driver to lib directory.
#
######################################################################################################schemaName: sharding_db
#
dataSources:ds_0:url: jdbc:mysql://192.168.119.127:3307/demo_ds_0?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50ds_1:url: jdbc:mysql://192.168.119.127:3307/demo_ds_1?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50
#
shardingRule:tables:t_order:actualDataNodes: ds_${0..1}.t_order_${0..1}tableStrategy:inline:shardingColumn: order_idalgorithmExpression: t_order_${order_id % 2}keyGenerator:type: SNOWFLAKEcolumn: order_idt_order_item:actualDataNodes: ds_${0..1}.t_order_item_${0..1}tableStrategy:inline:shardingColumn: order_idalgorithmExpression: t_order_item_${order_id % 2}keyGenerator:type: SNOWFLAKEcolumn: order_item_idbindingTables:- t_order,t_order_itemdefaultDatabaseStrategy:inline:shardingColumn: user_idalgorithmExpression: ds_${user_id % 2}defaultTableStrategy:none:读写分离 config-master_slave.yaml ######################################################################################################
#
# If you want to connect to MySQL, you should manually copy MySQL driver to lib directory.
#
######################################################################################################schemaName: sharding_db_1
#
dataSources:master_0_ds:url: jdbc:mysql://192.168.119.127:3307/demo_ds_0?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50slave_ds_0:url: jdbc:mysql://192.168.119.127:3317/demo_ds_0?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50
masterSlaveRule:name: ms_dsmasterDataSourceName: master_0_dsslaveDataSourceNames:- slave_ds_0
# - slave_ds_1
# - slave_ds_1config-master_slave_2.yaml ######################################################################################################
#
# If you want to connect to MySQL, you should manually copy MySQL driver to lib directory.
#
######################################################################################################schemaName: sharding_db_2
#
dataSources:master_1_ds:url: jdbc:mysql://192.168.119.127:3307/demo_ds_1?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50slave_ds_1:url: jdbc:mysql://192.168.119.127:3317/demo_ds_1?serverTimezoneUTCuseSSLfalseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50
masterSlaveRule:name: ms_ds_1masterDataSourceName: master_1_dsslaveDataSourceNames:- slave_ds_1
# - slave_ds_1
# - slave_ds_13.4、修改 修改mysql-master和mysql-slaver-01服务的my.cnf添加我们ShardingSphere配置的数据库
binlog-do-dbdemo_ds_0
binlog-do-dbdemo_ds_1重启数据库 docker restart mysql-master mysql-slaver-01mysql-master和mysql-slaver-01连接创建两个库demo_ds_0、demo_ds_1 进入sharding-proxy的bin目录下cmd 输入start.bat 3388指定端口号
D:\ShardingSphere\apache-shardingsphere-incubating-4.0.0-sharding-proxy-bin\binstart.bat 3388在sharding_db创建测试表
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)
) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_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)
) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin;4、k8s 有状态服务部署
可以使用 kubesphere快速搭建 MySQL 环境。
有状态服务抽取配置为 ConfigMap有状态服务必须使用 pvc 持久化数据服务集群内访问使用 DNS 提供的稳定域名 具体搭建流程
4.1、 mysql-master(mysql主节点)
4.1.1、创建配置 - mysql-mster-cnf
我们把mysql配置的配置文件也单独挂在出来先关闭服务创建点击 配置中心 -》配置创建mysql-mster-cnf文件 填写基本信息 名称mysql-mster-cnf别名mysql配置 配置设置 键my.cnf值 [client]
default-character-setutf8[mysql]
default-character-setutf8[mysqld]
init_connectSET collation_connection utf8_unicode_ci
init_connectSET NAMES utf8
character-set-serverutf8
skip-character-set-client-handshake
skip-name-resolveserver_id1
log-binmysql-bin
read-only0
binlog-do-dbgulimall_ums
binlog-do-dbgulimall_pms
binlog-do-dbgulimall_oms
binlog-do-dbgulimall_sms
binlog-do-dbgulimall_wms
binlog-do-dbgulimall_admin
replicate-ignore-dbmysql
replicate-ignore-dbsys
replicate-ignore-dbinformation_schema
replicate-ignore-dbperformance_schema创建
4.1.2、创建存储卷 - gulimall-mysql-master-pvc
创建名称为gulimall-mysql-master-pvc的存储卷
4.1.3、创建服务 - gulimall-mysql-master 选择有状态服务 填写基本信息 名称gulimall-mysql-master别名mysql主节点 容器镜像 容器组选择分散部署 添加容器镜像 这里我们使用的私有镜像仓库-Harbor创建容器,使用默认端口内存要大于1000M环境变量选择原先配置好的MYSQL_ROOT_PASSWORD 挂载存储 挂载配置文件 首先选择我们先前配置好的配置文件mysql-master-cnf然后选择读写模式 我们查看原先docker创建mysql-master发现我们以前挂载mysql的配置都是 /etc/mysql 下的所以我们路径填写 /etc/mysql然后点击√ 添加存储卷 首先选择我们先前创建好的存储卷gulimall-mysql-master-pvc然后选择读写模式我们查看原先docker创建mysql-master发现我们以前挂载mysql的数据都是 /var/lib/mysql 下的所以我们路径填写 /var/lib/mysql然后点击√ 点击下一步 点击创建 至此gulimall-mysql-master服务创建完成
4.1.4、测试 验证容器是否创建成功 点击gulimall-mysql-master进去之后我们可以看到服务是运行中代表服务创建成功。 验证创建的mysql-master服务是否正确 进入容器组的 gulimall-mysql-master-ii799w-0 点击终端进入容器内部查看配置是否是我们配置的内容可以看到my.conf正是我们的配置 验证其他服务是否能ping通 我们看到gulimall-mysql-master服务的DNS为gulimall-mysql-master.gulimall我们在kubespere找一个其他服务进行测试看看是否能ping通。 点击 worpress服务 -》容器组 -》wordpress-v1-5d8b597899-xz5cn进入页面然后点击左上角的终端 ping gulimall-mysql-master.gulimall结果看到可以ping通。
4.2、 mysql-slaver(mysql从节点)
4.2.1、创建配置 - mysql-slaver-cnf
我们把mysql配置的配置文件也单独挂在出来先关闭服务创建点击 配置中心 -》配置创建mysql-mster-cnf文件
填写基本信息 名称mysql-slaver-cnf别名mysql-slaver配置 2. 配置设置 键my.cnf 值 [client]
default-character-setutf8[mysql]
default-character-setutf8[mysqld]
init_connectSET collation_connection utf8_unicode_ci
init_connectSET NAMES utf8
character-set-serverutf8
skip-character-set-client-handshake
skip-name-resolveserver_id2
log-binmysql-bin
read-only1
binlog-do-dbgulimall_ums
binlog-do-dbgulimall_pms
binlog-do-dbgulimall_oms
binlog-do-dbgulimall_sms
binlog-do-dbgulimall_wms
binlog-do-dbgulimall_admin
replicate-ignore-dbmysql
replicate-ignore-dbsys
replicate-ignore-dbinformation_schema
replicate-ignore-dbperformance_schema4.2.2、创建存储卷 - gulimall-mysql-slaver-pvc
创建名称为gulimall-mysql-slaver-pvc的存储卷
4.2.3、创建服务 - gulimall-mysql-slaver 选择有状态服务 填写基本信息 名称gulimall-mysql-slaver别名mysql从节点 容器镜像 容器组选择分散部署 添加容器镜像 这里我们使用的私有镜像仓库-Harbor创建容器,使用默认端口内存要大于1000M环境变量选择原先配置好的MYSQL_ROOT_PASSWORD 挂载存储 挂载配置文件 首先选择我们先前配置好的配置文件mysql-slaver-cnf然后选择读写模式 我们查看原先docker创建mysql-slaver-01发现我们以前挂载mysql的配置都是 /etc/mysql 下的所以我们路径填写 /etc/mysql然后点击√ 添加存储卷 首先选择我们先前创建好的存储卷gulimall-mysql-slaver-pvc然后选择读写模式我们查看原先docker创建mysql-slaver-01发现我们以前挂载mysql的数据都是 /var/lib/mysql 下的所以我们路径填写 /var/lib/mysql然后点击√ 点击下一步 点击创建 至此gulimall-mysql-slaver服务创建完成
4.3、为 master 授权用户来他的同步数据 点击 gulimall-mysql-master 服务 -》容器组 -》gulimall-mysql-master-ii799w-0进入页面然后点击左上角的终端进入容器输入 mysql -uroot -p123456 登录mysql 添加用来同步的用户 GRANT REPLICATION SLAVE ON *.* to backup% identified by 123456;查看 master 状态 show master status;退出容器
4.4、配置 slaver 同步 master 数据 点击 gulimall-mysql-slaver 服务 -》容器组 -》gulimall-mysql-slaver-3urxgv-0进入页面然后点击左上角的终端进入容器输入 mysql -uroot -p123456 登录mysql 设置主库连接 change master to master_hostgulimall-mysql-master.gulimall,master_userbackup,master_password123456,master_log_filemysql-bin.000002,master_log_pos0,master_port3306;启动从库同步 start slave;查看从库状态 show slave status\G;4.5、测试
在guilimall-mysql-master服务创建一个数据库看看是否可以同步到gulimall-mysql-slaver
进入gulimall-mysql-master容器,查看都有哪些数据库show databases;创建数据库
CREATE DATABASE gulimall_oms DEFAULT CHARACTER SET utf8mb4;3. 去gulimall-mysql-slaver服务验证是否同步过来 可以看到创建的数据库已经同步过来
4.6、k8s搭建服务思路
每一个MySQL/Redis/elasticseash/rabbitmq必须都是-个有状态服务每一个MySQL/Redis/elasticseash/rabbitmq挂载自己配置文件(cm)和PVC以后的IP都用域名即可搭建出集群
因为电脑配置原因后面的服务集群我们不全部使用集群方法都是想通的后面都是搭建单机
六、Redis 集群
1、redis 集群形式
1.1、数据分区方案
1、客户端分区 客户端分区方案 的代表为 Redis ShardingRedis Sharding 是 Redis Cluster 出来之前业界普遍使用的 Redis 多实例集群 方法。Java 的 Redis 客户端驱动库 Jedis支持 Redis Sharding 功能即 ShardedJedis 以及 结合缓存池 的 ShardedJedisPool。 优点 不使用 第三方中间件分区逻辑 可控配置 简单节点之间无关联容易 线性扩展灵 活性强。 缺点 客户端 无法 动态增删 服务节点客户端需要自行维护 分发逻辑客户端之间 无连接共享 会造成 连接浪费。
2、代理分区 代理分区常用方案有 Twemproxy 和 Codis。
3、redis-cluster
1.2、高可用方式
1.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 哨兵搭建及原理》
1.2.2、redis-cluster
详见下章
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 数据当然槽的数据是可以迁移的不同的实例之间可以通过一定的协议进行数据迁移。
2.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.2、一致性 hash
一致性哈希 可以很好的解决 稳定性问题可以将所有的 存储节点 排列在 收尾相接 的Hash 环上每个 key 在计算 Hash 后会 顺时针 找到 临接 的 存储节点 存放。而当有节点 加入 或 退出 时仅影响该节点在 Hash 环上 顺时针相邻 的 后续节点。 Hash 倾斜 如果节点很少容易出现倾斜负载不均衡问题。一致性哈希算法引入了虚拟节点在整个环上均衡增加若干个节点。比如 a1a2b1b2c1c2a1 和 a2 都是属于 A 节点的。解决 hash 倾斜问题
3、部署 Cluster
3.1、创建 6 个 redis 节点
3 主 3 从方式从为了同步备份主进行 slot 数据分片
for port in $(seq 7001 7006); domkdir -p /mydata/redis/node-${port}/conftouch /mydata/redis/node-${port}/conf/redis.confcat 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.119.127
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOFdocker 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})3.2、使用 redis 建立集群
# 随便进入一个redis节点容器
docker exec -it redis-7001 bash
# 通过redis-cli创建redis集群
redis-cli --cluster create 192.168.119.127:7001 192.168.119.127:7002 192.168.119.127:7003 192.168.119.127:7004 192.168.119.127:7005 192.168.119.127:7006 --cluster-replicas 13.3、测试集群效果
随便进入某个 redis 容器
docker exec -it redis-7002 /bin/bash使用 redis-cli 的 cluster 方式进行连接
redis-cli -c -h 192.168.119.127 -p 7006Get/Set 命令测试将会重定向节点宕机slave 会自动提升为 mastermaster 开启后变为 slave
root174151a9f811:/data# redis-cli -c -h 192.168.119.127 -p 7006
192.168.119.127:7006 set hello 1
- Redirected to slot [866] located at 192.168.119.127:7001
OK
192.168.119.127:7001 set a aaaa
- Redirected to slot [15495] located at 192.168.119.127:7003
OK
192.168.119.127:7003 get hello
- Redirected to slot [866] located at 192.168.119.127:7001
1
192.168.119.127:7001 get a
- Redirected to slot [15495] located at 192.168.119.127:7003
aaaa
192.168.119.127:7003获取集群信息
cluster info获取集群节点
cluster nodes4、k8s部署redis
参照有状态部署即可
4.1、创建配置 - redis-conf
基本信息 名称redis-conf 配置设置 键(Key)redis-conf值(Value)appendonly yes 创建
4.2、创建存储卷 - gulimall-redis-pvc
基本信息 创建名称为gulimall-redis-pvc的存储卷 存储卷设置 创建
4.3、创建服务- gulimall -redis 选择有状态服务 填写基本信息 名称gulimall-redis别名redis服务 容器镜像 因为就一个容器我们容器组选择容器组默认部署就好 添加容器镜像 这里我们使用的私有镜像仓库-Harbor创建容器,使用默认端口
设置一个启动命令这里配置参考docker创建 6 个 redis 节点的命令 redis-server /etc/redis/redis.conf 4. 下一步 5. 挂载存储 - 挂载存储卷 这里的挂载路径也参考docker创建 6 个 redis 节点的命令 /data - 挂载配置文件 - 文件挂载路径/etc/redis - 特定的键redis-conf - 路径redis.conf 这里的配置我们参考创建 6 个 redis 节点的命令下一步 创建
4.4、测试
我们点击 gulimall-redis 服务 -》 容器组 -》gulimall-redis-4vf9pc-0 -》端口 通过redis-cli客户端命令进行get和set方法测试
# redis-cli
127.0.0.1:6379 set hello aaa
OK
127.0.0.1:6379 get hello
aaa
127.0.0.1:6379七、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.1、单节点 一个运行中的 Elasticsearch 实例称为一个节点而集群是由一个或者多个拥有相同cluster.name 配置的节点组成 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时集群将会重新平均分布所有的数据。当一个节点被选举成为 主节点时 它将负责管理集群范围内的所有变更例如增加、删除索引或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作所以当集群只拥有一个主节点的情况下即使流量的增加它也不会成为瓶颈。任何节点都可以成为主节点。我们的示例集群就只有一个节点所以它同时也成为了主节点。作为用户我们可以将请求发送到 集群中的任何节点 包括主节点。 每个节点都知道任意文档所处的位置并且能够将我们的请求直接转发到存储我们所需文档的节点。无论我们将请求发送到哪个节点它都能负责从各个包含我们所需文档的节点收集回数据并将最终结果返回給客户端。 Elasticsearch 对这一切的管理都是透明的。
1.2、集群健康
Elasticsearch 的集群监控信息中包含了许多的统计数据其中最为重要的一项就是 集群健康 它在 status 字段中展示为 green 、 yellow 或者 red 。 status 字段指示着当前集群在总体上是否工作正常。它的三种颜色含义如下 green所有的主分片和副本分片都正常运行。 yellow所有的主分片都正常运行但不是所有的副本分片都正常运行。 red有主分片没能正常运行。
1.3、分片
一个 分片 是一个底层的 工作单元 它仅保存了全部数据中的一部分。我们的文档被存储和索引到分片内但是应用程序是直接与索引而不是与分片进行交互。分片就认为是一个数据区一个分片可以是 主 分片或者 副本 分片。索引内任意一个文档都归属于一个主分片所以主分片的数目决定着索引能够保存的最大数据量。在索引建立的时候就已经确定了主分片数但是副本分片数可以随时修改。让我们在包含一个空节点的集群内创建名为 blogs 的索引。 索引在默认情况下会被分配 5 个主分片 但是为了演示目的我们将分配 3 个主分片和一份副本每个主分片拥有一个副本分片 此时集群的健康状况为 yellow 则表示全部 主分片都正常运行集群可以正常服务所有请求但是 副本 分片没有全部处在正常状态。 实际上所有 3 个副本分片都是 unassigned —— 它们都没有被分配到任何节点。在同一个节点上既保存原始数据又保存副本是没有意义的因为一旦失去了那个节点我们也将丢失该节点上的所有副本数据。 当前我们的集群是正常运行的但是在硬件故障时有丢失数据的风险。
1.4、新增节点
当你在同一台机器上启动了第二个节点时只要它和第一个节点有同样的 cluster.name 配置它就会自动发现集群并加入到其中。 但是在不同机器上启动节点的时候为了加入到同一集群你需要配置一个可连接到的单播主机列表。 详细信息请查看最好使用单播代替组播 此时cluster-health 现在展示的状态为 green 这表示所有 6 个分片包括 3 个主分片和3 个副本分片都在正常运行。我们的集群现在不仅仅是正常运行的并且还处于 始终可用 的状态。
1.5、水平扩容-启动第三个节点 Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点现在每个节点上都拥有 2 个分片而不是之前的 3 个。 这表示每个节点的硬件资源CPU, RAM, I/O将被更少的分片所共享每个分片的性能将会得到提升。
在运行中的集群上是可以动态调整副本分片数目的我们可以按需伸缩集群。让我们把副本数从默认的 1 增加到 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依然拥有着之前的分片它将尝试去重用它们同时仅从主分片复制发生了修改的数据文件。
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 是允许一个节点既做候选主节点也做数据节点的但是数据节点的负载较重所以需要考虑将二者分离开设置专用的候选主节点和数据节点避免因数据节点负载重导致主节点不响应。
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、集群结构 以三台物理机为例。在这三台物理机上搭建了 6 个 ES 的节点三个 data 节点三个 master节点每台物理机分别起了一个 data 和一个 master3 个 master 节点目的是达到n/21 等于 2 的要求这样挂掉一台 master 后不考虑 datan 等于 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_count262144我们只是测试所以临时修改。永久修改使用下面 #防止 JVM 报错
echo vm.max_map_count262144 /etc/sysctl.conf
sysctl -p2.0、准备 docker 网络
Docker 创建容器时默认采用 bridge 网络自行分配 ip不允许自己指定。
在实际部署中我们需要指定容器 ip不允许其自行分配 ip尤其是搭建集群时固定 ip是必须的。
我们可以创建自己的 bridge 网络 mynet创建容器的时候指定网络为 mynet 并指定 ip即可。
查看网络模式
docker network ls创建一个新的 bridge 网络
docker network create --driver bridge --subnet192.168.0.0/16 --gateway192.168.0.1 mynet查看网络信息
docker network inspect mynet以后使用–networkmynet --ip 192.168.0.x 指定 ip
2.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/21
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: [192.168.0.21:9301, 192.168.0.22:9302, 192.168.0.23:9303] #设置集群中的 Master 节点的初始列表可以通过这些节点来自动发现其他新加入集群的节点es7的新增配置
cluster.initial_master_nodes: [192.168.0.21] #新集群初始时的候选主节点es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--networkmynet --ip 192.168.0.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
donedocker stop $(docker ps -a |grep elasticsearch-node-* | awk { print $1})docker rm $(docker ps -a |grep elasticsearch-node-* | awk { print $1})2.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.119.127 #互相通信 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/21
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: [192.168.0.21:9301, 192.168.0.22:9302, 192.168.0.23:9303] #设置集群中的 Master 节点的初始列表可以通过这些节点来自动发现其他新加入集群的节点es7的新增配置
cluster.initial_master_nodes: [192.168.0.21] #新集群初始时的候选主节点es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--networkmynet --ip 192.168.0.2${port} \
-e ES_JAVA_OPTS-Xms300m -Xmx300m \
-v /mydata/elasticsearch/node-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.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
done3、测试集群 http://192.168.0.21:9201/_nodes/process?pretty 查看节点状况 http://192.168.0.21:9201/_cluster/stats?pretty 查看集群状态 http://192.168.0.21.10:9201/_cluster/health?pretty 查看集群健康状况 http://192.168.0.21: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
3.1、创建配置 - elastic-search-conf 创建配置 名称elastic-search-conf 配置设置 http.host0.0.0.0 discovery.typesingle-node ES_JAVA_OPTS-Xms64m -Xmx512m 创建
3.2、创建存储卷 - gulimall-elasticsearch-pvc
创建一个名称为gulimall-elasticsearch-pvc的存储卷 下一步 3、创建
3.3、创建服务 - gulimall-elasticsearch 选择有状态服务 基本信息 名称gulimall-elasticsearch 容器镜像 因为就一个容器我们容器组选择容器组默认部署就好 添加容器镜像 这里我们使用的私有镜像仓库-Harbor创建容器,使用默认端口 挂载存储 这里挂载路径参考docker创建elasticsearch的路径 /usr/share/elasticsearch/data 下一步 创建
3.4、测试
以admin登录kubespere进入控制台 查看elasticsearch有json数据则安装成功。
/ # curl http://gulimall-elasticsearch.gulimall:9200
{name : gulimall-elasticsearch-z8eh94-0,cluster_name : docker-cluster,cluster_uuid : fc3Pm8DLTzCXSHGYXR8oTA,version : {number : 7.4.2,build_flavor : default,build_type : docker,build_hash : 2f90bbf7b93631e52bafb59b3b049cb44ec25e96,build_date : 2019-10-28T20:40:44.881551Z,build_snapshot : false,lucene_version : 8.2.0,minimum_wire_compatibility_version : 6.8.0,minimum_index_compatibility_version : 6.0.0-beta1},tagline : You Know, for Search
}3.5、创建服务 - gulimall-kibana 创建一个无状态服务 填写基础信息 名称gulimall-kibana 容器镜像 因为就一个容器我们容器组选择容器组默认部署就好 添加容器镜像 这里我们使用的私有镜像仓库-Harbor创建容器,使用默认端口 我们需要访问elasticsearch路径这里环境变量配置 ELASTICSEARCH_HOSTShttp://gulimall-elasticsearch.gulimall:9200 挂载存储 不需要挂载直接下一步 创建 配置外网访问这样我们可以在外网访问kabana 我们可以看到外网访问的端口为31275 浏览器访问http://192.168.119.130:31275
八、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.1、搭建集群
mkdir /mydata/rabbitmq
cd rabbitmq/
mkdir rabbitmq01 rabbitmq02 rabbitmq03docker run -d --hostname rabbitmq01 --name rabbitmq01 \
-v /mydata/rabbitmq/rabbitmq01:/var/lib/rabbitmq \
-p 15673:15672 \
-p 5673:5672 \
-e RABBITMQ_ERLANG_COOKIEatguigu rabbitmq:managementdocker run -d --hostname rabbitmq02 --name rabbitmq02 \
-v /mydata/rabbitmq/rabbitmq02:/var/lib/rabbitmq \
-p 15674:15672 \
-p 5674:5672 \
-e RABBITMQ_ERLANG_COOKIEatguigu \
--link rabbitmq01:rabbitmq01 rabbitmq:managementdocker run -d --hostname rabbitmq03 --name rabbitmq03 \
-v /mydata/rabbitmq/rabbitmq03:/var/lib/rabbitmq \
-p 15675:15672 \
-p 5675:5672 \
-e RABBITMQ_ERLANG_COOKIEatguigu \
--link rabbitmq01:rabbitmq01 \
--link rabbitmq02:rabbitmq02 rabbitmq:management--hostname 设置容器的主机名
RABBITMQ_ERLANG_COOKIE 节点认证作用部署集成时 需要同步该值1.2、节点加入集群
docker exec -it rabbitmq01 /bin/bashrabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit进入第二个节点
docker exec -it rabbitmq02 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbitrabbitmq01
rabbitmqctl start_app
exit进入第三个节点
docker exec -it rabbitmq03 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbitrabbitmq01
rabbitmqctl start_app
exit访问一个节点后台http://192.168.119.127:15675/ 可以看到集群搭建成功。 但是目前只是一个普通集群普通集群会出现单点故障的问题下面我们继续实现镜像集群。
1.3、实现镜像集群
docker exec -it rabbitmq01 bashrabbitmqctl set_policy -p / ha ^ {ha-mode:all,ha-sync-mode:automatic}rabbitmqctl set_policy -p / ha-all “^” ’{“ha-mode”:“all”}’ 策略模式 all 即复制到所有节点包含新增节点策略正则表达式为 “^” 表示所有匹配所有队列名称。“^hello”表示只匹配名为 hello 开始的队列 可以使用 rabbitmqctl list_policies -p /查看 vhost/下面的所有 policy在 cluster 中任意节点启用策略策略会自动同步到集群节点
[rootlocalhost rabbitmq]# docker exec -it rabbitmq01 bash
rootrabbitmq01:/# rabbitmqctl list_policies -p /2、集群测试
随便在 mq 上创建一个队列发送一个消息保证整个集群其他节点都有这个消息。如果master 宕机其他节点也能成为新的 master
在rabbitmq01创建一个队列看看其他的rabbitmq有没有队列 点击rabbitmq03,查看是否有队列
在rabbitmq01发送一个持久化消息看看其他rabbitmq有没有消息并手动确认消费再查看是否都消费掉 点击rabbitmq02查看队列是否有消息并手动确认消费掉 查看其他rabbitmq01、rabbitmq02、rabbitmq03是否都消费掉
3、k8s 上部署
3.1、创建存储卷 - gulimall-rabbitmq-pvc
创建一个名称为gulimall-rabbitmq-pvc的存储卷
3.2、创建服务 - gulimall-rabbitmq-management
创建一个有状态服务 填写基本信息 名称 gulimall-rabbitmq-management 容器镜像 挂载存储 挂载路径参考原先docker创建rabbitmq的路径/var/lib/rabbitmq 创建
九、其他集群搭建
1、k8s 部署 nacos
以前docker部署命令
docker run --env MODEstandalone --name nacos \
-v /mydata/nacos/conf:/home/nacos/conf -d -p 8848:8848 nacos/nacos-server:v2.1.11.1、创建存储卷 - gulimall-nacos-pvc 1.2、创建服务 - gulimall-nacos 选择一个有状态服务 填写基础信息 名称gulimall-nacos 容器镜像 因为单机部署所以选择容器组默认部署 添加容器镜像 镜像nacos/nacos-server:v2.1.1 注意内存至少1000M否则容易内存溢出服务创建失败 添加环境变量 MODEstandalone 挂载存储 挂载路径/home/nacos/data 创建
1.3、如何把已部署的有状态服务做成外网访问
1、通过nginx代理外网可以访问 2、删除服务重新创建无状态服务 我们使用第二种方式但是我们不是完全删除之删除服务像容器组不删除。
删除服务有状态负载集不删除 服务里没有了nacos 容器组还有nacos 创建指定工作负载的服务填写基本信息 指定工作负载 服务设置 创建 设置外网访问 可以看到对外暴露端口号30271 8、随便选则一个节点ip访问访问地址http://192.168.119.130:30271/nacos
1.4、创建服务 - gulimall-nacos-service
我们已经部署了一台允许外网访问的gulinall-nacos服务我们通过gulimall-sentinel服务的终端测试发现内部集群无法访问gulinall-nacos服务的DNSgulimall-nacos.gulimall。
因为我们后面搭建集群项目各个微服务需要用到nacos所以接下来我们需要创建一个集群内部通过服务的后端 Endpoint IP 直接访问服务。
选择指定工作负载创建服务 填写基本信息 名称gulimall-nacos-service 服务设置 创建 测试集群内部是否可以访问gulimall-nacos-service服务的DNSgulimall-nacos-service.gulimall 我们通过gulimall-sentinel服务的终端测试发现现在是正常访问的。
2、k8s 部署 zipkin
docker run -d -p 9411:9411 openzipkin/zipkin或者
docker run --env STORAGE_TYPEelasticsearch --env ES_HOSTS192.168.56.10:9200 openzipkin/zipkin2.1、创建服务 - gulimall-zipkin 选择无状态服务 填写基础信息 名称gulimall-zipkin别名链路追踪 容器镜像 选择容器组默认部署 添加容器镜像 镜像openzipkin/zipkin 环境变量 STORAGE_TYPEelasticsearchES_HOSTShttp://gulimall-elasticsearch.gulimall:9200 挂载存储 创建 外网访问端口号31610 随便找一个节点ip进行测试http://192.168.119.130:31610/zipkin/
3.2、创建服务 - gulimall-zipkin-service
我们已经部署了一台允许外网访问的gulimall-zipkin服务由此可知集群内部无法访问。因为我们后面搭建集群项目各个微服务需要用到zipkin所以接下来我们需要创建一个集群内部通过服务的后端 Endpoint IP 直接访问服务。 选择指定工作负载创建服务 填写基本信息 名称gulimall-sentimel-service 服务设置 创建 测试集群内部是否可以访问gulimall-zipkin-service服务的DNSgulimall-zipkin-service.gulimall
我们通过gulimall-sentinel服务的终端测试发现现在是正常访问的。
3、k8s 部署 sentinel
可以制作一个镜像并启动它暴露访问
docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard:1.6.33.1、创建服务 - gulimall-sentinel
选择无状态服务 填写基础信息 名称gulimall-sentinel别名熔断/降级服务 容器镜像 选择容器组默认部署 添加容器镜像 镜像bladex/sentinel-dashboard:1.6.3 挂载存储 创建 设置外网访问 6、外网可以访问的端口号30702随便选择一个节点ip进行测试http://192.168.119.130:30702/
3.2、创建服务 - gulimall-sentimel-service
我们已经部署了一台允许外网访问的gulimall-sentimel服务由此可知集群内部无法访问。因为我们后面搭建集群项目各个微服务需要用到sentimel所以接下来我们需要创建一个集群内部通过服务的后端 Endpoint IP 直接访问服务。 选择指定工作负载创建服务 填写基本信息 名称gulimall-sentimel-service 服务设置 创建 测试集群内部是否可以访问gulimall-sentimel-service服务的DNSgulimall-sentimel-service.gulimall
我们通过gulimall-sentinel服务的终端测试发现现在是正常访问的。