K8s集群中部署Mysql一主两从集群

'# K8s集群中部署Mysql一主两从集群

一、背景与问题

在Kubernetes集群中部署MySQL一主两从架构,是实现数据库高可用、读写分离和负载均衡的典型场景。这种架构通过主从复制机制,将读请求分发到从库,同时通过主库的写操作同步到从库,可有效提升系统吞吐量。

但实际部署中常遇到如下挑战:

  1. 网络拓扑导致主从同步延迟
  2. 状态管理复杂性
  3. 数据持久化与恢复机制
  4. 故障转移时的自动切换
  5. 配置错误导致的复制中断

二、基本原理

MySQL主从复制的核心原理是通过binlog日志实现数据同步。主库将事务日志记录到binlog中,从库通过I/O线程获取binlog,通过SQL线程重放日志实现数据同步。

在K8s中部署时需要考虑:

  1. 有序部署:使用StatefulSet保证Pod的有序创建和标识
  2. 网络策略:通过Headless Service实现主从通信
  3. 持久化存储:使用PersistentVolume保证数据持久化
  4. 初始化容器:在Pod启动时执行初始化脚本
  5. 复制配置:通过配置文件设置主从关系

三、环境准备

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    server-id=1
    log-bin=mysql-bin
    binlog-format=ROW
    sync-binlog=1
    innodb_flush_log_at_trx_commit=1
    # 主库配置
    # log-bin=mysql-bin
    # binlog-format=ROW
    # sync-binlog=1
    # innodb_flush_log_at_trx_commit=1
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  storageClassName: standard

四、核心实现

1. StatefulSet配置(主库)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpass"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        lifecycle:
          postStart:
            exec:
              command: ["sh", "-c", "chown -R mysql:mysql /var/lib/mysql && /usr/bin/mysqld --initialize-insecure --user=mysql"]
      initContainers:
      - name: init-mysql
        image: mysql:8.0
        command:
        - sh
        - "-c"
        - |
          # 初始化主库
          if [ "$MYSQL_HOST" = "mysql-0.mysql" ]; then
            # 主库初始化
            mysql -u root -p"rootpass" -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass';"
            mysql -u root -p"rootpass" -e "GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'replpass';"
            mysql -u root -p"rootpass" -e "FLUSH PRIVILEGES;"
          elif [ "$MYSQL_HOST" = "mysql-1.mysql" ]; then
            # 从库初始化
            mysql -u root -p"rootpass" -e "CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;"
            mysql -u root -p"rootpass" -e "START SLAVE;"
          fi
        env:
        - name: MYSQL_HOST
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-pv

2. Headless Service配置

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None
  ports:
  - port: 3306
    protocol: TCP
  selector:
    app: mysql

3. 副本配置策略

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-replication
data:
  replication: |
    # 主库配置
    [mysqld]
    server-id=1
    log-bin=mysql-bin
    binlog-format=ROW
    sync-binlog=1
    innodb_flush_log_at_trx_commit=1

    # 从库配置
    [mysqld]
    server-id=2
    relay-log=mysql-relay
    relay-log-index=mysql-relay.index
    read-only
    replicate-do-db=mydb
    replicate-ignore-db=information_schema
    replicate-ignore-db=performance_schema
    replicate-ignore-db=mysql

五、完整案例

以下是一个完整的部署案例,包含主库和两个从库的配置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    server-id=1
    log-bin=mysql-bin
    binlog-format=ROW
    sync-binlog=1
    innodb_flush_log_at_trx_commit=1
    # 主库配置
    # log-bin=mysql-bin
    # binlog-format=ROW
    # sync-binlog=1
    # innodb_flush_log_at_trx_commit=1
    # 从库配置
    # server-id=2
    # relay-log=mysql-relay
    # relay-log-index=mysql-relay.index
    # read-only
    # replicate-do-db=mydb
    # replicate-ignore-db=information_schema
    # replicate-ignore-db=performance_schema
    # replicate-ignore-db=mysql

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  storageClassName: standard

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: standard
  resources:
    requests:
      storage: 10Gi

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpass"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        lifecycle:
          postStart:
            exec:
              command: ["sh", "-c", "chown -R mysql:mysql /var/lib/mysql && /usr/bin/mysqld --initialize-insecure --user=mysql"]
      initContainers:
      - name: init-mysql
        image: mysql:8.0
        command:
        - sh
        - "-c"
        - |
          # 初始化主库
          if [ "$MYSQL_HOST" = "mysql-0.mysql" ]; then
            # 主库初始化
            mysql -u root -p"rootpass" -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass';"
            mysql -u root -p"rootpass" -e "GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'replpass';"
            mysql -u root -p"rootpass" -e "FLUSH PRIVILEGES;"
          elif [ "$MYSQL_HOST" = "mysql-1.mysql" ]; then
            # 从库初始化
            mysql -u root -p"rootpass" -e "CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;"
            mysql -u root -p"rootpass" -e "START SLAVE;"
          fi
        env:
        - name: MYSQL_HOST
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-pvc

六、源码解析

1. StatefulSet配置分析

  • serviceName: mysql 指定Headless Service名称
  • replicas: 3 表示一个主库+两个从库
  • initContainers 用于初始化主从关系

    • 主库初始化:创建复制用户、授权
    • 从库初始化:设置主库信息、启动复制

