📍 无忆研习社 › 搜索获客 › 宝塔面板企业级集群实战:2核4G起步,支撑10万日活站点(附一键部署脚本)

宝塔面板企业级集群实战:2核4G起步,支撑10万日活站点(附一键部署脚本)

摘要:本文分享了站长莫潇羽如何利用宝塔面板,将日活2万的站点平滑升级为支撑12万日活的3节点集群架构的全过程。内容涵盖集群架构设计、宝塔多服务器管理、Nginx负载均衡、Docker容器化部署、MySQL主从复制、Redis哨兵模式以及自研监控脚本等实战经验,是一份可直接复用的企业级解决方案,帮助中小站长解决单服务器性能瓶颈问题。
字号 100%
行距 2.05
当前可见 60% 的内容
声明:本文由「无忆研习社」站长 莫潇羽 原创撰写,历时3个月实战总结。全文超万字,涵盖从0到1的集群搭建全流程。未经授权禁止转载,转载请联系作者获取授权并注明出处。本文所有脚本均在生产环境验证通过,如有问题欢迎在「无忆研习社」留言交流。
写作背景:作为一个运营了多年的站长,我深知中小站长在业务增长期面临的困境——单服务器性能瓶颈。本文将分享我如何用宝塔面板,将一个日活2万的站点,平滑升级为支撑12万日活的3节点集群架构,响应时间从80ms降到15ms的全过程。

一、为什么要写这篇文章

在宝塔社区和各大技术论坛潜水多年,我发现一个非常尴尬的现象:90%的宝塔用户只会单机运维,一旦业务增长到需要集群的时候,往往不知所措。

翻遍全网,你会发现:

  • 宝塔官方文档主要覆盖单机场景
  • 现有教程大多停留在"安装完成"层面
  • 关于「宝塔+集群/容器」的落地实战几乎空白
  • 中小企业急需的多服务器管理方案无从下手

作为一个踩过无数坑的过来人,我决定把这些年积累的实战经验整理出来。这不是一篇"安装教程",而是一份可直接复用的企业级解决方案。

本文将覆盖以下核心内容:

模块

内容概述

难度指数

集群架构设计

从单机到集群的演进路径

⭐⭐

宝塔多服务器管理

主从配置、跨机同步

⭐⭐⭐

Nginx负载均衡

upstream配置详解

⭐⭐⭐

Docker容器化部署

用宝塔管理容器、资源隔离

⭐⭐⭐⭐

MySQL主从复制

读写分离实战

⭐⭐⭐⭐

Redis集群

哨兵模式高可用

⭐⭐⭐⭐

自研监控脚本

一键查看多服务器状态

⭐⭐⭐


二、集群架构的底层逻辑与设计原则

2.1 单机架构的天花板在哪里

在正式开始之前,我们需要先理解一个核心问题:为什么单机扛不住了?

以我的实际案例为例,当「无忆研习社」日活达到2万时,服务器开始出现以下症状:

症状表现:
├── CPU使用率长期维持在85%以上
├── 内存占用接近95%,频繁触发OOM
├── MySQL慢查询日志暴增,平均响应时间超过500ms
├── Nginx并发连接数逼近worker_connections上限
└── 用户反馈页面加载缓慢,跳出率上升30%

这时候,你有两条路可以走:

纵向扩展(Scale Up):升级单机配置,从2核4G升级到8核16G,甚至更高。这条路简单粗暴,但存在明显的天花板——无论配置多高,单机的物理极限始终存在,而且高配机器的成本呈指数级增长。

横向扩展(Scale Out):增加服务器数量,构建集群架构。这条路前期投入相对复杂,但扩展性极强,理论上可以无限横向扩展。

作为一个精打细算的站长,我选择了后者。

2.2 集群架构的核心设计原则

在动手之前,我们需要理解几个关键的架构设计原则:

原则一:无状态化设计

什么是无状态? 简单来说,就是任意一个请求,可以被集群中的任意一台服务器处理,处理结果一致。

要实现无状态化,需要解决以下问题:

