灯下哥谭 灯下哥谭
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

灯下哥谭

灯还亮着
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

    • MySQL 运维知识地图:从入门配置到高可用排障
    • MySQL8 配置文件 my.cnf 重要参数解读
    • MySQL 导出 CSV 中文乱码:字符集链路从头讲一遍
    • MySQL 角色管理
    • MySQL网络抓包审计
    • MySQL 性能压测:Sysbench 1.0 实战
    • MySQL Router 实现读写分离
    • Gh-ost重建表,清除表碎片率
    • MySQL MGR配合MySQL-router实现innodb-cluster
    • MySQL 快速分析binlog定位问题
    • MySQL执行计划分析
    • DBA常用SQL和命令整理备查
    • 单表数据同步方案选型:为什么不该用 mysqldump 做「实时同步」
    • MySQL的事务隔离级别
    • MySQL存储过程批量生成数据
    • MySQL insert on duplicate key update,replace into , insert ignore的理解
    • MySQL不同字符集之间的区别和选择
    • MySQL为什么有时候会选错索引
    • MySQL死锁问题
    • MySQL使用SQL语句查重去重
    • MySQLdump逻辑备份
    • MySQL 基于 GTID 主从复制:跳过异常事务的正确姿势
    • MySQL8快速克隆插件使用指南
    • MySQL8双1设置保障安全
    • MySQL锁
    • innodb cluster安装
    • OPTIMIZE TABLE 和 ANALYZE TABLE 的区别:用实测数据说话
    • MySQLReplicaSet 安装
      • 1. 部署环境及初始化
      • 安装mysql
      • 利用 MySQL Shell 构建 ReplicaSet
      • 部署MySQL Router,实现读写分离以及故障自动转移
        • 参数解释
      • 验证
      • 坑与边界
    • MySQL 的 Left join、Right join 和 Inner join 的区别
    • ORDER BY 配合 LIMIT 触发的索引选择陷阱
  • Redis

  • 高性能KV

  • TiDB

  • Elasticsearch

  • 数据管道

  • 其他数据库

  • 数据库
  • MySQL
灯下哥谭
2023-04-13
目录

MySQLReplicaSet 安装原创

# 1. 部署环境及初始化

为了简单起见,建议用yum方式标准化安装MySQL Shell、Router

  1. MySQL官方的yum源,需要先下载安装repo包,下载地址:
# EL7;EL8/EL9 请把 el7 换成对应版本,repo 包版本号也会随官方更新,先到 dev.mysql.com/downloads/repo/yum/ 确认
yum -y install https://dev.mysql.com/get/mysql80-community-release-el7-4.noarch.rpm
1
2
  1. 用yum安装MySQL相关的软件包了
 yum list|grep mysql-shell

yum install -y mysql-shell mysql-router
#也可以用rpm包安装
 wget https://downloads.mysql.com/archives/get/p/43/file/mysql-shell-8.0.34-1.el7.x86_64.rpm  
 wget https://downloads.mysql.com/archives/get/p/41/file/mysql-router-community-8.0.34-1.el7.x86_64.rpm

1
2
3
4
5
6
7
  1. 网络调整
# 放行集群内部互访(MySQL 端口 + Group Replication 通信端口)
for ip in 192.0.2.11 192.0.2.12 192.0.2.13; do
  sudo iptables -I INPUT -s ${ip}/32 -p tcp -m multiport --dports 3366,33660 -j ACCEPT
done
sudo service iptables save
1
2
3
4
5

为什么要单独放行 33660:Group Replication 走的是独立于 MySQL 端口的组通信端口(group_replication_local_address 指定,惯例是 MySQL 端口后加 0 或另取一段),只放行 3366 会导致节点能连上、但加入组时卡在 RECOVERING 一直不进 ONLINE——这是新搭集群最常见的一个卡点。

  1. CPU磁盘内存调整
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo 'echo never > /sys/kernel/mm/transparent_hugepage/defrag' >> /etc/rc.d/rc.local

cat /sys/block/sdb/queue/scheduler
echo noop >/sys/block/sdb/queue/scheduler

cpupower frequency-info --governors

cpupower frequency-set --governor performance

cpupower frequency-info --policy
1
2
3
4
5
6
7
8
9
10
11
  1. 如果用的是 GreatSQL 分支,它依赖 jemalloc,需要先装上(官方 MySQL 不需要这一步,可跳过)
yum -y install jemalloc jemalloc-devel

#检查
[root@db-01]# ldconfig
[root@db-01]# ldconfig -p | grep libjemalloc
1
2
3
4
5
  1. /etc/hosts绑定IP和主机名防止创建mgr时报错 192.0.2.11 mytest-dbtest01 192.0.2.12 mytest-dbtest02 192.0.2.13 mytest-dbtest03

# 安装mysql

  1. 步骤省略。
  2. 修改root密码
SET SQL_LOG_BIN=0;

alter user 'root'@'localhost' identified by '';

rename user 'root'@'localhost' to 'admin'@'localhost';

SET SQL_LOG_BIN=1;
1
2
3
4
5
6
7
  1. 避免使用root请创建mgr_admin用户
