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