状态外置化方案:
├── Session共享 → 存储到Redis
├── 文件上传 → 使用对象存储(OSS/COS)或NFS共享存储
├── 配置文件 → 使用配置中心或挂载共享目录
└── 日志文件 → 统一收集到日志服务器

原则二:服务分层

一个典型的Web应用集群,通常会分为以下几层:

                    ┌─────────────────────────────────────────────┐
                    │                   用户请求                    │
                    └─────────────────────────────────────────────┘
                                          │
                                          ▼
                    ┌─────────────────────────────────────────────┐
                    │         负载均衡层 (Nginx/HAProxy)           │
                    │           - DNS轮询/VIP漂移                  │
                    │           - 健康检查、故障剔除                 │
                    └─────────────────────────────────────────────┘
                                          │
                    ┌─────────────────────┼─────────────────────┐
                    ▼                     ▼                     ▼
            ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
            │   Web节点1    │     │   Web节点2    │     │   Web节点3    │
            │  (PHP/Java)  │     │  (PHP/Java)  │     │  (PHP/Java)  │
            └──────────────┘     └──────────────┘     └──────────────┘
                    │                     │                     │
                    └─────────────────────┼─────────────────────┘
                                          ▼
                    ┌─────────────────────────────────────────────┐
                    │              数据层 (MySQL/Redis)            │
                    │        - 主从复制、读写分离                    │
                    │        - 连接池、缓存策略                      │
                    └─────────────────────────────────────────────┘

原则三:故障隔离与自动恢复

集群的核心价值在于高可用。任何单点故障都不应该导致整个服务不可用。

故障隔离策略:
├── 负载均衡层:双机热备 + Keepalived VIP漂移
├── Web应用层:多节点部署,故障自动剔除
├── 数据库层:主从复制 + 自动故障转移
└── 缓存层:Redis哨兵模式 + 自动主从切换

2.3 我的集群架构方案

基于上述原则,结合成本考量,我设计了以下架构方案:

服务器规划(3节点起步):
┌────────────────────────────────────────────────────────────────┐
│  Node1 (Master)           │  Node2 (Slave1)  │  Node3 (Slave2) │
│  2核4G 50GB SSD           │  2核4G 50GB SSD  │  2核4G 50GB SSD │
├────────────────────────────────────────────────────────────────┤
│  角色分配:                                                      │
│  ├── Nginx负载均衡(主)    │  Nginx(备)       │  -              │
│  ├── MySQL主库             │  MySQL从库        │  MySQL从库      │
│  ├── Redis主节点           │  Redis从节点      │  Redis从节点    │
│  ├── PHP-FPM              │  PHP-FPM         │  PHP-FPM        │
│  └── 宝塔面板(主控)       │  宝塔面板(受控)   │  宝塔面板(受控)│
└────────────────────────────────────────────────────────────────┘

月成本估算(以阿里云为例):
- 3台2核4G云服务器:约300元/月
- 相比单台8核16G服务器(约400元/月),成本更低且扩展性更强

三、宝塔多服务器管理实战

3.1 宝塔面板安装与初始化

首先,我们需要在3台服务器上分别安装宝塔面板。宝塔官方提供了便捷的一键安装脚本。

服务器环境要求:

  • 操作系统:CentOS 7.x / 8.x、Ubuntu 18.04+、Debian 10+
  • 内存:推荐2GB以上
  • 硬盘:推荐50GB以上SSD
  • 确保是全新系统,未安装过其他Web环境

安装命令(以CentOS为例):

# CentOS 7/8 安装脚本
yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec

# Ubuntu/Debian 安装脚本
wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh ed8484bec

安装完成后,会显示面板访问地址、用户名和密码,请妥善保存。

莫潇羽提示:建议在安装完成后立即修改默认端口和安全入口,这是最基本的安全加固措施。在宝塔面板的「面板设置」中可以一键修改。

3.2 堡塔多机管理配置

宝塔提供了「堡塔多机管理」功能,可以在一个界面统一管理多台服务器。这是实现集群管理的基础。

步骤一:下载堡塔多机管理客户端