create user `dba_admin`@`192.0.2.%` identified by '';

GRANT ALL PRIVILEGES ON *.* TO `dba_admin`@`192.0.2.%` WITH GRANT OPTION;
-- 注:AdminAPI 的建集群操作确实需要很高的权限,官方也是这么建议的。
-- 但这个账号只应对集群内网段开放(上面的 192.0.2.%),且不要复用为业务账号。
1
2
3
4
5

# 利用 MySQL Shell 构建 ReplicaSet

⚠️ ReplicaSet 不是 MGR。 下面这套 AdminAPI 流程和 innodb cluster 安装 长得几乎一样,但底层完全不同:InnoDB Cluster 底下是 Group Replication(多数派协议,可自动故障转移),ReplicaSet 底下就是传统异步主从——它只是给主从复制套了一层统一的纳管接口,没有自动故障转移。主库挂了必须有人(或有脚本)去执行 forcePrimaryInstance。

选它的理由是简单、资源省、对网络要求低;代价是 RTO 取决于人/脚本的反应速度,且异步复制天然有丢数据的风险。要自动切换见 ReplicaSet 高可用配置。

  1. 登录第一台mysql
mysqlsh --uri dba_admin@192.0.2.11:3366
1
  1. 检查配置
dba.configureInstance();
dba.checkInstanceConfiguration('dba_admin@192.0.2.12:3366');
dba.checkInstanceConfiguration('dba_admin@192.0.2.13:3366');
1
2
3
  1. 创建集群
var rs = dba.createReplicaSet("My_replicaset")
1

如果失败或报错需要重来:

dba.dropMetadataSchema();
1

⚠️ 这条只能在「刚创建失败、还没有任何业务数据」的实例上用。它会删掉 mysql_innodb_cluster_metadata 元数据库——在一个已在运行的集群上执行,等于把集群拓扑信息整个抹掉,Router 会立刻失去路由目标,且无法通过 dba.getCluster() 恢复,只能重新 createCluster 并逐个 addInstance。误操作代价极高,执行前先确认 cluster.status() 里没有任何在服务的节点。

  1. 添加节点
rs.addInstance('dba_admin@192.0.2.12:3366');
1

选择默认克隆模式添加直接回车 重复以上操作添加所有节点

  1. 查看状态以下命令均可查看 首先定义var
var rs = dba.getReplicaSet()
1

然后执行

rs.status();
rs.status({extended:1});
1
2
  1. 手动切换主从
var rs = dba.getReplicaSet()
rs.setPrimaryInstance('192.0.2.12:3366') # 主库运行时,可执行。否则会有以下报错

rs.forcePrimaryInstance('192.0.2.12:3366') # 强制切主:仅在原主库确认已不可用时使用
1
2
3
4
ERROR: Unable to connect to the PRIMARY of the ReplicaSet Core_rs: MYSQLSH 51118: Could not open connection to '192.0.2.11:3366': Can't connect to MySQL server on '192.0.2.11:3366' (110)
1
  1. 移除节点

⚠️ forcePrimaryInstance 是有数据丢失风险的操作。ReplicaSet 是异步复制,被选中的从库可能还没收全原主库的 binlog,切过去就等于丢掉那部分事务。执行前如果原主库还能连上,一律先用 setPrimaryInstance(它会等待从库追平再切,无损);只有原主库彻底失联时才用 force。

切之前先看清楚各节点落后多少:

rs.status({extended:1});   // 看每个 SECONDARY 的 replicationLag
1

切完必须做的一件事:原主库恢复后不能直接开机接回。它上面很可能有没同步出去的事务,直接加回来会造成 GTID 分叉(ERROR 3546 或数据不一致)。正确做法是把它当成一个全新节点,用 clone 方式重新加入:

rs.rejoinInstance('192.0.2.11:3366');   // 若报 GTID 分叉,改用下面这条
rs.removeInstance('192.0.2.11:3366', {force:true});
rs.addInstance('dba_admin@192.0.2.11:3366', {recoveryMethod:'clone'});
1
2
3
 rs.removeInstance('192.0.2.11:3366') # 手动移除节点,节点已宕机的情况会报错
 ERROR: Unable to connect to the target instance 192.0.2.11:3366. Please make sure the instance is available and try again. If the instance is permanently not reachable, use the 'force' option to remove it from the replicaset metadata and skip reconfiguration of that instance.
1
2
rs.removeInstance('192.0.2.11:3366',{force:true}) # 强制移除宕机节点
NOTE: Unable to connect to the target instance 192.0.2.11:3366:3366. The instance will only be removed from the metadata, but its replication configuration cannot be updated. Please, take any necessary actions to make sure that the instance will not replicate from the replicaset if brought back online.

1
2
3

# 部署MySQL Router,实现读写分离以及故障自动转移

MySQL Router是一个轻量级的中间件,它采用多端口的方案实现读写分离以及读负载均衡,而且同时支持mysql和mysql x协议。

mysqlrouter初始化 MySQL Router对应的服务器端程序文件是 /usr/bin/mysqlrouter,第一次启动时要先进行初始化

# 参数解释

