目录标题

MySQL MaxScale Proxy 完整指南

文档概述

  • 集群名称: mysql-fd9852bf
  • 命名空间: qfusion-admin
  • 数据库版本: MySQL 5.7.36
  • 代理类型: MariaDB MaxScale v21.06.16
  • 管理方式: 自定义 CRD (MysqlCluster/Maxscale)
  • 创建时间: 2026-01-10

目录

  1. 集群架构
  2. MaxScale 配置详解
  3. 流量分发机制
  4. 高可用架构
  5. 负载均衡策略
  6. 集群扩容分析
  7. 监控与运维

集群架构

完整拓扑图

业务应用
    │
    │ 连接到: 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 操作数量,包括:

  1. 正在执行的查询 - 已发送但尚未返回结果的查询
  2. 事务中的操作 - 在未提交事务中的命令
  3. 预编译语句 - 正在执行的 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%)
延迟风险 极低
存储成本 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 挂载)

故障排查

常见问题
  1. 连接被拒绝

    • 检查 Proxy Pod 状态: kubectl get pods -n qfusion-admin -l ProxyType=maxscale
    • 检查服务端点: kubectl get endpoints mysql-fd9852bf-proxy -n qfusion-admin
  2. 读写分离不生效

    • 检查 MaxScale 服务状态: maxctrl list services
    • 检查服务器主从状态: maxctrl list servers
    • 检查从库复制延迟: maxctrl show server server-0
  3. 从库延迟过高

    • 检查从库复制状态
    • 调整 max_slave_replication_lag 参数
    • 优化网络或增加从库资源
  4. 主库故障

    • 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

总结

流量分发特点

  1. 智能读写分离: 自动识别 SQL 类型并路由
  2. 负载均衡: 从库负载最少优先
  3. 延迟感知: 超过延迟阈值的从库自动下线
  4. 事务保护: 事务内请求全部路由到主库
  5. 高可用: 多副本部署,自动故障转移

性能优势

  1. 读性能扩展: 通过多个从库分担读压力
  2. 写性能集中: 写操作集中在主库,保证数据一致性
  3. 连接复用: MaxScale 连接池管理,减少后端连接数
  4. 智能路由: 根据实时状态选择最优后端

架构优势

  1. 解耦设计: 业务只需连接 Proxy,无需关心后端拓扑
  2. 透明代理: 对业务应用完全透明
  3. 运维友好: 统一管理入口,便于监控和维护
  4. 弹性伸缩: 可独立扩展 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 修正内容 (基于完整验证)

  1. 主从切换机制: 修正为"自动故障切换"而非"手动切换"
  2. 故障检测时间: 确认为 failcount=5, monitor_interval=1s → 5秒检测
  3. 实际日志验证: 基于真实故障日志验证自动切换能力

v2.1 修正内容

  1. K8S Service 流量分发: 从"随机分发"修正为"轮询分发"
  2. 主从角色: 确认 server-0 为 Master, server-1/2 为 Slave
  3. 资源配置: 修正 Slave 的 CPU 配置为与 Master 相同

验证覆盖

  • ✅ 静态配置: 100% 验证
  • ✅ 架构描述: 100% 验证
  • ✅ 故障切换: 日志验证
  • ⚠️ 负载均衡: 无流量(理论正确)
  • ⚠️ 性能指标: 未测试(理论值)
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