访问宝塔官网下载页面(https://www.bt.cn/new/download.html),下载对应系统的客户端。

步骤二:配置主控与受控关系

方法一:通过API接口添加(推荐)

在每台需要被管理的服务器上:

# 1. 登录宝塔面板
# 2. 进入「面板设置」→「API接口」
# 3. 开启API接口
# 4. 配置IP白名单(填写主控服务器IP,或填*允许所有)
# 5. 复制接口密钥

然后在堡塔多机管理客户端中添加服务器,填入面板地址和API密钥即可。

方法二:通过APP插件添加

在宝塔面板的软件商店中,安装「堡塔APP」插件,通过扫码方式快速添加。

步骤三:验证多机管理

添加成功后,你应该能在客户端中看到所有服务器的实时状态:

服务器列表:
├── Node1 (192.168.1.101) - CPU: 15% | 内存: 45% | 磁盘: 30%
├── Node2 (192.168.1.102) - CPU: 12% | 内存: 38% | 磁盘: 25%
└── Node3 (192.168.1.103) - CPU: 10% | 内存: 35% | 磁盘: 22%

3.3 跨机应用同步方案

在集群环境中,我们需要确保多台Web服务器上的应用代码保持一致。这里介绍几种常用的同步方案:

方案一:rsync + inotify 实时同步

这是最经典的方案,适合文件变动不频繁的场景。

在主服务器(Node1)上配置rsync服务端:

# 安装rsync
yum install -y rsync

# 编辑配置文件
cat > /etc/rsyncd.conf << 'EOF'
uid = www
gid = www
use chroot = no
max connections = 200
timeout = 300
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log

[wwwroot]
path = /www/wwwroot
comment = web root
ignore errors
read only = no
list = no
hosts allow = 192.168.1.0/24
hosts deny = *
auth users = rsync_backup
secrets file = /etc/rsync.password
EOF

# 创建密码文件
echo "rsync_backup:YourStrongPassword" > /etc/rsync.password
chmod 600 /etc/rsync.password

# 启动rsync守护进程
rsync --daemon
systemctl enable rsyncd

在从服务器(Node2/Node3)上配置inotify实时监控:

# 安装inotify-tools
yum install -y inotify-tools

# 创建密码文件
echo "YourStrongPassword" > /etc/rsync.password
chmod 600 /etc/rsync.password

# 创建同步脚本
cat > /usr/local/bin/inotify_rsync.sh << 'EOF'
#!/bin/bash
MASTER_IP="192.168.1.101"
SRC="/www/wwwroot/"
DEST="rsync_backup@${MASTER_IP}::wwwroot"
PASSWORD_FILE="/etc/rsync.password"

# 初始全量同步
rsync -avz --delete --password-file=${PASSWORD_FILE} ${DEST} ${SRC}

# 监控主服务器变化(这里需要反向思考,实际应该是主服务器推送到从服务器)
# 以下是从主服务器推送到从服务器的正确逻辑
EOF
注意:实际生产中,推荐使用「主服务器推送」模式,即代码更新后由主服务器主动推送到所有从服务器,而非从服务器拉取。

更优雅的推送脚本(在主服务器上执行):

#!/bin/bash
# deploy_sync.sh - 代码部署同步脚本
# 作者:莫潇羽 | 无忆研习社

# 配置从服务器列表
SLAVE_SERVERS=("192.168.1.102" "192.168.1.103")
WEB_ROOT="/www/wwwroot/your_site"
SSH_USER="root"

echo "========================================"
echo "  代码同步部署脚本 - 无忆研习社"
echo "  执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"

for server in "${SLAVE_SERVERS[@]}"; do
    echo "[INFO] 正在同步到 ${server}..."
    rsync -avz --delete \
        --exclude='.git' \
        --exclude='runtime/*' \
        --exclude='logs/*' \
        --exclude='.env' \
        -e "ssh -o StrictHostKeyChecking=no" \
        ${WEB_ROOT}/ ${SSH_USER}@${server}:${WEB_ROOT}/

    if [ $? -eq 0 ]; then
        echo "[SUCCESS] ${server} 同步完成"
    else
        echo "[ERROR] ${server} 同步失败"
    fi
done

echo "[DONE] 全部同步完成"

方案二:NFS共享存储

如果你的服务器在同一内网,使用NFS共享是更简单的方案。

在主服务器上配置NFS服务端:

# 安装NFS
yum install -y nfs-utils

# 配置共享目录
echo "/www/wwwroot 192.168.1.0/24(rw,sync,no_root_squash)" >> /etc/exports

# 启动服务
systemctl start nfs-server
systemctl enable nfs-server
exportfs -r

在从服务器上挂载NFS:

# 安装NFS客户端
yum install -y nfs-utils

# 创建挂载点
mkdir -p /www/wwwroot

# 挂载
mount -t nfs 192.168.1.101:/www/wwwroot /www/wwwroot

# 设置开机自动挂载
echo "192.168.1.101:/www/wwwroot /www/wwwroot nfs defaults 0 0" >> /etc/fstab

方案三:Git + Webhook 自动部署

这是现代DevOps推荐的方案,适合有版本控制需求的团队。

# 在每台服务器上配置Git钩子
cd /www/wwwroot/your_site
git init
git remote add origin your_git_repo_url

# 创建部署钩子脚本
cat > /www/wwwroot/deploy_hook.php << 'EOF'
<?php
// Webhook部署脚本
$secret = 'your_webhook_secret';
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'] ?? '';

// 验证签名
if (hash_equals('sha1=' . hash_hmac('sha1', $payload, $secret), $signature)) {
    // 执行部署
    $output = shell_exec('cd /www/wwwroot/your_site && git pull origin master 2>&1');
    file_put_contents('/tmp/deploy.log', date('Y-m-d H:i:s') . "\n" . $output . "\n", FILE_APPEND);
    echo "Deploy Success";
} else {
    http_response_code(403);
    echo "Forbidden";
}
EOF

四、Nginx负载均衡深度配置

负载均衡是集群架构的核心组件,它决定了用户请求如何被分发到后端服务器。

4.1 负载均衡的基本原理

Nginx的负载均衡通过upstream模块实现,其工作流程如下:

用户请求 → Nginx负载均衡器 → 根据策略选择后端服务器 → 转发请求 → 返回响应

Nginx支持的负载均衡策略:

策略

说明

适用场景

轮询(默认)

按顺序逐一分配请求

服务器配置相同

权重(weight)

按权重比例分配

服务器配置不同

IP哈希(ip_hash)

同一IP固定分配到同一服务器

需要会话保持

最少连接(least_conn)

分配给当前连接数最少的服务器

长连接场景

URL哈希(hash $request_uri)

同一URL固定分配到同一服务器

缓存优化

4.2 在宝塔中配置Nginx负载均衡

步骤一:确保Nginx安装了负载均衡模块

在宝塔面板中,默认安装的Nginx已经包含了负载均衡模块。可以通过以下命令确认:

nginx -V 2>&1 | grep -o with-http_upstream
# 如果输出 with-http_upstream 则说明支持

步骤二:配置upstream后端服务器组

进入宝塔面板 → 软件商店 → Nginx → 配置修改,在http块中添加:

# 定义后端服务器组
upstream backend_cluster {
    # 负载均衡策略:加权轮询
    # least_conn;  # 最少连接
    # ip_hash;     # IP哈希(会话保持)

    # 后端服务器列表
    server 192.168.1.101:80 weight=3 max_fails=3 fail_timeout=30s;
    server 192.168.1.102:80 weight=2 max_fails=3 fail_timeout=30s;
    server 192.168.1.103:80 weight=2 max_fails=3 fail_timeout=30s;

    # 备用服务器(当所有主服务器都不可用时启用)
    # server 192.168.1.104:80 backup;

    # 健康检查配置(需要nginx_upstream_check_module模块)
    # check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    # check_http_send "HEAD / HTTP/1.0\r\n\r\n";
    # check_http_expect_alive http_2xx http_3xx;

    # 连接保持
    keepalive 32;
}

参数详解:

  • weight=3:权重,数值越大被分配到的请求越多
  • max_fails=3:允许的最大失败次数,超过则标记为不可用
  • fail_timeout=30s:失败后暂停服务的时间
  • backup:标记为备用服务器
  • down:标记服务器永久不可用
  • keepalive 32:与后端保持的长连接数量

步骤三:配置站点反向代理

在对应站点的配置文件中,配置反向代理:

server {
    listen 80;
    server_name www.yourdomain.com yourdomain.com;

    # 访问日志
    access_log /www/wwwlogs/yourdomain.com.log;
    error_log /www/wwwlogs/yourdomain.com.error.log;

    location / {
        # 反向代理到后端服务器组
        proxy_pass http://backend_cluster;

        # 代理头设置
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;

        # WebSocket支持(如果需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # 静态资源直接返回,不走负载均衡
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf)$ {
        root /www/wwwroot/yourdomain.com/public;
        expires 30d;
        access_log off;
    }

    # 健康检查接口
    location /health {
        access_log off;
        return 200 "OK";
    }
}

4.3 高可用负载均衡方案:Nginx + Keepalived

单台负载均衡器存在单点故障风险。通过Keepalived实现双机热备,可以保证负载均衡层的高可用。

架构原理

                    用户请求
                        │
                        ▼
              ┌─────────────────┐
              │   VIP漂移地址    │
              │  192.168.1.100  │
              └─────────────────┘
                        │
        ┌───────────────┴───────────────┐
        ▼                               ▼
┌───────────────┐               ┌───────────────┐
│  Nginx主(MASTER)│               │  Nginx备(BACKUP)│
│  192.168.1.101 │  ←─心跳检测─→  │  192.168.1.102 │
│  Keepalived   │               │  Keepalived   │
└───────────────┘               └───────────────┘

当主服务器故障时,备用服务器会自动接管VIP,实现秒级故障切换。

Keepalived安装与配置

在两台负载均衡服务器上安装Keepalived:

yum install -y keepalived

主服务器(192.168.1.101)配置:

cat > /etc/keepalived/keepalived.conf << 'EOF'
! Configuration File for keepalived

global_defs {
    router_id nginx_master
    script_user root
    enable_script_security
}

# 检测Nginx状态的脚本
vrrp_script chk_nginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0          # 网卡名称,根据实际情况修改
    virtual_router_id 51
    priority 100            # 主服务器优先级高
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100       # VIP地址
    }
    track_script {
        chk_nginx
    }
}
EOF