2. Headless Service的作用

  • clusterIP: None 保证DNS解析返回Pod的IP地址
  • selector 确保服务指向正确的Pod
  • 通过mysql-0.mysql等DNS名称实现主从通信

3. 环境变量配置

  • MYSQL_HOST 用于区分主库和从库
  • MYSQL_ROOT_PASSWORD 设置root密码
  • replpass 设置复制用户密码

七、进阶使用

1. 健康检查配置

livenessProbe:
  exec:
    command:
    - sh
    - "-c"
    - "mysqladmin -u root -p'rootpass' ping"
  initialDelaySeconds: 30
  periodSeconds: 10
readinessProbe:
  exec:
    command:
    - sh
    - "-c"
    - "mysqladmin -u root -p'rootpass' ping"
  initialDelaySeconds: 5
  periodSeconds: 5

2. 自动故障转移

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-failover
data:
  failover: |
    # 自动故障转移脚本
    # 检测主库状态
    if [ "$MYSQL_HOST" = "mysql-0.mysql" ]; then
      # 主库检测
      if ! mysql -u root -p"rootpass" -e "SHOW STATUS LIKE 'Slave_IO_Running'" | grep -q 'Yes'; then
        # 主库故障,提升从库为新主库
        mysql -u root -p"rootpass" -e "STOP SLAVE;"
        mysql -u root -p"rootpass" -e "RESET SLAVE;"
        mysql -u root -p"rootpass" -e "CHANGE MASTER TO MASTER_HOST='mysql-1.mysql', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;"
        mysql -u root -p"rootpass" -e "START SLAVE;"
      fi
    fi

3. 性能调优

data:
  my.cnf: |
    [mysqld]
    server-id=1
    log-bin=mysql-bin
    binlog-format=ROW
    sync-binlog=1
    innodb_flush_log_at_trx_commit=1
    innodb_buffer_pool_size=1G
    innodb_log_file_size=128M
    innodb_log_files_in_group=4
    query_cache_type=OFF
    query_cache_size=0

八、性能与工程实践

1. 性能优化策略

  1. 调整innodb_buffer_pool_size:根据可用内存设置,建议设置为物理内存的70%-80%
  2. 优化binlog格式:使用ROW格式可提高复制可靠性
  3. 调整同步方式:使用sync-binlog=1保证数据一致性
  4. 启用压缩:在复制过程中启用压缩减少网络传输
  5. 定期清理binlog:使用PURGE BINARY LOGS清理旧日志

2. 安全实践

  1. 最小权限原则:复制用户仅需REPLICATION权限
  2. SSL加密:配置SSL证书进行通信加密
  3. 定期备份:使用mysqldump或xtrabackup进行定期备份
  4. 访问控制:通过K8s的NetworkPolicy限制访问
  5. 审计日志:开启general_log和slow_log进行监控

3. 异常处理

  1. 复制延迟监控:

    SHOW SLAVE STATUS\G

    关注Seconds_Behind_Master指标

  2. 主从同步异常处理:

    # 停止从库复制
    mysql -u root -p"rootpass" -e "STOP SLAVE;"
    
    # 重置从库
    mysql -u root -p"rootpass" -e "RESET SLAVE;"
    
    # 重新配置主库
    mysql -u root -p"rootpass" -e "CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;"
    
    # 启动复制
    mysql -u root -p"rootpass" -e "START SLAVE;"

九、常见问题与踩坑

1. 主从同步延迟问题

现象:Seconds_Behind_Master持续增大
原因:

  • 网络带宽不足
  • 主库写入压力过大
  • 从库配置不当

解决:

  1. 检查网络QoS策略
  2. 调整innodb_flush_log_at_trx_commit为2
  3. 增加从库资源

2. 配置错误导致复制失败

错误示例:

# 错误的配置
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mysql

问题:未指定serviceName导致无法发现Pod

改进:

spec:
  serviceName: mysql
  replicas: 3

3. 状态管理问题

错误示例:

lifecycle:
  postStart:
    exec:
      command: ["sh", "-c", "chown -R mysql:mysql /var/lib/mysql"]

问题:未处理初始化失败情况

改进:

lifecycle:
  postStart:
    exec:
      command: ["sh", "-c", "chown -R mysql:mysql /var/lib/mysql || exit 1"]

十、最佳实践

  1. 使用StatefulSet保证有序性:确保主库始终是第一个Pod
  2. 启用自动故障转移:通过监控和脚本实现自动切换
  3. 定期维护:设置CronJob进行定期备份和日志清理
  4. 监控报警:集成Prometheus+Grafana进行监控
  5. 安全加固:启用SSL加密和访问控制

十一、总结

在Kubernetes集群中部署MySQL一主两从架构,需要深入理解主从复制机制和K8s的StatefulSet特性。通过合理的配置和实践,可以实现高可用、可扩展的数据库架构。

这种方案适用于:

  • 需要读写分离的业务场景
  • 对数据一致性要求较高的系统
  • 需要水平扩展的数据库集群

但需要注意:

  • 不适合对延迟敏感的业务
  • 不适合小型应用
  • 不适合需要频繁主库切换的场景

通过合理配置监控、安全和性能参数,可以最大化发挥这种架构的优势。在实际项目中,建议结合具体业务需求,选择合适的部署方案。

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日