我折腾服务器集群的心路历程:从物理机到云原生的实战笔记

说起服务器运维,我折腾这玩意儿差不多八年了。从最早在大学机房里搬机箱、理网线,到后来在公司负责整套基础设施架构,中间踩过的坑够写好几本书了。今天这篇文章不是什么教程,就是我这些年摸爬滚打的真实记录,希望能给同样在路上的兄弟们一点参考。

物理机时代:和Dell R750相爱相杀的日子

2019年那会儿,公司业务量上来了,老板说”上物理机吧,云太贵了”。我当时还挺兴奋,觉得终于能玩真家伙了。采购了4台Dell PowerEdge R750,配置是双路Intel Xeon Gold 6338(32核64线程)、256G内存、4块960G SSD做RAID 10。机器到位那天我激动得不行,结果开箱一看,好家伙,这玩意儿是真沉。

上架那天我和同事两个人抬一台,差点没把腰闪了。当时机房空调制冷不太够,4台R750全功率跑起来之后,整个机柜区域的温度直接飙到38度。我进去待了十分钟就汗流浃背,出来之后头发都是热的。这件事给我上了一课——散热规划比买服务器本身还重要

后来我专门研究了一阵子机房热管理。简单说,冷热通道隔离是基本功,进风口和出风口不能混着摆。当时我们的机柜排列是冷通道正面朝北,热通道朝南,空调从北侧送风。但问题出在盲板没装好,热空气回流导致进风温度偏高。我手工用挡板把每个机柜的空U位都封上了,进风温度从32度降到了24度,效果立竿见影。

说说RAID配置的经验吧。Dell R750用的是PERC H755 RAID卡,配置RAID 10的时候有个坑——默认的Stripe Size是64KB,对我们这种数据库为主的业务不太合适。我后来改成了256KB,IOPS测试下来提升了大概15%。下面是我在iDRAC里用racadm命令行调整的脚本:

# 通过iDRAC查看当前RAID配置
racadm storage get vdisk -o -v

# 创建RAID 10阵列,Stripe Size设为256KB
racadm storage createvd:RAID10:Enclosure-0:Disk-0,Disk-1,Disk-2,Disk-3:256KB

# 设置写缓存策略为WriteBack(有电池保护的情况下)
racadm storage setvd:RAID10:vd0:writepolicy:writeback

# 查看物理磁盘状态
racadm storage get pdisk -o -v

还有个事儿必须提——iDRAC的固件升级。我们有一台R750的iDRAC固件版本是4.0,有一次远程管理突然连不上,KVMoverIP也挂了。大半夜跑机房用物理键盘操作的体验,我这辈子都不想再来第二次。后来我把所有iDRAC固件统一升级到最新版,并且配了双网卡做管理网络冗余。说实话,Dell的硬件质量整体不错,但固件这块的bug是真的不少,定期检查更新是必须的。

上云之路:阿里云、AWS、华为云我用下来的真实感受

物理机跑了两年多,到了2021年公司要扩容,机房空间不够了,而且运维人力也跟不上。CTO拍板上云。当时我们做了为期一个月的POC测试,对比了阿里云、AWS和华为云三家。这里我直接说结论,不藏着掖着。

阿里云的ECS实例类型最丰富,网络延迟在国内是最低的。我们华东区的业务用了ecs.g7e实例,2核8G的配置月费大概240块。阿里云的VPC网络配置比较直观,SLB负载均衡器的健康检查机制比AWS的ALB要灵活一些,可以自定义检查路径和返回码。但阿里云的控制台改版太频繁了,有时候找个功能得翻半天,而且API文档有些地方更新不及时。

AWS我用的是新加坡和东京区域,给东南亚用户服务。EC2 t3.medium实例按需付费每小时约0.05美元,用了Reserved Instances之后能省40%左右。AWS最让我喜欢的是它的生态完整性,CloudFormation做基础设施即代码、Systems Manager做批量运维、CloudWatch做监控,一套流程下来非常丝滑。但AWS的学习曲线是真的陡,光IAM权限模型就让我团队里一个小伙伴折腾了一周才搞明白。另外AWS的技术支持是收费的,Business Support每月要额外付几十美元,这点不如阿里云的基础工单支持。

华为云是后来政务项目要求的,用的ecs.kc1实例,基于鲲鹏ARM处理器。说实话一开始我挺排斥ARM架构的,怕软件兼容性有问题。但实际跑下来发现,Nginx、Redis、MySQL这些主流软件都有ARM版本,性能也没差多少。华为云的安全组规则配置方式我比较喜欢,比阿里云的更直观一点。不过华为云的文档确实不如前两家完善,有些高级特性得翻社区论坛才能找到答案。