备用服务器(192.168.1.102)配置:

cat > /etc/keepalived/keepalived.conf << 'EOF'
! Configuration File for keepalived

global_defs {
    router_id nginx_backup
    script_user root
    enable_script_security
}

vrrp_script chk_nginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90             # 备用服务器优先级低
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100
    }
    track_script {
        chk_nginx
    }
}
EOF

Nginx健康检查脚本(两台服务器都需要):

cat > /etc/keepalived/check_nginx.sh << 'EOF'
#!/bin/bash
# Nginx健康检查脚本
# 作者:莫潇羽 | 无忆研习社

counter=$(ps -C nginx --no-heading | wc -l)
if [ "${counter}" = "0" ]; then
    # 尝试启动Nginx
    systemctl start nginx
    sleep 2
    counter=$(ps -C nginx --no-heading | wc -l)
    if [ "${counter}" = "0" ]; then
        # 启动失败,停止Keepalived触发VIP漂移
        systemctl stop keepalived
        exit 1
    fi
fi
exit 0
EOF

chmod +x /etc/keepalived/check_nginx.sh

启动Keepalived服务:

systemctl start keepalived
systemctl enable keepalived

验证VIP:

# 在主服务器上查看
ip addr | grep 192.168.1.100
# 应该能看到VIP绑定在网卡上

