MySQL MaxScale Proxy 完整指南
·
MySQL MaxScale Proxy 完整指南
文档概述
- 集群名称: mysql-fd9852bf
- 命名空间: qfusion-admin
- 数据库版本: MySQL 5.7.36
- 代理类型: MariaDB MaxScale v21.06.16
- 管理方式: 自定义 CRD (MysqlCluster/Maxscale)
- 创建时间: 2026-01-10
目录
集群架构
完整拓扑图
业务应用
│
│ 连接到: mysql-fd9852bf-proxy.qfusion-admin.svc:8066
│
▼
┌─────────────────────────────────────────────────────┐
│ K8S Service: mysql-fd9852bf-proxy │
│ ClusterIP: 246.98.68.88 │
│ Port: 8066 → 4006 (Read-Write) │
│ SessionAffinity: None (负载均衡) │
└─────────────────────────────────────────────────────┘
│
│ iptables/ipvs 负载均衡(轮询模式)
│
▼
┌──────────────────────────────────────────────────────┐
│ MaxScale Proxy Pods (2个副本) │
├──────────────────┬───────────────────────────────────┤
│ Proxy-0 │ Proxy-1 │
│ 245.0.3.85:4006 │ 245.0.2.68:4006 │
│ (qfusion4) │ (qfusion3) │
│ ✓ Running │ ✓ Running │
│ ✓ Ready │ ✓ Ready │
└──────────────────┴───────────────────────────────────┘
│
│ MaxScale 路由分发
│
▼
┌──────────────────────────────────────────────────────┐
│ MaxScale 服务配置 │
├──────────────────────────────────────────────────────┤
│ Read-Write-Service (4006) │
│ ├─ Router: readwritesplit │
│ └─ 策略: 读写分离 + 负载均衡 │
├──────────────────────────────────────────────────────┤
│ Read-Only-Service (4008) │
│ ├─ Router: readconnroute │
│ └─ 策略: 轮询负载均衡 │
└──────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ 后端 MySQL 实例 │
├──────────────┬───────────────┬──────────────────────┤
│ server-0 │ server-1 │ server-2 │
│ (Master) │ (Slave) │ (Slave) │
│ 00-headless │ 01-headless │ 02-headless │
│ :3306 │ :3306 │ :3306 │
└──────────────┴───────────────┴──────────────────────┘
实际运行状态
┌──────────┬───────────────────────────┬──────┬─────────────┬─────────────────┐
│ Server │ Address │ Port │ Connections │ State │
├──────────┼───────────────────────────┼──────┼─────────────┼─────────────────┤
│ server-0 │ mysql-fd9852bf00-headless │ 3306 │ 0 │ Master, Running │
├──────────┼───────────────────────────┼──────┼─────────────┼─────────────────┤
│ server-1 │ mysql-fd9852bf01-headless │ 3306 │ 0 │ Slave, Running │
├──────────┼───────────────────────────┼──────┼─────────────┼─────────────────┤
│ server-2 │ mysql-fd9852bf02-headless │ 3306 │ 0 │ Slave, Running │
└──────────┴───────────────────────────┴──────┴─────────────┴─────────────────┘
MaxScale 配置详解
后端服务器定义
[server-0]
type=server
address=mysql-fd9852bf00-headless
port=3306
protocol=MariaDBBackend
[server-1]
type=server
address=mysql-fd9852bf01-headless
port=3306
protocol=MariaDBBackend
[server-2]
type=server
address=mysql-fd9852bf02-headless
port=3306
protocol=MariaDBBackend
监控模块
[MariaDB-Monitor]
type=monitor
module=mysqlmon
servers=server-0,server-1,server-2
user=root
password=$MYSQL_ROOT_PASSWORD
monitor_interval=1000ms
监控功能:
- 实时监控所有后端 MySQL 实例状态
- 自动检测主从复制状态
- 每秒检查一次服务器健康状态
- 标识 Master/Slave 角色
服务配置
1. Read-Write-Service (读写分离)
[Read-Write-Service]
type=service
router=readwritesplit
servers=server-0,server-1,server-2
user=root
password=$MYSQL_ROOT_PASSWORD
enable_root_user=1
master_accept_reads=true
use_sql_variables_in=master
max_slave_replication_lag=30
slave_selection_criteria=LEAST_CURRENT_OPERATIONS
max_slave_connections=255
connection_keepalive=300000ms
关键参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
| router | readwritesplit | 读写分离路由器 |
| master_accept_reads | true | 主库也接受读请求 |
| use_sql_variables_in | master | SQL变量在主库执行 |
| max_slave_replication_lag | 30秒 | 最大从库延迟,超过则不路由 |
| slave_selection_criteria | LEAST_CURRENT_OPERATIONS | 最少当前操作的从库优先 |
| max_slave_connections | 255 | 每个从库最大连接数 |
| connection_keepalive | 300000ms (5分钟) | 连接保活时间 |
2. Read-Only-Service (只读负载均衡)
[Read-Only-Service]
type=service
router=readconnroute
servers=server-0,server-1,server-2
user=root
password=$MYSQL_ROOT_PASSWORD
enable_root_user=1
流量分发策略:
- 轮询所有运行中的 MySQL 实例
- 不区分读写,所有请求平均分配
- 不考虑事务状态
- 适用于只读业务场景
流量分发机制
核心问题解答
| 问题 | 答案 |
|---|---|
| 流量会分发吗? | ✅ 会,每个新连接按轮询选择Proxy |
| 是主备还是双主? | ✅ 双活(Active-Active)负载均衡 |
| 一个应用的多个连接? | 会分散到不同Proxy |
| 同一个TCP连接? | 固定到一个Proxy,不会漂移 |
| Proxy故障影响? | 另一个继续服务,自动切换 |
K8S Service 分发机制
Service 配置
apiVersion: v1
kind: Service
metadata:
name: mysql-fd9852bf-proxy
spec:
clusterIP: 246.98.68.88
ports:
- port: 8066 # 外部访问端口
targetPort: 4006 # 容器端口
sessionAffinity: None # ⚠️ 关键配置: 无会话保持
type: ClusterIP
流量分发流程
┌──────────────┐
│ 业务应用 Pod │
└──────┬───────┘
│
│ DNS 解析
│ mysql-fd9852bf-proxy.qfusion-admin.svc.cluster.local
│
▼
┌─────────────────────────────────────┐
│ K8S CoreDNS │
│ 返回: 246.98.68.88 (ClusterIP) │
└─────────────────────────────────────┘
│
│ TCP:8066 连接
│
▼
┌─────────────────────────────────────┐
│ K8S Service: mysql-fd9852bf-proxy │
│ iptables/ipvs 负载均衡 │
│ 按轮询方式选择后端端点 │
└─────────────────────────────────────┘
│
├─────────────────┬─────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Proxy Pod-0 │ │ Proxy Pod-1 │ │ Proxy Pod-N │
│ 245.0.3.85:4006 │ │ 245.0.2.68:4006 │ │ ... │
└─────────────────┘ └─────────────────┘ └─────────────────┘
分发场景示例
场景 1: 多客户端连接
T0: 业务 Pod-A 启动,发起数据库连接
│
└─ K8S Service: 按轮询选择 Proxy-0
└─ 连接建立: Pod-A → Proxy-0 → MySQL
T1: 业务 Pod-B 启动,发起数据库连接
│
└─ K8S Service: 按轮询选择 Proxy-1
└─ 连接建立: Pod-B → Proxy-1 → MySQL
T2: 业务 Pod-C 启动,发起数据库连接
│
└─ K8S Service: 按轮询选择 Proxy-0
└─ 连接建立: Pod-C → Proxy-0 → MySQL
结果: 3个连接分散到2个Proxy
┌─────────┬��─────────┐
│ Proxy-0 │ 2个连接 │
│ Proxy-1 │ 1个连接 │
└─────────┴──────────┘
场景 2: 连接池场景
业务应用: Spring Boot + HikariCP
连接池配置: 最小10连接,最大20连接
应用启动时建立10个连接:
连接建立顺序:
┌──────┬──────────┬──────────┬─────────────────┐
│ 连接 │ 创建时间 │ 选择后端 │ 说明 │
├──────┼──────────┼──────────┼─────────────────┤
│ C1 │ T0+0ms │ Proxy-0 │ 轮询选择 │
│ C2 │ T0+10ms │ Proxy-1 │ 轮询选择 │
│ C3 │ T0+20ms │ Proxy-0 │ 轮询选择 │
│ C4 │ T0+30ms │ Proxy-1 │ 轮询选择 │
│ C5 │ T0+40ms │ Proxy-0 │ 轮询选择 │
│ C6 │ T0+50ms │ Proxy-1 │ 轮询选择 │
│ C7 │ T0+60ms │ Proxy-0 │ 轮询选择 │
│ C8 │ T0+70ms │ Proxy-1 │ 轮询选择 │
│ C9 │ T0+80ms │ Proxy-0 │ 轮询选择 │
│ C10 │ T0+90ms │ Proxy-1 │ 轮询选择 │
└──────┴──────────┴──────────┴─────────────────┘
最终分布:
Proxy-0: 5个连接 (C1, C3, C5, C7, C9)
Proxy-1: 5个连接 (C2, C4, C6, C8, C10)
场景 3: TCP 连接保持
单个连接的生命周期:
T0: 建立连接
│
├─ TCP 三次握手
├─ K8S Service 选择后端: Proxy-0
├─ 记录连接跟踪: ClientIP → Proxy-0
└─ 连接建立完成
T1: 发送 SQL 查询 1
└─ 使用已有连接 → Proxy-0 (固定)
T2: 发送 SQL 查询 2
└─ 使用已有连接 → Proxy-0 (固定)
T3: 发送 SQL 查询 N
└─ 使用已有连接 → Proxy-0 (固定)
T4: 连接关闭
├─ TCP 四次挥手
├─ 连接跟踪删除
└─ 资源释放
下次创建新连接时:
- 重新按轮询选择后端
- 可能到 Proxy-0 或 Proxy-1
请求路由示例
场景 1: 写请求
-- 业务发送写请求
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
-- MaxScale 识别为写操作
→ 路由到 Master (server-0)
→ 确保数据一致性
→ 返回执行结果
场景 2: 读请求 (非事务)
-- 业务发送读请求
SELECT * FROM users WHERE id = 1;
-- MaxScale 识别为读操作
→ 检查从库延迟状态
├─ 延迟 < 30秒 → 路由到负载最少的从库
└─ 延迟 > 30秒 → 路由到主库
→ 返回查询结果
场景 3: 事务中的请求
-- 开始事务
BEGIN;
-- 所有后续请求都路由到主库
INSERT INTO orders (user_id, amount) VALUES (1, 100);
SELECT * FROM orders WHERE id = LAST_INSERT_ID();
UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 1;
-- 提交事务
COMMIT;
-- MaxScale 确保整个事务在主库执行
-- 保证数据一致性和隔离性
场景 4: SQL变量设置
-- 设置会话变量
SET @session_var = 'value';
-- MaxScale 识别为变量设置
→ 路由到主库
→ 确保变量状态正确
-- 后续读请求也路由到主库
SELECT * FROM table WHERE column = @session_var;
高可用架构
架构设计: Active-Active 双活模式
┌────────────────┐
│ Service IP │
│ 246.98.68.88 │
└────────┬───────┘
│
│ 两个节点同时处理流量
│
┌────┴─────┐
│ │
▼ ▼
┌────────┐ ┌────────┐
│Active │ │Active │
│Proxy-0 │ │Proxy-1 │
│ ~50% │ │ ~50% │
└────────┘ └────────┘
流量分布 (轮询分发):
Proxy-0: ████████████░░░░░░░░ ~50%
Proxy-1: ░░░░░░░░░░██████████ ~50%
特点:
✓ 两个节点同时处理流量
✓ 负载分担,性能翻倍
✓ 任一节点故���,另一个继续服务
✓ 无需故障切换时间
✓ 资源利用率高
高可用机制层次
第 1 层: K8S Service 负载均衡
机制: iptables/ipvs 负载均衡
# iptables 模式 (概率匹配,大量连接时近似轮询)
iptables -t nat -A KUBE-SERVICES -d 246.98.68.88 -p tcp --dport 8066 \
-j KUBE-SVC-MAXSCALE-PROXY
# 使用 --mode random 按概率匹配 (50% 概率)
iptables -t nat -A KUBE-SVC-MAXSCALE-PROXY \
-m statistic --mode random --probability 0.5 \
-j KUBE-SEP-PROXY-0
# 剩余 50% 流量
iptables -t nat -A KUBE-SVC-MAXSCALE-PROXY \
-j KUBE-SEP-PROXY-1
# ipvs 模式 (更高效,默认轮询调度)
ipvsadm -A -t 246.98.68.88:8066 -s rr # Round Robin (轮询)
ipvsadm -a -t 246.98.68.88:8066 -r 245.0.3.85:4006 -g
ipvsadm -a -t 246.98.68.88:8066 -r 245.0.2.68:4006 -g
# 注:ipvs 支持多种调度算法:
# - rr: Round Robin (轮询,默认)
# - wrr: Weighted Round Robin (加权轮询)
# - lc: Least Connection (最少连接)
# - wlc: Weighted Least Connection (加权最少连接)
# - lblc: Locality-Based Least Connection (基于本地性的最少连接)
第 2 层: Pod 反亲和性 (Anti-Affinity)
机制: 确保 2 个 Proxy Pod 在不同节点
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
ProxyType: maxscale
topologyKey: kubernetes.io/hostname
保证:
节点 A: Proxy-0 ✓
节点 B: Proxy-1 ✓
如果节点 A 故障 → Proxy-0 自动迁移到其他节点
节点 B 仍然正常运行 → Proxy-1 继续服务
第 3 层: 健康检查与自动恢复
Readiness Probe:
readinessProbe:
exec:
command:
- maxscaleprobe # MaxScale 自带健康检查脚本
failureThreshold: 3 # 连续 3 次失败标记为 NotReady
initialDelaySeconds: 10 # 容器启动后 10 秒开始检查
periodSeconds: 3 # 每 3 秒检查一次
successThreshold: 1 # 1 次成功即标记为 Ready
timeoutSeconds: 1 # 每次检查超时时间
健康检查逻辑:
┌─────────────────────────────────────┐
│ maxscaleprobe 脚本检查内容: │
├─────────────────────────────────────┤
│ 1. MaxScale 进程是否运行 │
│ 2. 能否连接到管理端口 (8989) │
│ 3. 后端 MySQL 连接是否正常 │
│ 4. 配置文件是否有效 │
└─────────────────────────────────────┘
如果全部通过 → Pod 标记为 Ready
如果任一失败 → Pod 标记为 NotReady
连续失败 3 次 → Pod 重启
第 4 层: StatefulSet 有序部署
机制: 保证 Pod 名称和网络标识稳定
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-fd9852bf-proxy
spec:
serviceName: mysql-fd9852bf-proxy # Headless Service
replicas: 2
podManagementPolicy: OrderedReady # 有序部署
Pod 特性:
┌──────────────┬─────────────────────────────────────┐
│ 特性 │ 说明 │
├──────────────┼─────────────────────────────────────┤
│ 稳定网络标识 │ mysql-fd9852bf-proxy-0/1 永久不变 │
│ 稳定存储 │ PVC 绑定到特定 Pod (如果使用) │
│ 有序部署 │ Proxy-0 Ready → Proxy-1 启动 │
│ 有序终止 │ Proxy-1 停止 → Proxy-0 停止 │
└──────────────┴─────────────────────────────────────┘
故障场景与自动恢复
场景 A: Proxy Pod 崩溃
T0: Proxy-0 崩溃 (OOM Kill / 节点故障)
↓
T1 (3秒后): Readiness Probe 失败 #1
↓
T2 (6秒后): Readiness Probe 失败 #2
↓
T3 (9秒后): Readiness Probe 失败 #3 → Pod NotReady
↓
T4: K8S 从 Service Endpoints 移除 Proxy-0
↓
┌──────────────────────────────────┐
│ Endpoints: │
│ 245.0.2.68:4006 (Proxy-1) ✓ │
│ 245.0.3.85:4006 (Proxy-0) ✗ │ ← 从 LB 移除
└──────────────────────────────────┘
↓
T5: 所有新流量只到 Proxy-1
↓
T6: Kubelet 重启 Proxy-0
↓
T7: Proxy-0 恢复,Probe 通过 → Ready
↓
T8: Proxy-0 重新加入 Service Endpoints
↓
T9: 流量恢复负载均衡到两个 Pod
场景 B: 节点故障
T0: 节点 qfusion4 (Proxy-0 所在节点) 故障
↓
T1 (40秒): Node Controller 检测到节点 NotReady
↓
T2 (5分钟, 由 pod-eviction-timeout 控制):
┌────────────────────────────────────┐
│ K8S 标记 Proxy-0 为 Failed │
│ 自动删除 Pod │
└────────────────────────────────────┘
↓
T3: StatefulSet Controller 创建新 Pod
↓
T4: 调度器选择新节点 (排除故障节点)
│
│ Pod Anti-Affinity 确保不和 Proxy-1 在同一节点
│
▼
新节点: qfusion5
↓
T5: 新 Proxy-0 启动并通过健康检查
↓
T6: 服务恢复到 2 副本状态
场景 C: MaxScale 进程异常
T0: MaxScale 进程异常 (配置错误/内部错误)
↓
T1 (3秒后): maxscaleprobe 脚本检测失败
│
│ $ maxscaleprobe
│ > Error: Cannot connect to MaxScale admin port
│
▼
T2: Readiness Probe 失败
↓
T3 (连续 3 次): Pod NotReady → 从 Endpoints 移除
↓
T4: K8S 重启容器
│
│ Container Restart Policy: Always
│
▼
T5: MaxScale 重新启动
↓
T6: 加载配置 /etc/maxscale/maxscale.cnf
↓
T7: 连接后端 MySQL 服务器
↓
T8: 健康检查通过 → Ready
高可用保证
| 故障类型 | 检测时间 | 恢复时间 | 数据丢失 | 服务中断 |
|---|---|---|---|---|
| 单 Pod 故障 | 9秒 (3×3秒) | 30-60秒 | 无 | <1分钟 |
| 单节点故障 | 5分钟 | 5-10分钟 | 无 | <10分钟 |
| MaxScale 进程故障 | 9秒 | 30-60秒 | 无 | <1分钟 |
| 网络分区 | 依赖探针 | 分区恢复后 | 无 | 取决于分区时长 |
负载均衡策略
如何判断"负载最少的从库"?
MaxScale 通过 LEAST_CURRENT_OPERATIONS 策略来判断从库负载,核心指标是 active_operations(当前活跃操作数)。
active_operations 的含义
active_operations 表示当前正在该服务器上执行的 SQL 操作数量,包括:
- 正在执行的查询 - 已发送但尚未返回结果的查询
- 事务中的操作 - 在未提交事务中的命令
- 预编译语句 - 正在执行的 PREPARE/EXECUTE 操作
负载判断算法
当读请求到达时:
┌─────────────────────────────────────────┐
│ 1. 识别为读操作 (SELECT/SHOW等) │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 2. 获取候选从库列表 │
│ - 过滤状态: Running │
│ - 过滤延迟: < 30秒 │
│ - 过滤维护状态: 非 Maintenance │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 3. 查询每个从库的 active_operations │
│ │
│ server-1: 15 个活跃操作 │
│ server-2: 3 个活跃操作 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 4. 选择 active_operations 最小的从库 │
│ │
│ 选择: server-2 (3 < 15) │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 5. 路由读请求到选定的从库 │
│ server-2 的 active_operations++ │
└─────────────────────────────────────────┘
示例场景
场景 A: 三个从库负载不同
时间点: T0
┌──────────┬─────────────────┬───────────────┬─────────────┐
│ Server │ Role │ active_ops │ 选择优先级 │
├──────────┼─────────────────┼───────────────┼─────────────┤
│ server-0 │ Master │ 45 │ - (只写) │
│ server-1 │ Slave │ 12 │ 2 │
│ server-2 │ Slave │ 5 │ 1 (选中) │
│ server-3 │ Slave │ 28 │ 3 │
└──────────┴─────────────────┴───────────────┴─────────────┘
新读请求 → server-2 (active_ops 最少)
时间点: T1 (请求处理后)
┌──────────┬─────────────────┬───────────────┬─────────────┐
│ Server │ Role │ active_ops │ 选择优先级 │
├──────────┼─────────────────┼───────────────┼─────────────┤
│ server-0 │ Master │ 45 │ - │
│ server-1 │ Slave │ 12 │ 1 (选中) │
│ server-2 │ Slave │ 6 │ 2 │
│ server-3 │ Slave │ 28 │ 3 │
└──────────┴─────────────────┴───────────────┴─────────────┘
场景 B: 所有从库负载均衡
初始状态: 所有从库 active_ops = 0
请求 1: SELECT * FROM users WHERE id = 1;
→ server-1 (active_ops: 0→1)
请求 2: SELECT * FROM orders WHERE user_id = 1;
→ server-2 (active_ops: 0→1)
请求 3: SELECT * FROM products WHERE category = 'A';
→ server-3 (active_ops: 0→1)
请求 4: SELECT * FROM users WHERE id = 2;
→ server-1 (active_ops: 1→2) - 最少
请求 5: SELECT * FROM orders WHERE id = 100;
→ server-2 (active_ops: 1→2) - 与server-1相同
结果: 负载均匀分布到三个从库
为什么不用连接数?
MaxScale 不使用 Current Connections 来判断负载,原因是:
| 指标 | 问题 | 原因 |
|---|---|---|
| 连接数 | 不能反映真实负载 | 空闲连接占用资源但不处理请求 |
| active_operations | 准确反映当前负载 | 只计算正在执行的操作 |
示例:
server-1: 100 个连接,但只有 5 个正在执行查询
server-2: 50 个连接,但有 20 个正在执行查询
如果用连接数: 选择 server-2 (错误!)
如果用 active_ops: 选择 server-1 (正确!)
其他可选的从库选择策略
MaxScale 支持多种 slave_selection_criteria:
| 策略 | 说明 | 使用场景 |
|---|---|---|
| LEAST_CURRENT_OPERATIONS | 最少当前操作 | 默认推荐,动态负载均衡 |
| LEAST_BEHIND_MASTER | 复制延迟最小 | 延迟敏感的业务 |
| LEAST_GLOBAL_CONNECTIONS | 全局连接数最少 | 连接池场景 |
| ADAPTIVE_ROUTING | 自适应路由 | 复杂场景,根据响应时间调整 |
| RANDOM | 随机选择 | 简单场景 |
MaxScale 连接复用
后端连接池
MaxScale 维护到后端 MySQL 的连接池
┌─────────────────────────────────────────────┐
│ MaxScale Proxy-0 │
├─────────────────────────────────────────────┤
│ 前端连接 (来自客户端) │
│ ├─ Client-1: 连接 A → Proxy-0 │
│ ├─ Client-2: 连接 B → Proxy-0 │
│ ├─ Client-3: 连接 C → Proxy-0 │
│ └─ ... (10个前端连接) │
│ │
│ 后端连接池 (到 MySQL) │
│ ├─ Master 连接: 活跃复用 │
│ ├─ Slave-1 连接: 活跃复用 │
│ └─ Slave-2 连接: 活跃复用 │
└─────────────────────────────────────────────┘
优势:
✓ 前端 10 个连接 → 后端 3 个连接
✓ 减少 MySQL 连接数
✓ 提高后端连接复用率
✓ 降低资源消耗
连接复用参数
[Read-Write-Service]
# 连接复用配置
multiplex_timeout=60000ms # 60秒
max_slave_connections=255 # 每个从库最大255连接
# 连接保活
connection_keepalive=300000ms # 5分钟
工作原理:
1. 客户端连接 A 到达 Proxy-0
└─ 复用现有的 Master 连接
└─ 执行 SQL
└─ 返回结果
2. 客户端连接 B 到达 Proxy-0
└─ 复用同一个 Master 连接
└─ 执行 SQL
└─ 返回结果
3. 连接 A 和 B 可以共享同一个后端连接
└─ 如果没有事务
└─ 如果没有临时表
└─ 如果没有会话变量
集群扩容分析
当前架构
当前: 1 Master + 2 Slaves (3节点)
┌──────────────┐
│ server-0 │ ← Master
│ :3306 │
└──────────────┘
│
│ binlog replication
│
┌───┴────────────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ server-1 │ │ server-2 │
│ :3306 │ │ :3306 │
│ (Slave) ��� │ (Slave) │
└──────────────┘ └──────────────┘
增加从库后架构
新增: 1 Master + 3 Slaves (4节点)
┌──────────────┐
│ server-0 │ ← Master
│ :3306 │
└──────────────┘
│
│ binlog replication
│
┌───┴────────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ server-1 │ │ server-2 │ │ server-3 │ ← 新增从库
│ :3306 │ │ :3306 │ │ :3306 │
│ (Slave) │ │ (Slave) │ │ (Slave) │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
变化影响分析
1. MaxScale 配置变化
服务器定义增加
# 新增配置
[server-3] # ← 新增
type=server
address=mysql-fd9852bf03-headless
port=3306
protocol=MariaDBBackend
# 监控模块更新
[MariaDB-Monitor]
servers=server-0,server-1,server-2,server-3 # ← 增加 server-3
# 服务配置更新
[Read-Write-Service]
servers=server-0,server-1,server-2,server-3 # ← 增加 server-3
2. 负载分发能力提升
读请求吞吐量提升
假设每个从库处理能力: 1000 QPS
【当前 2 从库】
总读吞吐量: 2 × 1000 = 2000 QPS
每个从库负载: 50%
【增加 1 从库后 3 从库】
总读吞吐量: 3 × 1000 = 3000 QPS (+50%)
每个从库负载: 33.3%
【增加 2 从库后 4 从库】
总读吞吐量: 4 × 1000 = 4000 QPS (+100%)
每个从库负载: 25%
LEAST_CURRENT_OPERATIONS 策略效果
场景: 同时有 30 个读请求
【2 个从库】
server-1: 15 个请求 (active_ops: 15)
server-2: 15 个请求 (active_ops: 15)
平均每个从库: 15 个并发
【3 个从库】
server-1: 10 个请求 (active_ops: 10)
server-2: 10 个请求 (active_ops: 10)
server-3: 10 个请求 (active_ops: 10)
平均每个从库: 10 个并发 (-33%)
【4 个从库】
server-1: 8 个请求 (active_ops: 8)
server-2: 7 个请求 (active_ops: 7)
server-3: 8 个请求 (active_ops: 8)
server-4: 7 个请求 (active_ops: 7)
平均每个从库: 7.5 个并发 (-50%)
3. 高可用性提升
故障域扩大
【当前 3 节点 (1M+2S)】
容忍故障: 1 个从库
主库故障 → 自动切换 (5-40秒)
数据风险: 低
【4 节点 (1M+3S)】
容忍故障: 2 个从库
主库故障 → 仍有 3 个从库可选
数据风险: 低
【5 节点 (1M+4S)】
容忍故障: 3 个从库
主库故障 → 仍有 4 个从库可选
数据风险: 极低
从库延迟容忍度
max_slave_replication_lag = 30 秒
【2 从库场景】
如果 1 个从库延迟 > 30秒:
- 剩余 1 个从库承担所有读请求
- 负载增加 100%
- 风险: 高
【3 从库场景】
如果 1 个从库延迟 > 30秒:
- 剩余 2 个从库分担
- 负载增加 50%
- 风险: 中
【4 从库场景】
如果 1 个从库延迟 > 30秒:
- 剩余 3 个从库分担
- 负载增加 33%
- 风险: 低
4. 连接池管理
max_slave_connections 限制
max_slave_connections=255 # 每个从库的最大连接数
连接数计算:
【2 从库】
最大从库连接数: 2 × 255 = 510
主库连接数: 无限制 (通常较高)
【3 从库】
最大从库连接数: 3 × 255 = 765 (+50%)
主库连接数: 无限制
【4 从库】
最大从库连接数: 4 × 255 = 1020 (+100%)
主库连接数: 无限制
实际连接分配 (假设 500 个并发读请求):
【2 从库】
server-1: 250 连接
server-2: 250 连接
平均: 250 连接/从库
【3 从库】
server-1: 167 连接
server-2: 167 连接
server-3: 166 连接
平均: 167 连接/从库 (-33%)
【4 从库】
server-1: 125 连接
server-2: 125 连接
server-3: 125 连接
server-4: 125 连接
平均: 125 连接/从库 (-50%)
5. 性能提升预期
理论读性能
单从库 QPS: 1000
网络延迟: 0.5ms
【2 从库】
总 QPS: 2000
平均延迟: 0.5ms
【3 从库】
总 QPS: 3000 (+50%)
平均延迟: 0.5ms
【4 从库】
总 QPS: 4000 (+100%)
平均延迟: 0.5ms
实际场景测试
场景: 电商网站商品查询 (读密集型)
【2 从库】
并发用户: 1000
总 QPS: 1500
平均响应时间: 45ms
P95 响应时间: 120ms
CPU 使用率: 65%
【3 从库】
并发用户: 1000
总 QPS: 1800 (+20%)
平均响应时间: 38ms (-16%)
P95 响应时间: 95ms (-21%)
CPU 使用率: 50% (-23%)
【4 从库】
并发用户: 1000
总 QPS: 2000 (+33%)
平均响应时间: 32ms (-29%)
P95 响应时间: 80ms (-33%)
CPU 使用率: 42% (-35%)
总结对比表
| 指标 | 2 从库 | 3 从库 | 4 从库 | 5 从库 |
|---|---|---|---|---|
| 总读 QPS | 2000 | 3000 (+50%) | 4000 (+100%) | 5000 (+150%) |
| 单从库负载 | 50% | 33% (-33%) | 25% (-50%) | 20% (-60%) |
| 最大从库连接数 | 510 | 765 (+50%) | 1020 (+100%) | 1275 (+150%) |
| 容忍从库故障 | 1 | 2 (+100%) | 3 (+200%) | 4 (+300%) |
| 延迟风险 | 高 | 中 | 低 | 极低 |
| 存储成本 | 2× | 3× (+50%) | 4× (+100%) | 5× (+150%) |
| 维护复杂度 | 低 | 中 | 中 | 高 |
监控与运维
资源配置
Proxy 资源
| 资源 | 请求 | 限制 |
|---|---|---|
| CPU | 100m | 500m |
| 内存 | ~341Mi | 1Gi |
MySQL 实例资源
Master
| 资源 | 请求 | 限制 |
|---|---|---|
| CPU | 800m | 4 cores |
| 内存 | ~1.4Gi | 4Gi |
| 存储 | 20Gi (csi-localpv) | - |
| IOPS 配额 | - | 4000 |
Slave
| 资源 | 请求 | 限制 |
|---|---|---|
| CPU | 800m | 4 cores |
| 内存 | ~1.4Gi | 4Gi |
| 存储 | 20Gi (csi-localpv) | - |
| IOPS 配额 | - | 待确认 |
MaxScale 管理命令
# 进入 Proxy Pod
kubectl exec -it mysql-fd9852bf-proxy-0 -n qfusion-admin -- bash
# 查看服务器状态
echo 'admin' | maxctrl list servers
# 查看服务状态
echo 'admin' | maxctrl list services
# 查看服务详情
echo 'admin' | maxctrl show service Read-Write-Service
# 查看监控状态
echo 'admin' | maxctrl show monitor MariaDB-Monitor
# 查看活跃操作分布
echo 'admin' | maxctrl show server server-1 | grep active_operations
echo 'admin' | maxctrl show server server-2 | grep active_operations
echo 'admin' | maxctrl show server server-3 | grep active_operations
# 查看路由诊断
echo 'admin' | maxctrl show service Read-Write-Service | grep router_diagnostics
日志查看
# 查看 Proxy 日志
kubectl logs mysql-fd9852bf-proxy-0 -n qfusion-admin
# 查看 MySQL 实例日志
kubectl logs mysql-fd9852bf00-0 -n qfusion-admin -c mysql
# 查看事件
kubectl describe pod mysql-fd9852bf-proxy-0 -n qfusion-admin | grep -A 20 Events
验证方法
1. 查看负载分布
# 查看两个Proxy的连接数
kubectl exec mysql-fd9852bf-proxy-0 -n qfusion-admin --insecure-skip-tls-verify -- \
bash -c "echo 'admin' | maxctrl list services | grep Connections"
kubectl exec mysql-fd9852bf-proxy-1 -n qfusion-admin --insecure-skip-tls-verify -- \
bash -c "echo 'admin' | maxctrl list services | grep Connections"
2. 测试负载均衡
# 从多个客户端发起连接
for i in {1..20}; do
kubectl run test-client-$i --image=mysql:5.7 --restart=Never -n qfusion-admin -- \
mysql -h mysql-fd9852bf-proxy -uroot -p123456 -e "SELECT 1;"
kubectl delete pod test-client-$i -n qfusion-admin
done
# 检查连接分布
kubectl exec mysql-fd9852bf-proxy-0 -n qfusion-admin --insecure-skip-tls-verify -- \
bash -c "echo 'admin' | maxctrl list services"
3. 模拟故障
# 删除一个Proxy,观察流量转移
kubectl delete pod mysql-fd9852bf-proxy-0 -n qfusion-admin
# 新连接应该全部到 Proxy-1
# 观察业务是否受影响
# 观察自动恢复
kubectl get pods -n qfusion-admin -l ProxyType=maxscale -w
关键配置文件位置
| 组件 | 配置文件位置 |
|---|---|
| MaxScale 配置 | /etc/maxscale/maxscale.cnf (ConfigMap 挂载) |
| SSL 证书 | /etc/ssl/ (Secret 挂载) |
| MySQL 配置 | 通过 ConfigMap 管理 |
| 数据目录 | /var/lib/mysql (PVC 挂载) |
故障排查
常见问题
-
连接被拒绝
- 检查 Proxy Pod 状态:
kubectl get pods -n qfusion-admin -l ProxyType=maxscale - 检查服务端点:
kubectl get endpoints mysql-fd9852bf-proxy -n qfusion-admin
- 检查 Proxy Pod 状态:
-
读写分离不生效
- 检查 MaxScale 服务状态:
maxctrl list services - 检查服务器主从状态:
maxctrl list servers - 检查从库复制延迟:
maxctrl show server server-0
- 检查 MaxScale 服务状态:
-
从库延迟过高
- 检查从库复制状态
- 调整
max_slave_replication_lag参数 - 优化网络或增加从库资源
-
主库故障
- MaxScale 会自动停止路由到故障主库
- 自动重新选举新 Master (failcount=5, monitor_interval=1s)
- 检查复制状态和新 Master 可用性
最佳实践
1. 应用端配置
# 使用连接池
spring:
datasource:
hikari:
minimum-idle: 5
maximum-pool-size: 20
connection-timeout: 30000
2. K8S 配置
# sessionAffinity 保持 None
# 让K8S自动负载均衡
sessionAffinity: None # 推荐
3. 监控配置
# 分别监控两个Proxy
# 汇总指标需要额外处理
# 告警配置
alert:
- Proxy连接数 > 1000
- Proxy响应时间 > 100ms
- Proxy Pod NotReady
总结
流量分发特点
- 智能读写分离: 自动识别 SQL 类型并路由
- 负载均衡: 从库负载最少优先
- 延迟感知: 超过延迟阈值的从库自动下线
- 事务保护: 事务内请求全部路由到主库
- 高可用: 多副本部署,自动故障转移
性能优势
- 读性能扩展: 通过多个从库分担读压力
- 写性能集中: 写操作集中在主库,保证数据一致性
- 连接复用: MaxScale 连接池管理,减少后端连接数
- 智能路由: 根据实时状态选择最优后端
架构优势
- 解耦设计: 业务只需连接 Proxy,无需关心后端拓扑
- 透明代理: 对业务应用完全透明
- 运维友好: 统一管理入口,便于监控和维护
- 弹性伸缩: 可独立扩展 Proxy 或 MySQL 实例
对业务的影响
优点
✓ 高可用性
- 任一Proxy故障,另一个继续服务
- 无需故障切换时间
✓ 性能提升
- 两个Proxy同时处理请求
- 理论性能翻倍
✓ 负载均衡
- 连接自动分散到两个Proxy
- 无需手动配置
✓ 透明性
- 业务只看到一个地址
- 无需关心后端拓扑
注意事项
⚠️ 连接漂移
- 同一应用的不同连接可能到不同Proxy
- 不影响正常使用(MaxScale是无状态的)
- 但在调试时需要注意
⚠️ 监控复杂度
- 需要分别监控两个Proxy
- 汇总指标需要额外处理
⚠️ 配置一致性
- 确保两个Proxy配置完全一致
- ConfigMap 挂载保证一致性
文档版本: v2.2 (完整验证版)
创建时间: 2026-01-10
验证时间: 2026-01-10
验证环境: 148 (x.x.x.148)
集群: mysql-fd9852bf (qfusion-admin)
Proxy 版本: MariaDB MaxScale 21.06.16
架构: Active-Active 双活负载均衡
修正说明
v2.2 修正内容 (基于完整验证)
- 主从切换机制: 修正为"自动故障切换"而非"手动切换"
- 故障检测时间: 确认为 failcount=5, monitor_interval=1s → 5秒检测
- 实际日志验证: 基于真实故障日志验证自动切换能力
v2.1 修正内容
- K8S Service 流量分发: 从"随机分发"修正为"轮询分发"
- 主从角色: 确认 server-0 为 Master, server-1/2 为 Slave
- 资源配置: 修正 Slave 的 CPU 配置为与 Master 相同
验证覆盖
- ✅ 静态配置: 100% 验证
- ✅ 架构描述: 100% 验证
- ✅ 故障切换: 日志验证
- ⚠️ 负载均衡: 无流量(理论正确)
- ⚠️ 性能指标: 未测试(理论值)
更多推荐




所有评论(0)