阶段2(下):运维专题 Docker/Nginx/Linux/CI-CD/Git 的课程、企业场景、面试题和可运行示例

This commit is contained in:
Shikui Wang committed 2026-10-23 15:36:06 +08:00
1 parent 5eb67c5d08
commit b8010a74f3
42 files changed
+3533 -55

No files matched your search

@@ -0,0 +1,65 @@
"""分析 Nginx 访问日志:状态码分布、请求最多的 IP、最慢的接口、5xx 明细。
日志格式:Nginx combined 格式末尾追加 $request_time(秒),对应配置:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $request_time';
运行:python analyze.py [日志文件],默认分析同目录的 sample_access.log
等价的命令行写法见 Linux 专题课程(awk / sort / uniq)。
"""
import re
import sys
from collections import Counter, defaultdict
from pathlib import Path
LINE = re.compile(
r'(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] "(?P<method>\S+) (?P<path>\S+) [^"]*" '
r'(?P<status>\d{3}) (?P<bytes>\d+) "[^"]*" "[^"]*" (?P<rt>[\d.]+)'
)
def parse(path: Path):
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
m = LINE.match(line)
if not m:
print(f"第 {n} 行格式不匹配,跳过", file=sys.stderr)
continue
d = m.groupdict()
d["path"] = d["path"].split("?")[0] # 去掉查询参数,按接口聚合
d["rt"] = float(d["rt"])
yield d
def analyze(rows: list[dict]) -> dict:
by_api: dict[str, list[float]] = defaultdict(list)
for r in rows:
by_api[f'{r["method"]} {r["path"]}'].append(r["rt"])
slowest = sorted(((max(v), k) for k, v in by_api.items()), reverse=True)[:3]
return {
"status": Counter(r["status"] for r in rows),
"top_ips": Counter(r["ip"] for r in rows).most_common(3),
"slowest": [(k, t) for t, k in slowest],
"errors_5xx": [(r["time"], r["status"], r["path"], r["rt"]) for r in rows if r["status"].startswith("5")],
}
def main() -> None:
path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name("sample_access.log")
rows = list(parse(path))
res = analyze(rows)
print(f"共 {len(rows)} 条请求")
print("状态码分布:", dict(sorted(res["status"].items())))
print("请求最多的 IP:", res["top_ips"])
print("最慢的接口(最大耗时):", res["slowest"])
print("5xx 明细:")
for e in res["errors_5xx"]:
print(" ", *e)
if path.name == "sample_access.log": # 用示例日志自检
assert res["status"]["401"] == 3 and res["status"]["429"] == 1
assert res["top_ips"][0] == ("198.51.100.7", 4)
assert res["slowest"][0] == ("GET /api/reports/monthly", 30.001)
assert [e[1] for e in res["errors_5xx"]] == ["504", "502"]
if __name__ == "__main__":
main()
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# 不自动运行:线上问题的“第一分钟”快照,只读命令,不修改任何东西
# 用法:bash diag.sh [进程名关键字] > diag-$(date +%F-%H%M).txt
set -uo pipefail
keyword="${1:-}"
section() { printf '\n===== %s =====\n' "$1"; }
section "时间和负载"
date
uptime
section "CPU 占用最高的进程"
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 10
section "内存"
free -h
section "磁盘空间和 inode"
df -h -x tmpfs -x devtmpfs
df -i -x tmpfs -x devtmpfs | awk 'NR == 1 || $5+0 > 80'
section "监听端口"
ss -lntp 2>/dev/null | head -n 30
section "TCP 连接状态统计"
ss -ant | awk 'NR > 1 {count[$1]++} END {for (s in count) print s, count[s]}'
if [[ -n "$keyword" ]]; then
section "进程:$keyword"
pgrep -af -- "$keyword" || echo "没有找到进程"
fi
section "最近的内核日志(OOM 等)"
if kernel_log="$(journalctl -k --since "1 hour ago" --no-pager 2>/dev/null)" || kernel_log="$(dmesg 2>/dev/null)"; then
grep -iE 'oom|killed process' <<<"$kernel_log" | tail -n 20 || echo "最近没有 OOM 记录"
else
echo "无权限读取内核日志"
fi
@@ -0,0 +1,10 @@
203.0.113.5 - - [23/Oct/2026:10:00:01 +0800] "GET /api/orders?page=1 HTTP/1.1" 200 512 "-" "Mozilla/5.0" 0.023
203.0.113.5 - - [23/Oct/2026:10:00:02 +0800] "GET /api/orders?page=2 HTTP/1.1" 200 498 "-" "Mozilla/5.0" 0.031
198.51.100.7 - - [23/Oct/2026:10:00:02 +0800] "POST /api/login HTTP/1.1" 401 64 "-" "curl/8.5.0" 0.004
198.51.100.7 - - [23/Oct/2026:10:00:02 +0800] "POST /api/login HTTP/1.1" 401 64 "-" "curl/8.5.0" 0.004
198.51.100.7 - - [23/Oct/2026:10:00:03 +0800] "POST /api/login HTTP/1.1" 401 64 "-" "curl/8.5.0" 0.005
198.51.100.7 - - [23/Oct/2026:10:00:03 +0800] "POST /api/login HTTP/1.1" 429 31 "-" "curl/8.5.0" 0.001
192.0.2.10 - - [23/Oct/2026:10:00:04 +0800] "GET /api/reports/monthly HTTP/1.1" 504 167 "-" "Mozilla/5.0" 30.001
192.0.2.10 - - [23/Oct/2026:10:00:40 +0800] "GET /api/reports/monthly HTTP/1.1" 200 20480 "-" "Mozilla/5.0" 12.874
203.0.113.9 - - [23/Oct/2026:10:00:41 +0800] "GET /api/orders/42 HTTP/1.1" 502 157 "-" "Mozilla/5.0" 0.002
203.0.113.9 - - [23/Oct/2026:10:00:42 +0800] "GET /api/orders/42 HTTP/1.1" 200 233 "-" "Mozilla/5.0" 0.018