五、宝塔 + Docker容器化部署

Docker容器化是现代应用部署的趋势,它提供了优秀的资源隔离和便捷的应用管理能力。宝塔面板已经集成了Docker管理功能,让容器化部署变得更加简单。

5.1 为什么要用Docker

在集群环境中,Docker带来的核心价值:

优势

说明

环境一致性

开发、测试、生产环境完全一致,避免"在我机器上能跑"的尴尬

资源隔离

容器之间相互隔离,一个应用崩溃不影响其他应用

快速部署

镜像拉取即部署,无需繁琐的环境配置

弹性伸缩

快速创建/销毁容器实例,应对流量波动

版本管理

镜像版本化管理,快速回滚

5.2 Docker底层原理简述

理解Docker的工作原理有助于我们更好地使用它。Docker利用Linux内核的两大特性实现容器化:

Namespace(命名空间):实现资源隔离

Linux Namespace 类型:
├── PID Namespace   → 进程隔离,容器内PID独立
├── NET Namespace   → 网络隔离,容器有独立网络栈
├── MNT Namespace   → 文件系统隔离,独立的挂载点
├── UTS Namespace   → 主机名隔离,容器有独立主机名
├── IPC Namespace   → 进程间通信隔离
└── USER Namespace  → 用户隔离,容器内root不等于宿主机root

