Linux 从零部署项目实战指南(五):性能优化、监控与日志(完结篇)
本系列面向零基础或初中级开发者,手把手教你将一个项目从零部署到 Linux 服务器,并解决过程中遇到的常见问题。
一、前言
前四篇文章我们完成了从服务器选购到应用上线的完整流程。但部署上线只是开始,后续的运维同样重要。
本篇目标:掌握服务器性能监控、日志管理、安全加固三大核心运维技能,成为能独立管理服务器的开发者。
二、服务器性能监控
2.1 监控什么?
运维监控的核心指标,可以概括为 CPU、内存、磁盘、网络 四大维度:
┌─────────────────────────────────────────────────────────┐│ 服务器监控仪表盘 │├──────────────┬──────────────┬──────────────┬──────────────┤│ CPU 使用率 │ 内存占用 │ 磁盘空间 │ 网络流量 ││ ████████░░ │ ████████░░ │ ████████░░ │ ████████░░ ││ 78% │ 3.2G/4G │ 45G/60G │ 5Mbps ││ 正常 │ 正常 │ 正常 │ 正常 │├──────────────┴──────────────┴──────────────┴──────────────┤│ 进程数: 245 │ 运行时间: 15天 │ 负载: 1.2 │ 状态: ✅ │└───────────────────────────────────────────────────────────┘
2.2 命令行实时监控
# ========== CPU 和内存(实时刷新) ==========top# 按 q 退出# 常用快捷键:# 1 — 查看每个 CPU 核心的负载# P — 按 CPU 使用率排序# M — 按内存使用率排序# c — 显示完整命令路径# htop(更友好的 top,需要安装)sudo apt install -y htophtop# ========== 磁盘空间 ==========df -h# 查看各分区使用情况,重点关注 / 和 /data 的使用率# 查看目录大小du -sh /home/wwwdu -sh /var/logdu -sh /data# 按大小排序查看前 10 的大目录du -sh /* 2>/dev/null | sort -rh | head -10# ========== 内存 ==========free -h# 输出中 -/+ buffers/cache 那一行才是实际使用量# available 列是可用内存(包括缓存可回收部分)# ========== 网络流量 ==========# 查看网络接口流量ip -s link# 或使用 nload(需要安装)sudo apt install -y nloadnload# ========== 磁盘 I/O ==========sudo apt install -y iotopsudo iotop -o# -o 参数只显示正在 I/O 的进程# ========== 系统负载 ==========uptime# 输出示例:10:00:00 up 15 days, 3:20, 2 users, load average: 0.08, 0.03, 0.01# load average 的三个值分别代表 1分钟、5分钟、15分钟的平均负载# 负载值超过 CPU 核心数时说明系统过载
2.3 安装 Netdata 可视化监控
Netdata 是一个开源的实时监控工具,安装后通过浏览器访问,可以看到精美的仪表盘:
# 一键安装 Netdatabash <(curl -Ss https://my-netdata.io/kickstart.sh)# 安装完成后,Netdata 会监听在 19999 端口# 访问:http://yourdomain.com:19999# 配置 Nginx 反向代理(可选,建议放在内网或加密码)sudo tee /etc/nginx/sites-available/netdata << 'EOF'server { listen 8080; server_name _; location / { proxy_pass http://127.0.0.1:19999; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 添加简单密码认证(需要安装 apache2-utils) # auth_basic "Netdata Monitor"; # auth_basic_user_file /etc/nginx/.htpasswd; }}EOF# 如果不想暴露到公网,只允许本机访问sudo ufw allow from 127.0.0.1 to any port 19999
2.4 使用 Prometheus + Node Exporter 监控
对于更专业的监控方案,推荐 Prometheus 生态:
# 安装 Node Exporter(收集系统指标)sudo useradd --no-create-home --shell /bin/false node_exporterwget https://github.com/prometheus/node_exporter/releases/latest/download/node_exporter-*.linux-amd64.tar.gztar xzf node_exporter-*.linux-amd64.tar.gzsudo cp node_exporter-*/node_exporter /usr/local/bin/sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter# 创建 systemd 服务sudo tee /etc/systemd/system/node_exporter.service << 'EOF'[Unit]Description=Node ExporterAfter=network.target[Service]User=node_exporterGroup=node_exporterType=simpleExecStart=/usr/local/bin/node_exporter[Install]WantedBy=multi-user.targetEOF# 启动 Node Exportersudo systemctl daemon-reloadsudo systemctl start node_exportersudo systemctl enable node_exporter# 验证(默认监听 9100 端口)curl http://localhost:9100/metrics | head -20
2.5 设置资源告警阈值
掌握服务器资源的"红线"在哪里,对运维至关重要:
CPU 使用率: 正常: < 70% 警告: 70% - 90% 危险: > 90%(持续 5 分钟以上)内存使用率: 正常: < 70% 警告: 70% - 85% 危险: > 85%(开始使用 Swap,性能下降)磁盘使用率: 正常: < 70% 警告: 70% - 85% 危险: > 85%(需要立即清理或扩容)系统负载(Load Average): 正常: < CPU 核心数 × 0.7 警告: CPU 核心数 × 0.7 - 1.0 危险: > CPU 核心数(请求排队,响应变慢)
三、日志管理
3.1 日志分类
Linux 服务器上常见的日志:
/var/log/├── syslog # 系统日志(Ubuntu 默认)├── auth.log # 认证日志(SSH 登录记录)├── kern.log # 内核日志├── nginx/│ ├── access.log # Nginx 访问日志│ └── error.log # Nginx 错误日志├── mysql/│ └── error.log # MySQL 错误日志├── redis/│ └── redis-server.log # Redis 日志└── myproject/ # 项目日志 ├── app.log # 应用日志 └── access.log # 应用访问日志
3.2 日志查看技巧
# 实时查看日志(最常用)sudo tail -f /var/log/nginx/access.log# 查看最近 100 行sudo tail -n 100 /var/log/nginx/error.log# 查看今天的日志sudo journalctl -u mywebapi --since today# 查看特定时间段的日志sudo journalctl -u mywebapi --since "2026-07-28 10:00:00" --until "2026-07-28 12:00:00"# 模糊搜索日志sudo grep "ERROR" /var/log/nginx/error.logsudo grep -r "500" /var/log/nginx/# 统计错误次数sudo grep "ERROR" /var/log/nginx/error.log | wc -l# 统计 IP 访问次数(排错时很有用)sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10# 输出示例:# 12345 123.123.123.123 ← 这个 IP 访问了 12345 次(可能是在攻击)# 567 192.168.1.100# 234 10.0.0.1# 统计 HTTP 状态码sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn# 输出示例:# 9876 200 ← 正常# 123 404 ← 页面不存在# 45 500 ← 服务器错误# 12 502 ← 网关错误
3.3 日志轮转(防止日志撑爆磁盘)
日志文件会不断增长,必须配置日志轮转(logrotate)自动切割和清理旧日志:
# 查看系统的 logrotate 配置ls -la /etc/logrotate.d/# 添加项目日志的轮转配置sudo tee /etc/logrotate.d/myproject << 'EOF'/home/www/myproject/logs/*.log { daily # 每天轮转一次 rotate 7 # 保留最近 7 天的日志 compress # 压缩旧日志(.gz) delaycompress # 压缩延期一天,方便查看昨天的日志 missingok # 如果日志文件不存在,不报错 notifempty # 如果日志为空,不轮转 copytruncate # 复制并截断原文件(不影响正在写入的进程) dateext # 在文件名中添加日期 dateformat -%Y%m%d # 日期格式}EOF# 手动测试 logrotate 配置sudo logrotate -d /etc/logrotate.d/myproject# -d 是调试模式,不会实际执行# 强制执行sudo logrotate -f /etc/logrotate.d/myproject# 查看 logrotate 执行状态sudo cat /var/lib/logrotate/status
3.4 使用 journalctl 管理 systemd 日志
# 查看应用日志sudo journalctl -u mywebapi# 实时查看sudo journalctl -u mywebapi -f# 查看最近 100 行sudo journalctl -u mywebapi -n 100# 限制日志大小(防止日志占用过多磁盘)sudo journalctl --vacuum-size=500M # 保留最近 500MB 日志sudo journalctl --vacuum-time=30d # 保留最近 30 天的日志# 永久限制日志大小sudo vim /etc/systemd/journald.conf# 修改以下行:SystemMaxUse=500M # 日志最大占用 500MBMaxFileSec=30 # 日志文件最大保留 30 天# 重启 journald 服务sudo systemctl restart systemd-journald
四、性能优化
4.1 系统层面优化
# 优化 swappiness(减少磁盘交换,提升响应速度)echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.confsudo sysctl -p# 优化文件描述符限制echo 'fs.file-max=100000' | sudo tee -a /etc/sysctl.confsudo sysctl -p# 禁用不必要的服务(释放资源)sudo systemctl list-unit-files --state=enabled | grep -E 'bluetooth|avahi|cups'# 以下服务如果不需要可以禁用sudo systemctl disable bluetooth # 服务器不需要蓝牙sudo systemctl disable avahi-daemon # 不需要零配置网络sudo systemctl disable cups # 不需要打印服务
4.2 Nginx 优化
# 编辑 /etc/nginx/nginx.confsudo vim /etc/nginx/nginx.conf
# 工作进程数 = CPU 核心数worker_processes auto;# 每个进程的最大连接数worker_connections 1024;# 使用 epoll(Linux 高性能 I/O)events { use epoll; multi_accept on;}# 开启 gzip 压缩gzip on;gzip_min_length 1000;gzip_comp_level 5;gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;gzip_vary on;gzip_proxied any;# 开启静态文件缓存# 在站点配置中:location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ { expires 30d; add_header Cache-Control "public, immutable"; access_log off;}# 开启 HTTP/2(需要 HTTPS)# 在 server 块中添加:listen 443 ssl http2;
# 测试配置并重载sudo nginx -t && sudo systemctl reload nginx
4.3 MySQL 优化
# 使用 MySQLTuner 工具分析数据库性能wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.plperl mysqltuner.pl --user root --pass 你的数据库密码
根据 MySQLTuner 的推荐,调整 MySQL 配置:
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 根据服务器内存调整(2G 服务器推荐值)# InnoDB 缓冲池大小(最重要的参数,建议总内存的 50%)innodb_buffer_pool_size = 1G# 日志文件大小innodb_log_file_size = 256M# 最大连接数(根据应用需求调整)max_connections = 100# 连接超时(单位:秒)wait_timeout = 600interactive_timeout = 600# 表缓存table_open_cache = 2000# 临时表大小tmp_table_size = 64Mmax_heap_table_size = 64M
# 重启 MySQLsudo systemctl restart mysql
4.4 Redis 优化
# 编辑 /etc/redis/redis.confsudo vim /etc/redis/redis.conf
# 内存限制maxmemory 512mb# 淘汰策略(推荐 allkeys-lru)maxmemory-policy allkeys-lru# 关闭 RDB 持久化(如果只做缓存,不需要持久化)# save "" # 注释掉所有 save 选项# 或者保留 AOF 但调整频率appendfsync everysecno-appendfsync-on-rewrite yes
# 重启 Redissudo systemctl restart redis-server
4.5 .NET 应用优化
# 在 Program.cs 中添加性能配置
var builder = WebApplication.CreateBuilder(args);// 配置 Kestrel 服务器builder.WebHost.ConfigureKestrel(options =>{ // 最大并发连接数 options.Limits.MaxConcurrentConnections = 100; options.Limits.MaxConcurrentUpgradedConnections = 100; // 请求体大小限制(按需调整) options.Limits.MaxRequestBodySize = 100 * 1024 * 1024; // 100MB // 保持连接超时 options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);});// 启用响应压缩builder.Services.AddResponseCompression(options =>{ options.EnableForHttps = true; options.Providers.Add<BrotliCompressionProvider>(); options.Providers.Add<GzipCompressionProvider>();});// 配置 JSON 序列化builder.Services.ConfigureHttpJsonOptions(options =>{ options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;});
五、安全加固
5.1 安全基线检查清单
# ========== 1. 检查是否有未授权的用户 ==========cat /etc/passwd | grep -E "/bin/bash|/bin/sh"# 确认所有用户都是你创建的,没有可疑用户# ========== 2. 检查 sudo 权限 ==========sudo cat /etc/sudoers | grep -E "^[^#]"# 确认只有必要用户有 sudo 权限# ========== 3. 检查 SSH 配置 ==========sudo cat /etc/ssh/sshd_config | grep -E "^(PermitRootLogin|PasswordAuthentication|Port|PubkeyAuthentication)"# 确认:# PermitRootLogin no(禁止 root 直接登录)# PasswordAuthentication no(禁用密码登录)# PubkeyAuthentication yes(仅允许密钥登录)# ========== 4. 检查防火墙规则 ==========sudo ufw status verbose# 确认只开放了必要端口# ========== 5. 检查监听端口 ==========sudo ss -tlnp# 确认没有未授权的端口在监听# ========== 6. 检查 Fail2ban 状态 ==========sudo fail2ban-client status sshd# 查看被封禁的 IP 数量# ========== 7. 检查系统更新 ==========sudo apt list --upgradable# 如果有安全更新,及时安装sudo apt upgrade -y
5.2 自动安全扫描
# 安装 Lynis 安全审计工具sudo apt install -y lynis# 执行安全审计sudo lynis audit system# 查看审计报告sudo lynis show details
5.3 配置自动备份
除了数据库备份,还要备份配置文件和项目代码:
# 创建完整的备份脚本sudo tee /usr/local/bin/backup-all.sh << 'EOF'#!/bin/bashBACKUP_DIR="/data/backup"DATE=$(date +%Y%m%d_%H%M%S)# 1. 备份 MySQL 数据库echo "[1/3] 备份数据库..."mysqldump -u myapp -pYourAppPassword2024! myproject_db | \ gzip > $BACKUP_DIR/db/myproject_db_$DATE.sql.gz# 2. 备份 Nginx 配置echo "[2/3] 备份 Nginx 配置..."tar czf $BACKUP_DIR/config/nginx-config_$DATE.tar.gz /etc/nginx/# 3. 备份项目代码echo "[3/3] 备份项目代码..."tar czf $BACKUP_DIR/code/myproject-source_$DATE.tar.gz /home/www/myproject/source# 4. 删除 30 天前的旧备份echo "清理旧备份..."find $BACKUP_DIR -name "*.gz" -mtime +30 -deleteecho "备份完成: $DATE"EOFsudo chmod +x /usr/local/bin/backup-all.sh# 配置定时任务:每天凌晨 2 点执行sudo crontab -e# 添加:0 2 * * * /usr/local/bin/backup-all.sh >> /var/log/backup-all.log 2>&1
5.4 监控关键文件变化
使用 AIDE(Advanced Intrusion Detection Environment)监控关键文件是否被篡改:
# 安装 AIDEsudo apt install -y aide# 初始化数据库sudo aideinit# 移动数据库到默认位置sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db# 运行检查(对比文件状态)sudo aide --check# 配置定时检查(每天凌晨 4 点)sudo crontab -e# 添加:0 4 * * * /usr/bin/aide --check | mail -s "AIDE Report" admin@yourdomain.com
六、系统健康检查脚本
创建一个一键检查脚本,可以快速了解服务器整体状态:
sudo tee /usr/local/bin/health-check.sh << 'EOF'#!/bin/bash# ==========================================# 服务器健康检查脚本# 用法:sudo bash health-check.sh# ==========================================RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'NC='\033[0m'echo "=========================================="echo " 服务器健康检查报告"echo " 时间:$(date)"echo "=========================================="# CPU 检查echo -n "CPU 使用率: "CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')echo "$CPU%"if (( $(echo "$CPU > 80" | bc -l) )); then echo -e " ${RED}⚠ CPU 使用率过高${NC}"elif (( $(echo "$CPU > 60" | bc -l) )); then echo -e " ${YELLOW}⚡ CPU 使用率偏高${NC}"else echo -e " ${GREEN}✓ 正常${NC}"fi# 内存检查echo -n "内存使用率: "MEM=$(free | grep Mem | awk '{print $3/$2 * 100.0}')echo "${MEM%.*}%"if (( $(echo "$MEM > 80" | bc -l) )); then echo -e " ${RED}⚠ 内存不足${NC}"elif (( $(echo "$MEM > 60" | bc -l) )); then echo -e " ${YELLOW}⚡ 内存偏高${NC}"else echo -e " ${GREEN}✓ 正常${NC}"fi# 磁盘检查echo "磁盘使用率:"df -h | grep -E "^/dev|/data" | awk '{print " " $5 " " $6}'# 服务检查echo -n "Nginx: "systemctl is-active nginx > /dev/null && echo -e "${GREEN}运行中${NC}" || echo -e "${RED}已停止${NC}"echo -n "MySQL: "systemctl is-active mysql > /dev/null && echo -e "${GREEN}运行中${NC}" || echo -e "${RED}已停止${NC}"echo -n "Redis: "systemctl is-active redis-server > /dev/null && echo -e "${GREEN}运行中${NC}" || echo -e "${RED}已停止${NC}"echo -n "应用: "systemctl is-active mywebapi > /dev/null && echo -e "${GREEN}运行中${NC}" || echo -e "${RED}已停止${NC}"# 监听端口echo "监听端口:"sudo ss -tlnp | grep -E "80|443|5000|3306|6379" | awk '{print " " $4}'# 系统负载echo "系统负载: $(uptime | awk -F'load average:' '{print $2}')"# 在线时间echo "运行时间: $(uptime -p | sed 's/up //')"# Fail2ban 状态BANNED=$(sudo fail2ban-client status sshd 2>/dev/null | grep "Banned IP list" | awk '{print $NF}')echo "Fail2ban 封禁数: ${BANNED:-0}"# 最后登录echo "最后 5 次登录失败:"sudo lastb 2>/dev/null | head -3echo "=========================================="echo " 检查完成"echo "=========================================="EOFsudo chmod +x /usr/local/bin/health-check.sh# 运行检查脚本sudo bash /usr/local/bin/health-check.sh
七、常见问题
❓ Q1:服务器 CPU 使用率一直 100%
# 找出 CPU 使用率最高的进程top -c -b -n 1 | head -20# 或者使用ps aux --sort=-%cpu | head -10# 常见原因:# ① 网站被大量爬虫抓取# ② 代码中有死循环或无限递归# ③ 数据库查询没有索引,导致全表扫描# ④ 受到 CC 攻击# 如果是爬虫问题,可以封禁 IPsudo ufw deny from 爬虫IP# 或者在 Nginx 中限制访问频率
❓ Q2:磁盘空间满了怎么办?
# 紧急释放空间sudo apt clean # 清理 apt 缓存sudo journalctl --vacuum-size=200M # 清理 journal 日志sudo rm -rf /tmp/* # 清理临时文件sudo du -sh /var/log/* # 查看日志占用sudo truncate -s 0 /var/log/nginx/access.log # 清空大日志文件# 如果还是不够,扩容数据盘# 云平台控制台 → 磁盘 → 扩容 → 然后执行:sudo growpart /dev/vdb 1sudo resize2fs /dev/vdb1
❓ Q3:网站访问慢,如何定位瓶颈?
# ① 检查网络延迟ping yourdomain.com# ② 检查 DNS 解析时间dig yourdomain.com | grep "Query time"# ③ 检查页面加载时间curl -w "TCP: %{time_connect}s, SSL: %{time_starttransfer}s, Total: %{time_total}s\n" -o /dev/null -s https://yourdomain.com# ④ 检查数据库查询时间# 开启慢查询日志sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf# 添加:slow_query_log = 1slow_query_log_file = /var/log/mysql/slow.loglong_query_time = 2# 然后分析慢查询sudo tail -f /var/log/mysql/slow.log
❓ Q4:如何防止服务器被 DDoS 攻击?
# ① Nginx 限制单个 IP 的连接数# 在 nginx.conf 的 http 块中添加:limit_conn_zone $binary_remote_addr zone=addr:10m;limit_req_zone $binary_remote_addr zone=one:10m rate=30r/s;# 在站点配置的 server 块中添加:limit_conn addr 10; # 每个 IP 最多 10 个并发连接limit_req zone=one burst=20; # 每秒最多 30 个请求,突发允许 20 个# ② 使用 Cloudflare 等 CDN 防护# 开启 Under Attack 模式# ③ 安装 Fail2ban(已配置)# 添加 Nginx 防护规则sudo tee /etc/fail2ban/jail.d/nginx-http.conf << 'EOF'[nginx-http-auth]enabled = trueport = http,httpsfilter = nginx-http-authlogpath = /var/log/nginx/error.logmaxretry = 5findtime = 600bantime = 3600EOFsudo systemctl restart fail2ban
❓ Q5:如何查看谁在访问服务器?
# 查看当前登录的用户whow# 查看最近的 SSH 登录记录last | head -20# 查看失败的登录尝试sudo lastb | head -20# 查看 Nginx 实时访问日志sudo tail -f /var/log/nginx/access.log | awk '{print $1, $7, $9}'
八、系列总结
运维好习惯清单
每天: ✅ 查看一次服务器的健康状态(health-check.sh) ✅ 查看 Nginx 错误日志(tail -f /var/log/nginx/error.log)每周: ✅ 检查系统更新(sudo apt update && sudo apt upgrade -y) ✅ 检查磁盘空间(df -h) ✅ 检查 Fail2ban 封禁情况(sudo fail2ban-client status sshd)每月: ✅ 全量备份(数据库 + 配置 + 代码) ✅ 清理旧日志和备份 ✅ 检查 SSL 证书到期时间 ✅ 审查所有用户和权限不定期: ✅ 手动测试备份恢复流程 ✅ 安全审计(lynis audit system) ✅ 检查应用性能,优化慢查询 ✅ 更新系统文档
完整系列回顾
| | |
|---|
| 一:服务器选购与环境初始化 | | ssh |
| 二:Nginx + MySQL + Redis | | nginx、mysql_secure_installation、redis-cli |
| 三:实战部署 .NET Web 应用 | | dotnet publish |
| 四:域名、HTTPS、CI/CD | | certbot |
| 五:性能优化、监控与日志 | | netdata |
写在最后
从买服务器到配环境,从部署应用到绑定域名,从手动更新到自动发布,从裸奔到安全加固——这五篇文章带你走完了一个项目的完整部署生命周期。
记住三个核心原则:
- 安全第一:密钥登录、防火墙、Fail2ban、定期备份,少一步都不行
- 自动化:能用脚本就别手动,能用 CI/CD 就别 SSH 上去敲命令
- 监控预警
部署运维不是一次性的工作,而是持续的过程。希望你掌握了这些技能后,能更自信地管理自己的服务器和项目。
如果你在操作过程中遇到任何问题,欢迎在评论区留言交流!
📌 IT在线自学,陪你从菜鸟到大神,关注我第一时间获取最新教程!