最后我们的架构是混合云:核心数据库和计算密集型任务留在物理机上,Web层和缓存层上阿里云,海外业务上AWS,政务相关业务上华为云。用IPSec VPN打通各云之间的内网通信,下面是阿里云VPC Peering的Terraform配置片段:

# terraform main.tf - 阿里云VPC对等连接
resource "alicloud_vpc_peering_connection" "main_to_overseas" {
  vpc_id        = alicloud_vpc.main.id
  accepting_vpc_id = alicloud_vpc.overseas.id
  peer_region   = "ap-southeast-1"
  name          = "main-to-overseas-peering"
}

# 路由表添加对等连接路由
resource "alicloud_route_entry" "to_overseas" {
  route_table_id        = alicloud_vpc.main.route_table_id
  destination_cidr      = "10.20.0.0/16"
  next_hop_type         = "VpcPeering"
  next_hop_id           = alicloud_vpc_peering_connection.main_to_overseas.id
}

Linux系统管理:那些年我改过的内核参数

无论物理机还是云服务器,底层都是Linux。我用过CentOS 7、Ubuntu 18.04/20.04、还有现在的Rocky Linux 9。说实话CentOS停服那波操作对我影响挺大的,当时我们生产环境有30多台CentOS 7,迁移到Rocky Linux花了将近两个月。好在大部分systemd配置和bash脚本都能直接用,主要改动在yum/dnf的包管理差异上。

系统调优这块,我最常改的就是几个内核参数。先说TCP相关的,高并发场景下默认参数根本扛不住:

# /etc/sysctl.d/99-production.conf
# 增大文件描述符上限
fs.file-max = 1048576
fs.nr_open = 1048576

# TCP连接复用和快速回收
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 增大SYN队列长度,防止SYN Flood
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_syncookies = 1

# 增大连接跟踪表
net.netfilter.nf_conntrack_max = 1048576
net.ipv4.tcp_max_tw_buckets = 1048576

# TCP keepalive探测,更快发现死连接
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# 增大网络接收缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 5000

# 应用生效
sysctl -p /etc/sysctl.d/99-production.conf

再说说ulimit的坑。有一次我们的Java应用报了”Too many open files”错误,排查了半天发现是systemd的LimitNOFILE没配,默认只有1024。改了/etc/security/limits.conf还不行,因为systemd不读这个文件。得在service unit文件里显式声明:

# /etc/systemd/system/myapp.service
[Service]
LimitNOFILE=65536
LimitNPROC=65536
LimitMEMLOCK=infinity

# 重载并重启
systemctl daemon-reload
systemctl restart myapp

还有个实战经验关于磁盘IO调度器。SSD用deadline或者none(多队列)调度器就行,千万别用cfq,那是给机械硬盘准备的。在Rocky Linux 9上查看和修改:

# 查看当前调度器
cat /sys/block/sda/queue/scheduler

# 临时修改为none(适合NVMe SSD)
echo none > /sys/block/sda/queue/scheduler

# 永久生效,通过udev规则
echo 'ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="none"' \
  > /etc/udev/rules.d/60-ssd-scheduler.rules

高可用集群:Keepalived + HAProxy扛过百万级QPS

2022年双十一,我们预估流量会是平时的5倍。当时的架构是Nginx做反向代理,单点部署,我心想这不行,万一挂了全站完蛋。于是花了一周时间搭了一套Keepalived + HAProxy的双机高可用方案。

整体思路是两台HAProxy做负载均衡,通过Keepalived实现VIP故障切换。主节点宕机时,备用节点在1秒内接管VIP。HAProxy负责把请求分发到后端的Nginx集群,再由Nginx转发到应用服务器。这个架构跑了快两年了,中间经历过3次硬件故障自动切换,业务无感知。

先看Keepalived的配置,主节点和备用节点的配置基本一样,只有priority和state不同:

# /etc/keepalived/keepalived.conf - 主节点
global_defs {
    router_id HAPROXY_MASTER
    enable_script_security
    script_user root
}

# 健康检查脚本,检测HAProxy是否存活
vrrp_script check_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    weight -30
    fall 2
    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 MySecurePass2024
    }
    virtual_ipaddress {
        10.0.1.100/24 dev eth0
    }
    track_script {
        check_haproxy
    }
    # 故障切换时发邮件通知
    notify_master "/etc/keepalived/notify.sh master"
    notify_backup "/etc/keepalived/notify.sh backup"
}
#!/bin/bash
# /etc/keepalived/check_haproxy.sh
# 检查HAProxy进程是否存活
if ! killall -0 haproxy 2>/dev/null; then
    systemctl restart haproxy
    sleep 2
    if ! killall -0 haproxy 2>/dev/null; then
        echo "HAProxy is down, failing over" >&2
        exit 1
    fi
fi
exit 0

HAProxy的配置我调了挺久的,关键是后端健康检查和会话保持。我们的业务有session亲和性需求,用了source IP hash策略。另外开启了HAProxy的统计页面,方便实时观察流量:

# /etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    maxconn 100000
    nbthread 8
    cpu-map auto:1/1-8 0-7
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384
    tune.ssl.default-dh-param 2048

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5s
    timeout client 30s
    timeout server 30s
    retries 3

# 统计页面
listen stats
    bind *:8404
    mode http
    stats enable
    stats uri /stats
    stats auth admin:StrongPass2024
    stats refresh 10s

# 前端入口
frontend web_front
    bind *:80
    bind *:443 ssl crt /etc/haproxy/ssl/fullchain.pem
    redirect scheme https if !{ ssl_fc }
    acl is_api path_beg /api
    use_backend api_servers if is_api
    default_backend web_servers

# Web后端,源IP哈希保持会话
backend web_servers
    balance source
    option httpchk GET /health
    http-check expect status 200
    server web1 10.0.2.11:80 check inter 3s fall 3 rise 2
    server web2 10.0.2.12:80 check inter 3s fall 3 rise 2
    server web3 10.0.2.13:80 check inter 3s fall 3 rise 2 backup

# API后端,最少连接策略
backend api_servers
    balance leastconn
    option httpchk GET /api/health
    http-check expect status 200
    server api1 10.0.3.11:8080 check inter 2s fall 3 rise 2
    server api2 10.0.3.12:8080 check inter 2s fall 3 rise 2

上线之前我用wrk做了压力测试。单台HAProxy(8核16G)在SSL卸载场景下能跑到约45000 QPS,两台同时跑加上Keepalived的VIP切换,理论峰值能到9万QPS。实际双十一当天峰值在6万QPS左右,机器负载也就到60%,心里踏实多了。

不过这中间也有个小插曲。上线第二天夜里Keepalived发生了脑裂(split-brain),主备两台同时持有VIP,导致部分请求被丢到错误的节点上。排查后发现是因为VRRP的组播包被交换机的某个端口过滤了。改成单播模式之后就再没出过这个问题:

# 在vrrp_instance块里添加单播配置
vrrp_instance VI_1 {
    # ... 其他配置 ...
    unicast_src_ip 10.0.1.11
    unicast_peer {
        10.0.1.12
    }
}

服务器安全加固:我的实战清单和Bash脚本

最后聊聊安全。服务器被黑过一次,2020年那会儿,有个测试环境的Redis没设密码还绑了0.0.0.0,被人扫到之后往crontab里写了个挖矿脚本。发现的时候CPU已经跑满三天了,服务器卡得跟PPT一样。从那以后我搞了一套安全加固的标准流程,每台新机器上线前必须跑一遍。

我把整个加固过程写成了一个Bash脚本,下面是完整版,团队里所有人都能直接用:

#!/bin/bash
# server_hardening.sh - 服务器安全加固脚本
# 使用方法: bash server_hardening.sh
# 作者: 运维团队

set -euo pipefail

LOG_FILE="/var/log/server_hardening_$(date +%Y%m%d_%H%M%S).log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"; }

# ========== 1. 禁用root SSH登录 ==========
log "开始配置SSH安全策略..."
SSH_CONFIG="/etc/ssh/sshd_config"
cp "$SSH_CONFIG" "${SSH_CONFIG}.bak.$(date +%Y%m%d)"

sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' "$SSH_CONFIG"
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' "$SSH_CONFIG"
sed -i 's/^#*Port .*/Port 22022/' "$SSH_CONFIG"
sed -i 's/^#*MaxAuthTries.*/MaxAuthTries 3/' "$SSH_CONFIG"
sed -i 's/^#*LoginGraceTime.*/LoginGraceTime 30/' "$SSH_CONFIG"
sed -i 's/^#*AllowUsers.*/AllowUsers deploy admin/' "$SSH_CONFIG"

# 空密码登录禁止
sed -i 's/^#*PermitEmptyPasswords.*/PermitEmptyPasswords no/' "$SSH_CONFIG"

systemctl restart sshd
log "SSH配置完成:端口改为22022,禁用root登录和密码认证"

# ========== 2. 配置防火墙 ==========
log "配置firewalld规则..."
systemctl enable firewalld
systemctl start firewalld

# 清除默认规则,只放行必要端口
firewall-cmd --permanent --set-default-zone=drop
firewall-cmd --permanent --zone=internal --add-source=10.0.0.0/8
firewall-cmd --permanent --zone=internal --add-port=22022/tcp
firewall-cmd --permanent --zone=internal --add-port=80/tcp
firewall-cmd --permanent --zone=internal --add-port=443/tcp

# 限制内部管理端口只允许运维网段访问
firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address=10.0.1.0/24 port port=3306 protocol=tcp accept'
firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address=10.0.1.0/24 port port=6379 protocol=tcp accept'

firewall-cmd --reload
log "防火墙配置完成"