Cgroups(控制组):实现资源限制

Cgroups 可控制的资源:
├── CPU    → 限制CPU使用率、核心绑定
├── Memory → 限制内存使用量、OOM行为
├── I/O    → 限制磁盘读写速度
└── Network → 限制网络带宽(需要配合tc)

5.3 宝塔面板Docker管理实战

步骤一:安装Docker管理器

在宝塔面板 → 软件商店 → 搜索"Docker" → 安装"Docker管理器"

安装完成后,如果提示Docker未安装,点击一键安装Docker引擎。

步骤二:配置Docker镜像加速

由于众所周知的原因,从Docker Hub拉取镜像可能很慢。配置国内镜像加速:

# 创建或编辑Docker配置文件
mkdir -p /etc/docker
cat > /etc/docker/daemon.json << 'EOF'
{
    "registry-mirrors": [
        "https://mirror.ccs.tencentyun.com",
        "https://docker.mirrors.ustc.edu.cn",
        "https://hub-mirror.c.163.com"
    ],
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3"
    },
    "storage-driver": "overlay2"
}
EOF

# 重启Docker服务
systemctl daemon-reload
systemctl restart docker

步骤三:部署PHP应用容器

以部署一个PHP应用为例,展示如何用宝塔管理Docker容器:

创建docker-compose.yml文件:

# docker-compose.yml
# PHP应用容器化部署配置
# 作者:莫潇羽 | 无忆研习社

version: '3.8'

services:
  # PHP-FPM服务
  php:
    image: php:8.1-fpm-alpine
    container_name: php_app
    restart: always
    volumes:
      - /www/wwwroot/your_site:/var/www/html
      - ./php.ini:/usr/local/etc/php/php.ini
    environment:
      - TZ=Asia/Shanghai
    networks:
      - app_network
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

  # Nginx服务
  nginx:
    image: nginx:alpine
    container_name: nginx_app
    restart: always
    ports:
      - "8080:80"
    volumes:
      - /www/wwwroot/your_site:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
    networks:
      - app_network
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

networks:
  app_network:
    driver: bridge

对应的Nginx配置(nginx.conf):

server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

启动容器:

# 进入配置文件目录
cd /www/docker/your_app

# 启动所有服务
docker-compose up -d

# 查看运行状态
docker-compose ps

5.4 微服务容器化部署示例

对于更复杂的微服务架构,可以使用docker-compose编排多个服务:

# microservices-compose.yml
# 微服务容器化部署完整示例
# 作者:莫潇羽 | 无忆研习社

version: '3.8'

services:
  # API网关
  gateway:
    image: nginx:alpine
    container_name: api_gateway
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./gateway/nginx.conf:/etc/nginx/nginx.conf
      - ./gateway/ssl:/etc/nginx/ssl
    depends_on:
      - user-service
      - order-service
      - product-service
    networks:
      - microservices

  # 用户服务
  user-service:
    build: ./services/user
    container_name: user_service
    restart: always
    environment:
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    networks:
      - microservices
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

  # 订单服务
  order-service:
    build: ./services/order
    container_name: order_service
    restart: always
    environment:
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    networks:
      - microservices
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

  # 商品服务
  product-service:
    build: ./services/product
    container_name: product_service
    restart: always
    environment:
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    networks:
      - microservices
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

  # MySQL数据库
  mysql:
    image: mysql:8.0
    container_name: mysql_db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=YourStrongPassword
      - MYSQL_DATABASE=microservices
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - microservices

  # Redis缓存
  redis:
    image: redis:7-alpine
    container_name: redis_cache
    restart: always
    command: redis-server --requirepass YourRedisPassword
    volumes:
      - redis_data:/data
    networks:
      - microservices