参数 --bootstrap 表示开始初始化

参数 dba_admin@192.0.2.11:3366 是MGR集群管理员账号

--user=mysqlrouter 是运行mysqlrouter进程的系统用户名
[root@db-01]# mysqlrouter --bootstrap dba_admin@192.0.2.11:3366 --user=mysqlrouter

Please enter MySQL password for dba_admin: <-- 输入密码
# 然后mysqlrouter开始自动进行初始化
# 它会自动读取MGR的元数据信息,自动生成配置文件
1
2
3
4
5

4.2 启动mysqlrouter服务 这就初始化完毕了,按照上面的提示,直接启动 mysqlrouter 服务即可:

[root@db-01]# systemctl start mysqlrouter


检查
ps -ef | grep -v grep | grep mysqlrouter

netstat -lntp | grep mysqlrouter
1
2
3
4
5
6
7

mysqlrouter 初始化时自动生成的配置文件是 /etc/mysqlrouter/mysqlrouter.conf,主要是关于R/W、RO不同端口的配置

[routing:myCluster_rw]
bind_address=0.0.0.0
bind_port=6446
destinations=metadata-cache://myCluster/?role=PRIMARY
routing_strategy=first-available
protocol=classic
1
2
3
4
5
6

可以根据需要自行修改绑定的IP地址和端口。

4.3 确认读写分离效果 现在,用客户端连接到6446(读写)端口,确认连接的是PRIMARY节点:

[root@db-01]# mysql -h192.0.2.11 -u dba_admin -p -P6446

mysql>select @@server_uuid;
1
2
3

4.4 关闭ssl避免跟客户端应用不兼容通讯协议

分别登录mysqlrouter 的服务器,更改配置

 sudo vim /etc/mysqlrouter/mysqlrouter.conf

client_ssl_mode=DISABLED
server_ssl_mode=DISABLED
server_ssl_verify=DISABLED
1
2
3
4
5

分别重启mysqlrouter

sudo systemctl restart mysqlrouter.service
1

4.5 从元数据库剔除mysqlrouter节点

var rs = dba.getReplicaSet()
rs.listRouters()

rs.removeRouterMetadata('192.0.2.11::system');
1
2
3
4

# 验证

var rs = dba.getReplicaSet();
rs.status({extended:1});
1
2

预期输出(关注 status、instanceRole 与 replicationLag):

{
    "replicaSet": {
        "name": "My_replicaset",
        "primary": "192.0.2.11:3366",
        "status": "AVAILABLE",
        "statusText": "All instances available.",
        "topology": [
            {"address": "192.0.2.11:3366", "instanceRole": "PRIMARY",   "status": "ONLINE"},
            {"address": "192.0.2.12:3366", "instanceRole": "SECONDARY", "status": "ONLINE",
             "replication": {"applierStatus": "APPLIED_ALL", "replicationLag": null}}
        ]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

replicationLag 为 null 且 applierStatus 是 APPLIED_ALL 表示已追平。出现秒数说明有延迟,切主前必须等它归零。

端到端确认读写分离生效:

mysql -h 192.0.2.11 -P6446 -u dba_admin -p -e "SELECT @@hostname, @@read_only;"   # 期望 read_only=0
mysql -h 192.0.2.11 -P6447 -u dba_admin -p -e "SELECT @@hostname, @@read_only;"   # 期望 read_only=1
1
2

# 坑与边界

  • ReplicaSet 没有自动故障转移,这是它与 InnoDB Cluster 的根本区别,也是选型时唯一真正要想清楚的一条。别因为部署流程相似就以为高可用能力也相似。
  • 异步复制会丢数据。主库提交后立刻宕机,未传出的 binlog 就丢了。对丢数据零容忍的场景应该上 InnoDB Cluster(多数派确认),或至少开半同步复制。
  • Router 的 6447 只读口在只有 2 个节点时没有冗余:唯一的 SECONDARY 挂掉后所有读流量会失败或全压到 PRIMARY 上,容量规划时要按「读流量最终全落到主库」来算。
  • removeInstance({force:true}) 只改元数据,不会去关停那个实例的复制。被强制移除的节点如果还活着,它会继续从原主库拉数据——必须手工上去 STOP REPLICA; RESET REPLICA ALL;,否则它会变成一个没人管、却还在同步的影子从库。
  • 所有节点的 server_id 必须唯一,且建议显式设置 report_host(用 IP 或可解析的主机名)。不设时 AdminAPI 会用系统 hostname,在 /etc/hosts 没配全的环境里会连不上。
#高可用#MySQL
上次更新: 9/11/2026

← OPTIMIZE TABLE 和 ANALYZE TABLE 的区别:用实测数据说话 MySQL 的 Left join、Right join 和 Inner join 的区别→

最近更新
01
DeepSeek Harness 实战 06|学习笔记:插件、工具、技能不在同一个维度上 原创
09-11
02
DeepSeek Harness 实战 05|让两个编码 Agent 共用一份长期记忆 原创
09-09
03
DeepSeek Harness 实战 04|学习笔记:从「已知限制」里读出三处设计张力 原创
09-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式