# ========== 3. 禁用不必要的服务 ==========
log "关闭无用服务..."
SERVICES_TO_DISABLE=(
    "avahi-daemon"
    "cups"
    "bluetooth"
    "nfs-server"
    "rpcbind"
    "postfix"
)
for svc in "${SERVICES_TO_DISABLE[@]}"; do
    if systemctl is-active --quiet "$svc" 2>/dev/null; then
        systemctl stop "$svc"
        systemctl disable "$svc"
        log "已关闭服务: $svc"
    fi
done

# ========== 4. 配置fail2ban防暴力破解 ==========
log "安装配置fail2ban..."
if ! command -v dnf &>/dev/null; then
    apt-get update && apt-get install -y fail2ban
else
    dnf install -y fail2ban
fi

cat > /etc/fail2ban/jail.local << 'FAIL2BAN_EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = firewallcmd-ipset

[sshd]
enabled = true
port = 22022
logpath = %(sshd_log)s
backend = systemd
maxretry = 3
bantime = 7200
FAIL2BAN_EOF

systemctl enable fail2ban
systemctl restart fail2ban
log "fail2ban配置完成,SSH失败3次封禁2小时"

# ========== 5. 内核安全参数 ==========
log "配置内核安全参数..."
cat > /etc/sysctl.d/99-security.conf << 'SYSCTL_EOF'
# 禁用IP转发(非路由器场景)
net.ipv4.ip_forward = 0

# 禁用源路由
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# 禁用ICMP重定向
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# 启用反向路径过滤
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# 禁用IP欺骗
net.ipv4.conf.all.accept_source_route = 0

# 记录可疑数据包
net.ipv4.conf.all.log_martians = 1

# 禁用IPv6(如不需要)
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
SYSCTL_EOF

sysctl -p /etc/sysctl.d/99-security.conf
log "内核安全参数配置完成"

# ========== 6. 配置自动安全更新 ==========
log "配置自动安全更新..."
if command -v dnf &>/dev/null; then
    dnf install -y dnf-automatic
    sed -i 's/^upgrade_type.*/upgrade_type = security/' /etc/dnf/automatic.conf
    sed -i 's/^apply_updates.*/apply_updates = yes/' /etc/dnf/automatic.conf
    systemctl enable --now dnf-automatic.timer
else
    apt-get install -y unattended-upgrades
    dpkg-reconfigure -plow unattended-upgrades
fi
log "自动安全更新配置完成"

# ========== 7. 审计日志配置 ==========
log "配置audit审计规则..."
cat > /etc/audit/rules.d/hardening.rules << 'AUDIT_EOF'
# 删除已有规则
-D
# 设置缓冲区大小
-b 8192
# 监控密码和权限文件访问
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k identity
# 监控SSH配置变更
-w /etc/ssh/sshd_config -p wa -k ssh_config
# 监控crontab变更
-w /etc/crontab -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
# 监控系统启动相关文件
-w /etc/systemd/ -p wa -k systemd
# 监控登录相关事件
-w /var/log/lastlog -p wa -k logins
-w /var/log/faillog -p wa -k logins
AUDIT_EOF

systemctl enable auditd
systemctl restart auditd
log "审计规则配置完成"

log "========== 安全加固完成 =========="
log "请确认以下事项:"
log "1. 已创建普通用户并配置SSH密钥认证"
log "2. 测试SSH新端口22022可正常连接后再关闭旧会话"
log "3. 确认fail2ban状态: fail2ban-client status"
log "4. 确认防火墙规则: firewall-cmd --list-all"

这套脚本我们团队用了快两年,每台新机器上线前都跑一遍。除了脚本里自动化的部分,还有几个手工检查项我每次都会过一遍:确认SSH密钥能登录再禁用密码认证、检查有没有遗留的测试账号、确认sudoers配置是否合理、看看有没有装多余的开发工具包。

另外分享一个安全审计的小技巧。我会定期用lynis跑一遍系统扫描,输出报告里会列出所有安全风险项和修复建议:

# 安装并运行lynis安全审计
dnf install -y lynis
lynis audit system --quick

# 查看完整报告
cat /var/log/lynis-report.dat | grep -E "warning|suggestion"

# 查看安全评分
grep hardening_index /var/log/lynis-report.dat

说到底,服务器运维没有银弹。物理机也好,云服务器也好,每一层都需要你真正去理解它的运行机制。我这些年最大的感悟就是——别迷信任何"最佳实践",所有架构决策都要基于你自己的业务场景和团队能力。别人家的方案再漂亮,不适合你就是不适合。多折腾,多记录,多复盘,这条路没有捷径。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/wo-zhe-teng-fu-wu-qi-ji-qun-de-xin-lu-li-cheng-cong-wu-li/

(0)
小编小编
上一篇 17小时前
下一篇 17小时前

相关推荐