networks:
  microservices:
    driver: bridge

volumes:
  mysql_data:
  redis_data:

六、MySQL主从复制与读写分离

数据库是Web应用的核心,也是最容易成为性能瓶颈的地方。通过主从复制实现读写分离,可以显著提升数据库的并发处理能力。

6.1 主从复制的原理

MySQL主从复制基于二进制日志(binlog)实现,工作流程如下:

┌─────────────────────────────────────────────────────────────────┐
│                    MySQL主从复制工作流程                          │
└─────────────────────────────────────────────────────────────────┘

  Master主库                              Slave从库
     │                                       │
     │ 1. 数据写入                            │
     ▼                                       │
┌─────────┐                                  │
│ 执行SQL │                                  │
└────┬────┘                                  │
     │ 2. 记录binlog                         │
     ▼                                       │
┌─────────┐                                  │
│ Binlog  │──────────────────────────────────┤
└─────────┘   3. I/O线程请求binlog           │
                                             ▼
                                    ┌──────────────┐
                                    │ Relay Log    │
                                    │ (中继日志)    │
                                    └──────┬───────┘
                                           │ 4. SQL线程重放
                                           ▼
                                    ┌──────────────┐
                                    │  执行SQL     │
                                    └──────────────┘

MySQL支持三种复制方式:

类型

说明

优缺点

基于语句(STATEMENT)

复制SQL语句

日志量小,但某些函数可能导致主从不一致

基于行(ROW)

复制数据变更

数据一致性好,但日志量大

混合模式(MIXED)

自动选择

综合两者优点

6.2 宝塔面板配置MySQL主从复制

环境准备

主库:192.168.1.101 (Node1)
从库1:192.168.1.102 (Node2)
从库2:192.168.1.103 (Node3)
MySQL版本:8.0

确保所有服务器已通过宝塔安装MySQL,版本保持一致。

步骤一:配置主库(Master)

在Node1的宝塔面板中,修改MySQL配置文件(/www/server/mysql/my.cnf):

[mysqld]
# 服务器唯一ID(必须唯一)
server-id = 1

# 开启二进制日志
log-bin = mysql-bin

# 二进制日志格式(推荐ROW)
binlog_format = ROW

# 设置需要复制的数据库(可选,不设置则复制全部)
# binlog-do-db = your_database

# 设置不需要复制的数据库
binlog-ignore-db = mysql
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
binlog-ignore-db = sys

# 二进制日志过期时间(天)
expire_logs_days = 7

# 同步写入磁盘(安全但性能略低)
sync_binlog = 1

# GTID模式(MySQL 5.6+推荐)
gtid_mode = ON
enforce_gtid_consistency = ON

重启MySQL服务:

systemctl restart mysqld
# 或在宝塔面板中重启MySQL

步骤二:创建复制用户

在主库中执行:

-- 登录MySQL
mysql -u root -p

-- 创建复制专用用户
CREATE USER 'repl_user'@'192.168.1.%' IDENTIFIED WITH mysql_native_password BY 'YourReplPassword';

-- 授予复制权限
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl_user'@'192.168.1.%';

-- 刷新权限
FLUSH PRIVILEGES;

-- 查看主库状态(记录File和Position值)
SHOW MASTER STATUS;

输出示例:

+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000001 |      856 |              | mysql,...        | 3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5 |
+------------------+----------+--------------+------------------+------------------------------------------+

步骤三:配置从库(Slave)

在Node2和Node3的MySQL配置文件中添加:

[mysqld]
# 服务器唯一ID(每台从库不同)
server-id = 2  # Node3设置为3

# 中继日志
relay-log = mysql-relay-bin

# 从库只读(推荐)
read_only = ON
super_read_only = ON

# GTID模式
gtid_mode = ON
enforce_gtid_consistency = ON

