Python 后端开发技术博客专栏 | 第22篇:Linux 系统运维与网络基础 -- 后端工程师必备技能
Python技术博客专栏 - 模块七微服务架构与容器化部署作者耿雨飞 | 难度中级 | 阅读时间45分钟导读无论你用的是 FastAPI 还是 Django你的代码最终都跑在 Linux 上无论你的微服务拆得多精细它们之间的通信都依赖网络协议。Linux 命令和网络知识是后端工程师的空气——平时感觉不到它的存在但一旦出了问题服务器 CPU 飙升、接口超时、DNS 解析失败不会用就寸步难行。本篇将系统梳理后端开发中最高频使用的 Linux 命令、Shell 脚本编写技巧、Systemd 服务管理、TCP/IP 和 HTTP 协议核心知识、Nginx 配置实战以及安全运维基础。不追求大而全只讲面试会问、工作会用的内容。学习目标完成本篇学习后你将能够熟练运用 Linux 命令排查服务器性能问题编写实用的 Shell 脚本完成运维自动化任务深入理解 TCP 三次握手/四次挥手、TLS 握手流程掌握 Nginx 反向代理、负载均衡的配置方法建立基本的服务器安全防护意识一、Linux 常用命令1.1 文件管理四剑客find——按条件搜索文件# 查找7天前修改的日志文件find/var/log-name*.log-mtime7-typef# 查找大于100MB的文件find/-size100M-typef2/dev/null# 查找并删除临时文件-exec 执行命令find/tmp-name*.tmp-mtime3-execrm-f{}\;# 查找Python项目中所有包含 TODO 的文件find.-name*.py-execgrep-lTODO{}\;grep——文本内容搜索# 递归搜索目录下所有文件grep-rndatabase_url/app/config/# 正则匹配-E 扩展正则grep-EERROR|CRITICAL/var/log/app.log# 排除目录grep-rnimport--include*.py--exclude-dir.venv# 统计匹配行数grep-c500access.log# 显示匹配前后上下文grep-B3-A5Traceback/var/log/app.logawk——列处理与统计# 打印第1列和第4列默认空格分隔awk{print $1, $4}access.log# 统计HTTP状态码分布awk{print $9}access.log|sort|uniq-c|sort-rn# 计算响应时间平均值假设第10列是响应时间awk{sum$10; count} END {print sum/count}access.log# 按条件过滤只看5xx错误awk$9 500 {print $0}access.logsed——流式文本编辑# 替换文件中的字符串-i 原地修改sed-is/old_host/new_host/gconfig.yaml# 删除空行sed-i/^$/dfile.txt# 在第5行后插入内容sed-i5a\new_line_contentfile.txt# 打印第10-20行sed-n10,20plarge_file.log1.2 进程管理命令用途常用姿势ps aux查看所有进程ps auxtop/htop实时监控进程按 M 按内存排序P 按 CPU 排序kill -9 PID强制杀进程慎用优先用kill -15SIGTERMkill -15 PID优雅终止给进程机会处理完当前请求nohup cmd 后台运行忽略挂断nohup python app.py app.log 21 lsof -i :8000查看端口占用排查端口冲突strace -p PID跟踪系统调用排查进程卡死原因信号Signal对比SIGTERM (15)优雅终止进程可以捕获并清理资源SIGKILL (9)强制杀死进程无法捕获可能导致数据丢失SIGHUP (1)终端挂断很多守护进程用它来重载配置SIGUSR1/USR2用户自定义常用于日志轮转1.3 网络诊断# ss查看网络连接替代 netstatss-tlnp# TCP监听端口 进程名ss-s# 连接状态统计ss state time-wait|wc-l# TIME_WAIT 数量# tcpdump抓包分析tcpdump-ieth0 port80-wcapture.pcap# 抓HTTP包tcpdump-ianyhost10.0.0.5-nn# 抓特定主机流量tcpdump-ieth0tcp[tcpflags] tcp-syn ! 0# 只抓SYN包# curlHTTP 请求调试curl-vhttps://api.example.com/health# 显示详细握手过程curl-o/dev/null-s-wtime_total: %{time_total}s\nURL# 只看耗时curl-XPOST-HContent-Type: application/json\-d{key:value}http://localhost:8000/api# dig/nslookupDNS 解析digexample.com# 查看A记录digexample.com trace# 追踪完整解析路径1.4 系统资源监控# 内存free -h$free-htotal usedfreeshared buff/cache available Mem: 16G8.2G1.5G 512M6.3G7.1G Swap: 4G 200M3.8G# 关键指标看 available 而非 freebuff/cache 可回收# 磁盘df -h / du -shdf-h# 各分区使用情况du-sh/var/log/*# 各目录大小# IOiostat -x 1iostat-x1# 每秒刷新关注 %util 和 await# %util 80% 表示磁盘接近饱和# await 10ms 表示IO等待严重# 系统负载uptime / vmstatuptime# 1/5/15分钟平均负载vmstat1# 每秒刷新r(运行队列) b(阻塞) si/so(swap)性能排查五步法top看 CPU 和内存的大致情况iostat -x 1排查磁盘 IO 瓶颈ss -s看网络连接状态是否异常dmesg | tail看内核是否有 OOM 等错误strace -p PID定位具体进程卡在什么系统调用上二、Shell 脚本编写2.1 基础语法#!/bin/bashset-euopipefail# 严格模式出错即退出、未定义变量报错、管道错误传播# 变量APP_NAMEweb-appLOG_DIR/var/log/${APP_NAME}DATE$(date%Y%m%d)# 条件判断if[-f${LOG_DIR}/app.log];thenechoLog file existselif[-d${LOG_DIR}];thenechoLog directory exists but no log fileelsemkdir-p${LOG_DIR}fi# 循环forserverinweb-01 web-02 web-03;doechoChecking${server}...ssh${server}uptimedone# 函数check_service(){localservice_name$1ifsystemctl is-active--quiet${service_name};thenecho[OK]${service_name}is runningreturn0elseecho[FAIL]${service_name}is not runningreturn1fi}check_service nginx check_service postgresqlset -euo pipefail的含义-e任何命令失败非零退出立即退出脚本-u引用未定义的变量时报错而非当空字符串-o pipefail管道中任一命令失败则整个管道失败这三个选项是生产脚本的必备设置能避免大量隐蔽 Bug。2.2 实用脚本模板日志清理脚本#!/bin/bashset-euopipefailLOG_DIR/var/log/myappKEEP_DAYS30MAX_SIZE_MB500echo[$(date)] Starting log cleanup...# 删除超过30天的日志find${LOG_DIR}-name*.log-mtime${KEEP_DAYS}-deleteechoDeleted logs older than${KEEP_DAYS}days# 压缩超过500MB的日志保留原始文件名.gzfind${LOG_DIR}-name*.log-size${MAX_SIZE_MB}M\-execgzip{}\;echoCompressed logs larger than${MAX_SIZE_MB}MB# 报告当前磁盘使用echoCurrent disk usage:$(du-sh${LOG_DIR}|cut-f1)服务健康检查脚本#!/bin/bashset-euopipefailSERVICES(nginxpostgresqlredis-server)ENDPOINTS(http://localhost:8000/healthhttp://localhost:8001/health)ALERT_WEBHOOKhttps://hooks.slack.com/services/xxxalert(){localmessage$1curl-s-XPOST${ALERT_WEBHOOK}\-HContent-Type: application/json\-d{\text\:\[ALERT]${message}\}/dev/null}# 检查 systemd 服务forsvcin${SERVICES[]};doif!systemctl is-active--quiet${svc};thenalert${svc}is down on$(hostname)systemctl restart${svc}# 尝试自动恢复fidone# 检查 HTTP 端点forurlin${ENDPOINTS[]};dostatus$(curl-s-o/dev/null-w%{http_code}${url}||echo000)if[${status}!200];thenalertHealth check failed:${url}returned${status}fidone三、Systemd 服务管理3.1 编写 Service 文件Systemd 是现代 LinuxCentOS 7、Ubuntu 16.04的 init 系统管理所有系统服务的启动和监控。# /etc/systemd/system/myapp.service [Unit] DescriptionMy Python Web Application Afternetwork.target postgresql.service redis.service Wantspostgresql.service redis.service [Service] Typeexec Userappuser Groupappuser WorkingDirectory/opt/myapp EnvironmentAPP_ENVproduction EnvironmentFile/opt/myapp/.env ExecStart/opt/myapp/.venv/bin/uvicorn main:app \ --host 0.0.0.0 --port 8000 --workers 4 ExecReload/bin/kill -HUP $MAINPID ExecStop/bin/kill -TERM $MAINPID Restarton-failure RestartSec5 StartLimitBurst5 StartLimitIntervalSec60 # 安全加固 NoNewPrivilegestrue ProtectSystemstrict ProtectHometrue ReadWritePaths/var/log/myapp /opt/myapp/data # 资源限制 LimitNOFILE65536 MemoryMax2G [Install] WantedBymulti-user.target关键配置说明配置项含义After在指定服务之后启动只控制顺序不强制依赖Wants弱依赖依赖不存在也不影响本服务Typeexec主进程启动即视为服务就绪适合 uvicorn/gunicornRestarton-failure非正常退出时自动重启RestartSec5重启间隔5秒StartLimitBurst560秒内最多重启5次防止无限重启ProtectSystemstrict只读挂载文件系统安全加固LimitNOFILE65536最大文件描述符数3.2 常用管理命令# 生命周期管理systemctl start myapp# 启动systemctl stop myapp# 停止systemctl restart myapp# 重启systemctl reload myapp# 重载配置不中断服务systemctlenablemyapp# 开机自启systemctl disable myapp# 取消开机自启# 状态检查systemctl status myapp# 详细状态包括最近日志systemctl is-active myapp# 是否在运行systemctl is-enabled myapp# 是否开机自启# 修改 service 文件后必须执行systemctl daemon-reload# 日志查看journalctljournalctl-umyapp-f# 实时跟踪日志journalctl-umyapp--since1h ago# 最近1小时journalctl-umyapp-perr# 只看错误级别journalctl-umyapp --no-pager-n100# 最近100行四、网络基础4.1 TCP/IP 协议栈应用层 HTTP, gRPC, DNS, SMTP ↕ 传输层 TCP可靠/ UDP快速 ↕ 网络层 IP, ICMP路由寻址 ↕ 链路层 Ethernet, WiFi物理传输4.2 TCP 三次握手与四次挥手三次握手建立连接Client Server │ │ │──── SYN (seqx) ──────────→│ ① 客户端发起连接请求 │ │ │←── SYNACK (seqy,ackx1)─│ ② 服务端确认并同步 │ │ │──── ACK (acky1) ─────────→│ ③ 客户端确认 │ │ │ 连接已建立 │为什么是三次而非两次防止旧的重复连接请求突然到达服务端导致服务端白白建立无效连接。第三次握手让客户端确认我确实想建立这个连接。四次挥手关闭连接Client Server │ │ │──── FIN (sequ) ───────────→│ ① 客户端请求关闭 │ │ │←── ACK (acku1) ──────────│ ② 服务端确认可能还有数据要发 │ │ │←── FIN (seqv) ────────────│ ③ 服务端数据发完也请求关闭 │ │ │──── ACK (ackv1) ─────────→│ ④ 客户端确认 │ │ │ TIME_WAIT (2MSL) │ 客户端等待2MSL后关闭为什么是四次而非三次TCP 是全双工的每个方向需要独立关闭。服务端收到 FIN 后可能还有数据要发送所以 ACK 和 FIN 分开发送。TIME_WAIT 的作用确保最后的 ACK 能到达对端如果丢了对端会重发 FIN让网络中残留的旧报文消亡避免影响新连接生产中 TIME_WAIT 过多的处理# 查看 TIME_WAIT 数量ss-s|grepTIME-WAIT# 内核参数调优/etc/sysctl.confnet.ipv4.tcp_tw_reuse1# 允许复用TIME_WAIT连接net.ipv4.tcp_max_tw_buckets20000# TIME_WAIT最大数量net.ipv4.tcp_fin_timeout30# FIN_WAIT_2 超时时间4.3 HTTP/HTTPS 协议HTTP/1.1 vs HTTP/2 vs HTTP/3特性HTTP/1.1HTTP/2HTTP/3传输层TCPTCPQUIC (UDP)多路复用无队头阻塞有二进制帧有头部压缩无HPACKQPACK服务器推送无支持支持连接建立TCP 3次 TLS 2次同 HTTP/1.10-RTT首次1-RTT队头阻塞应用层传输层传输层仍有完全解决TLS 1.3 握手流程1-RTTClient Server │ │ │── ClientHello ───────────────────→│ │ (支持的密码套件、密钥共享参数) │ │ │ │←─ ServerHello Certificate ─────│ │ (选定密码套件、证书、密钥共享) │ │ │ ← 此时已可计算对称密钥 │── Finished ──────────────────────→│ │ │ │←─ Finished ──────────────────────│ │ │ │ 开始加密传输共1个RTT │TLS 1.3 相比 TLS 1.2 的改进握手从 2-RTT 降为 1-RTT首次支持 0-RTT重连移除不安全的算法RSA 密钥交换、RC4、SHA-1前向保密Forward Secrecy成为默认要求4.4 DNS 解析流程用户输入 www.example.com │ ▼ 浏览器 DNS 缓存 → 命中则直接返回 │ Miss ▼ 操作系统 DNS 缓存 (/etc/hosts) │ Miss ▼ 本地 DNS 服务器递归解析器 │ Miss ▼ 根域名服务器 → 返回 .com 的 NS 地址 │ ▼ .com 顶级域名服务器 → 返回 example.com 的 NS 地址 │ ▼ example.com 权威服务器 → 返回 www.example.com 的 A 记录IPDNS 记录类型A域名 → IPv4 地址AAAA域名 → IPv6 地址CNAME域名别名 → 另一个域名MX邮件交换记录TXT文本记录常用于域名验证、SPFNS指定域名的权威DNS服务器4.5 正向代理 vs 反向代理正向代理代理客户端 反向代理代理服务端 Client → [Proxy] → Server Client → [Reverse Proxy] → Server - 客户端知道代理的存在 - 客户端不知道代理的存在 - 代理代表客户端发请求 - 代理代表服务端接请求 - 用途翻墙、缓存、访问控制 - 用途负载均衡、SSL终止、缓存 - 例Squid、V2Ray - 例Nginx、HAProxy、Envoy4.6 Nginx 配置实战# /etc/nginx/conf.d/myapp.conf # 上游服务组负载均衡 upstream myapp_backend { least_conn; # 最少连接策略 server 127.0.0.1:8000 weight3; server 127.0.0.1:8001 weight2; server 127.0.0.1:8002 backup; # 备用节点 keepalive 32; # 与上游保持长连接 } server { listen 443 ssl http2; server_name api.example.com; # SSL 配置 ssl_certificate /etc/ssl/certs/example.com.pem; ssl_certificate_key /etc/ssl/private/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 安全头 add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Strict-Transport-Security max-age31536000 always; # API 反向代理 location /api/ { proxy_pass http://myapp_backend; 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 5s; proxy_read_timeout 30s; proxy_send_timeout 10s; # 错误时切换到下一个上游 proxy_next_upstream error timeout http_502 http_503; } # 静态资源直接由Nginx提供 location /static/ { alias /opt/myapp/static/; expires 30d; add_header Cache-Control public, immutable; } # 健康检查端点不记录日志 location /health { proxy_pass http://myapp_backend; access_log off; } } # HTTP → HTTPS 重定向 server { listen 80; server_name api.example.com; return 301 https://$server_name$request_uri; }Nginx 负载均衡策略策略指令特点轮询默认平均分配加权轮询weightN按权重分配最少连接least_conn优先分配给连接数少的IP哈希ip_hash同一客户端固定后端会话保持一致性哈希hash $key consistent缓存友好五、安全运维5.1 SSH 密钥管理# 生成密钥对Ed25519 比 RSA 更安全更快ssh-keygen-ted25519-Cgengyufeicompany.com# 将公钥部署到服务器ssh-copy-id-i~/.ssh/id_ed25519.pub userserver# SSH 配置文件~/.ssh/configHost prod-* User deploy IdentityFile ~/.ssh/id_ed25519 StrictHostKeyCheckingyesHost prod-web-01 HostName10.0.1.10 Host prod-web-02 HostName10.0.1.11SSH 安全加固/etc/ssh/sshd_config# 禁止密码登录只允许密钥PasswordAuthentication no PubkeyAuthenticationyes# 禁止 root 直接登录PermitRootLogin no# 限制登录用户AllowUsers deploy appuser# 修改默认端口减少扫描攻击Port22022# 超时断开ClientAliveInterval300ClientAliveCountMax25.2 防火墙配置firewalldCentOS 7 / RHEL 8# 查看当前规则firewall-cmd --list-all# 开放端口firewall-cmd--permanent--add-port443/tcp firewall-cmd--permanent--add-port8000/tcp# 只允许特定IP访问firewall-cmd--permanent--add-rich-rule rule familyipv4 source address10.0.0.0/24 port port5432 protocoltcp accept# 重载生效firewall-cmd--reloadiptables底层适合精细控制# 基本策略默认拒绝入站iptables-PINPUT DROP iptables-PFORWARD DROP iptables-POUTPUT ACCEPT# 允许已建立的连接iptables-AINPUT-mstate--stateESTABLISHED,RELATED-jACCEPT# 允许本地回环iptables-AINPUT-ilo-jACCEPT# 允许SSH限制源IPiptables-AINPUT-s10.0.0.0/24-ptcp--dport22022-jACCEPT# 允许HTTP/HTTPSiptables-AINPUT-ptcp--dport80-jACCEPT iptables-AINPUT-ptcp--dport443-jACCEPT# 限制连接速率防DDoSiptables-AINPUT-ptcp--dport80-mlimit--limit100/s --limit-burst200-jACCEPT5.3 日志审计# 查看登录记录last# 成功登录lastb# 失败登录who# 当前在线用户# 查看sudo操作记录grepsudo/var/log/auth.log# auditd 审计系统# 监控关键文件修改auditctl-w/etc/passwd-pwa-kuser_modify auditctl-w/etc/ssh/sshd_config-pwa-kssh_config# 查看审计日志ausearch-kuser_modify--starttoday5.4 容器安全基线检查项推荐做法原因运行用户非 rootUSER appuser防止容器逃逸获得宿主机root基础镜像定期更新扫描漏洞CVE漏洞修复能力限制--cap-drop ALL --cap-add NET_BIND_SERVICE最小权限原则只读文件系统--read-only tmpfs 挂载防止容器内被篡改资源限制--memory --cpus防止单容器耗尽主机资源镜像签名Docker Content Trust确保镜像来源可信网络隔离自定义network最小连通性减少攻击面面试高频题汇总Q1如何排查一个 Linux 服务器的性能问题系统性排查方法USE 方法对每种资源检查 Utilization使用率、Saturation饱和度、Errors错误。实际排查步骤先看大盘top或htopCPU 使用率高看哪个进程占用最多内存使用率高看是否有内存泄漏Load Average 高和 CPU 核数对比CPU 瓶颈top→ 按 P 排序 → 找到高 CPU 进程perf top或py-spyPython 进程找热点函数vmstat 1→ 看r列运行队列长度内存瓶颈free -h→ 看 available 是否充足vmstat 1→ 看si/soswap in/out非零说明内存不足dmesg | grep OOM→ 是否触发了 OOM KillerIO 瓶颈iostat -x 1→%util 80%表示磁盘饱和iotop→ 找出高 IO 的进程await 10ms表示 IO 等待严重网络瓶颈ss -s→ 大量 TIME_WAIT 或 CLOSE_WAIT 异常sar -n DEV 1→ 网络带宽是否打满netstat -s | grep retransmit→ 丢包重传Q2HTTP 和 HTTPS 的区别是什么TLS 握手的流程核心区别维度HTTPHTTPS协议明文传输TLS 加密传输端口80443安全性可被窃听、篡改机密性完整性身份认证性能无额外开销TLS握手增加1-2 RTT证书不需要需要CA签发证书TLS 1.3 握手1-RTTClient → ServerClientHello支持的密码套件 密钥共享参数Server → ClientServerHello 证书 密钥共享 FinishedClient 验证证书CA链验证→ 计算对称密钥 → 发送 Finished握手完成后续全部对称加密传输TLS 保证了三个安全属性机密性对称加密AES-GCM/ChaCha20完整性MAC消息认证码身份认证数字证书CA签名 → 证明服务器身份Q3Nginx 的反向代理是如何工作的工作流程客户端发送请求到 Nginx如https://api.example.com/api/usersNginx 根据server_name和location匹配规则将请求转发到proxy_pass指定的上游服务如http://127.0.0.1:8000Nginx 收到上游响应后返回给客户端Nginx 在反向代理中的核心价值负载均衡多个上游实例间分发流量SSL终止Nginx处理HTTPS解密后端只需HTTP静态资源分离静态文件直接由Nginx返回不经过应用服务器缓存缓存上游响应减少后端压力连接管理与后端保持长连接keepalive减少TCP开销安全防护隐藏后端真实地址、限流、防DDoS关键配置proxy_set_header X-Real-IP传递真实客户端IPproxy_next_upstream后端出错时自动切换到下一个upstream keepalive与后端保持连接复用Q4TCP 三次握手和四次挥手的过程三次握手SYN客户端发送 SYN1seqx“我想建立连接”SYNACK服务端回复 SYN1ACK1seqyackx1“同意我也想建立”ACK客户端回复 ACK1acky1“确认连接建立”为什么三次防止历史重复连接的 SYN 请求到达服务端后建立无效连接服务端发了 SYNACK 后如果客户端不回 ACK服务端会超时关闭。四次挥手FIN客户端发送 FIN“我数据发完了”ACK服务端确认“收到但我可能还有数据”FIN服务端发送 FIN“我也发完了”ACK客户端确认进入 TIME_WAIT 等待 2MSL为什么四次TCP 全双工每个方向需要独立关闭。步骤 2 和 3 不能合并因为服务端收到 FIN 后可能还有数据要发送。TIME_WAIT2MSLMSL Maximum Segment Lifetime通常60秒目的1确保最后的 ACK 能到达如果丢了对方会重发 FIN目的2让网络中残留的旧报文全部消亡本章总结知识域核心要点命令行find/grep/awk/sed 四剑客处理日志和配置文件进程管理SIGTERM 优于 SIGKILL掌握信号的含义性能排查top→iostat→ss→dmesg→strace 五步法Shell脚本set -euo pipefail是生产脚本的标配Systemd理解 service 文件各字段含义掌握 journalctlTCP三次握手防止旧连接、四次挥手因为全双工TLS1.3 一个RTT完成握手保证机密性完整性身份认证Nginx反向代理的核心负载均衡SSL终止静态分离安全禁密码登录非root运行最小权限定期审计下一篇预告第23篇Python 测试策略 – 从单元测试到集成测试代码写好还不够如何证明它是正确的下一篇我们将深入 pytest 框架的 fixture 机制与参数化测试、Mock 的正确使用时机、异步代码的测试方法、FastAPI/Django 的 API 测试实践以及代码覆盖率的合理目标设定帮你建立系统的测试策略。Python技术博客专栏| 第22篇 / 共25篇上一篇Docker与Kubernetes容器化部署下一篇Python测试策略