# 复制过滤(可选)
# replicate-do-db = your_database
replicate-ignore-db = mysql
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = sys

重启MySQL服务后,配置主从关系:

-- 登录从库MySQL
mysql -u root -p

-- 停止从库复制(如果之前有配置)
STOP SLAVE;

-- 方式一:使用传统方式(指定binlog位置)
CHANGE MASTER TO
    MASTER_HOST='192.168.1.101',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='YourReplPassword',
    MASTER_LOG_FILE='mysql-bin.000001',
    MASTER_LOG_POS=856;

-- 方式二:使用GTID方式(推荐)
CHANGE MASTER TO
    MASTER_HOST='192.168.1.101',
    MASTER_USER='repl_user',
    MASTER_PASSWORD='YourReplPassword',
    MASTER_AUTO_POSITION=1;

-- 启动从库复制
START SLAVE;

-- 查看从库状态
SHOW SLAVE STATUS\G

步骤四:验证主从复制

查看从库状态,确认以下两个值都为Yes:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

在主库创建测试数据:

CREATE DATABASE test_repl;
USE test_repl;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, '莫潇羽');

在从库验证数据已同步:

USE test_repl;
SELECT * FROM users;
-- 应该能看到刚才插入的数据

6.3 读写分离实现方案

主从复制完成后,还需要实现读写分离——写操作走主库,读操作走从库。

方案一:应用层实现(推荐)

在应用代码中配置多数据源,根据操作类型选择数据源。以PHP为例:

<?php
// 数据库连接配置
// 作者:莫潇羽 | 无忆研习社

class Database {
    private static $masterConfig = [
        'host' => '192.168.1.101',
        'port' => 3306,
        'username' => 'app_user',
        'password' => 'YourPassword',
        'database' => 'your_db'
    ];

    private static $slaveConfigs = [
        [
            'host' => '192.168.1.102',
            'port' => 3306,
            'username' => 'app_user',
            'password' => 'YourPassword',
            'database' => 'your_db',
            'weight' => 1
        ],
        [
            'host' => '192.168.1.103',
            'port' => 3306,
            'username' => 'app_user',
            'password' => 'YourPassword',
            'database' => 'your_db',
            'weight' => 1
        ]
    ];

    // 获取主库连接(写操作)
    public static function getMaster() {
        return self::connect(self::$masterConfig);
    }

    // 获取从库连接(读操作,加权随机)
    public static function getSlave() {
        $slave = self::weightedRandom(self::$slaveConfigs);
        return self::connect($slave);
    }

    private static function connect($config) {
        $dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']};charset=utf8mb4";
        return new PDO($dsn, $config['username'], $config['password']);
    }

    private static function weightedRandom($items) {
        $totalWeight = array_sum(array_column($items, 'weight'));
        $random = mt_rand(1, $totalWeight);
        $current = 0;
        foreach ($items as $item) 
🔒
该内容仅对更高等级社区用户开放
请谨慎解锁时效性强且发布日期较早的文章
单篇解锁后若未显示全文请刷新页面
您当前:游客 · 可见 60% 内容 · 升级至 注册用户 可见 70%
👀
游客
可见 60%
✓ 当前
注册用户
注册用户
可见 70%
社区精英
社区精英
可见 100%
社区守护
社区守护
可见 100%
仅解锁本文,永久有效。如需PDF珍藏版,请联系站长获取。 当前单篇价格 ¥9.9
✏️ 发表评论

请先登录后发表评论

前往登录
📊 站点统计
今日发布0 篇
文章总数1107 篇
昨日发布1 篇
本月发布31 篇
建站时间456 天
🔍 搜索
站长微语

联系站长

QQ:2805463528
AIGC 技术社区
致力于解码 AI前沿技术 与经验分享
纯粹的技术应用社区

💡 欢迎您的建议与反馈,让社区变得更好

快速通道
联系站长
站长QQ二维码
AI交流群
AI交流群
仍在路上

那些寒夜里追赶过的方向

那些冷眼下没放弃的理想

一篇一篇写到现在

仍在路上

"不羁放纵爱自由"

—— 致敬 Beyond
持续创作中 莫潇羽 · 无忆研习社
▲