Skip to content

技术干货手册

整理自问答文档1、问答文档2,提取所有代码片段与技术要点,附注释说明。


目录

  1. 大模型推理部署
  2. 量化与性能优化
  3. 动态批处理
  4. 异常检测算法
  5. 告警阈值设计
  6. 告警降噪与编排
  7. Prometheus 监控
  8. ELK 日志体系
  9. SkyWalking 链路追踪
  10. CI/CD 流水线
  11. Ansible 自动化运维
  12. Python 运维脚本
  13. Shell 日志分析
  14. Linux 系统排查
  15. 网络基础
  16. Docker 与 Kubernetes
  17. MySQL 优化
  18. Redis 实战
  19. 根因分析
  20. 容量规划与成本优化

一、大模型推理部署

1.1 MindIE 推理引擎核心配置

yaml
# MindIE 推理服务配置(DeepSeek-R1 671B 多机部署)
model:
  type: deepseek_r1
  tensor_parallel: 8      # 单机内 Tensor 并行度,对应 8 张 NPU
  pipeline_parallel: 4    # 跨机 Pipeline 并行度,4 台服务器各负责若干层
  num_layers: 61          # DeepSeek-R1 共 61 层 Transformer

compute:
  precision: w8a8          # 权重 INT8 + 激活 INT8 量化
  enable_flash_attention: true   # 启用 Flash Attention 3.0,减少显存访问
  enable_rdma: true        # 启用 RDMA 网络,降低跨机通信延迟

batching:
  max_batch_size: 128      # 最大批次大小,太大延迟高,太小利用率低
  dynamic_batching: true   # 动态批处理,自动合并不同长度请求
  prefill_interval: 16     # Prefill 与 Decode 阶段切换频率

memory:
  kv_cache_type: paged     # PagedAttention 管理 KV Cache,避免碎片
  max_sequence_length: 8192
  kv_cache_percent: 0.7    # 70% 显存用于 KV Cache,预留 30% buffer

serving:
  request_timeout: 120     # 请求超时时间(秒)
  streaming: true          # 启用流式输出(SSE)

rpc:
  enable_rdma: true
  rdma_port: 40000

1.2 模型部署流程

bash
# 1. 导出模型为 MindIE 格式(JIT 编译优化)
python -m mindie.exporter --model deepseek_r1 --output /models/compiled

# 2. 启动推理服务
mindie-server --config inference.yaml

# 3. 验证服务是否正常(OpenAI 兼容接口)
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"deepseek-r1","messages":[{"role":"user","content":"Hello"}],"stream":true}'

注意enable_compile 开启后首次推理有冷启动延迟,需要提前预热;kv_cache_percent 设太大会 OOM,要预留 buffer。

1.3 HCCL 集合通信环境变量调优

bash
# 昇腾 NPU 多机通信关键参数
export HCCL_CONNECT_TIMEOUT=600      # 连接超时时间(秒),多机初始化较慢
export HCCL_RDMA_MEM_SIZE=65536      # RDMA 内存池大小(KB)
export HCCL_BUFF_SIZE=65536          # 通信缓冲区大小

# NCCL 兼容层参数(部分场景适用)
export NCCL_IB_TIMEOUT=22            # IB 网络超时
export NCCL_NET_GDR_LEVEL=PHB        # GPU Direct RDMA 级别
export NCCL_ALGO=Ring                # 通信算法:Ring 或 Tree

优化前 HCCL 通信占推理总耗时 15%,调优后降至 8%,通信延迟降低约 40%。


二、量化与性能优化

2.1 W8A8 量化流程

python
# SmoothQuant 平滑异常激活通道,避免量化精度损失
# 原理:将激活值的异常通道"平滑"到权重侧,使两者分布更均匀

alpha = 0.5  # 平滑系数,0~1 之间,越大越多平滑到权重侧

# 计算平滑因子:激活标准差 / 权重标准差 的比值
smooth_factor = calculate_smooth_factor(activation_std, weight_std)

# 对权重做平滑变换
smoothed_weight = weight * (smooth_factor ** alpha)

# 量化为 INT8(范围 -128~127)
quantized_weight = quantize_to_int8(smoothed_weight)
yaml
# MindIE 量化配置
quantization:
  enabled: true
  method: w8a8              # 权重 INT8 + 激活 INT8
  weight_clip: true         # 裁剪权重异常值
  activation_scheme: per_token  # 按 token 动态量化激活值

calibration:
  method: minmax            # 用最大最小值确定量化范围
  samples: 5000             # 校准样本数,越多越准确
  batch_size: 32

量化收益:

  • 显存:1.2 TB → 600 GB(减少 50%)
  • 单卡吞吐:120 tokens/s → 280 tokens/s
  • 总吞吐:1800 tokens/s → 2500 tokens/s(提升约 40%)
  • 精度损失:< 0.5%(用 MMLU、HumanEval benchmark 验证)

2.2 Flash Attention 与算子融合

python
# Flash Attention 核心思想:分块计算 Attention,减少 HBM 读写次数
# 传统 Attention:Q*K^T 结果写回 HBM,再读出来做 Softmax,再写回
# Flash Attention:在 SRAM 内完成分块计算,大幅减少显存带宽消耗

# 在 MindIE 中启用(配置项)
compute:
  enable_flash_attention: true   # 启用后 Attention 计算显存访问减少约 60%

三、动态批处理

3.1 动态批处理实现原理

python
import time
from collections import defaultdict

class DynamicBatcher:
    """
    动态批处理器:将不同长度、不同来源的请求智能合并,
    最大化 GPU/NPU 利用率,同时控制延迟。
    """
    def __init__(self, max_batch_size=128, max_wait_time=0.05):
        self.queue = []
        self.max_batch_size = max_batch_size
        self.max_wait_time = max_wait_time  # 最长等待 50ms

    def add_request(self, request):
        self.queue.append(request)

    def get_batch(self):
        # 策略1:队列满了立即处理,不再等待
        if len(self.queue) >= self.max_batch_size:
            batch = self.queue[:self.max_batch_size]
            self.queue = self.queue[self.max_batch_size:]
            return batch

        # 策略2:队列中最早的请求等待超时,触发处理
        if self.queue and \
           time.time() - self.queue[0].arrival_time > self.max_wait_time:
            batch = self.queue[:self.max_batch_size]
            self.queue = self.queue[self.max_batch_size:]
            return batch

        # 策略3:按相同前缀分组,共享 KV Cache 计算
        batch = self.group_by_prefix()
        if batch:
            return batch

        return None

    def group_by_prefix(self):
        """将有相同 prompt 前缀的请求合并,只计算一次 Prefill"""
        prefix_groups = defaultdict(list)
        for req in self.queue:
            # 用 prompt 的 hash 作为分组 key(实际应用中用前缀树)
            prefix_key = hash(req.prompt[:50])
            prefix_groups[prefix_key].append(req)
        # 返回最大的前缀组,优先处理可以共享计算的请求
        if prefix_groups:
            return max(prefix_groups.values(), key=len)
        return []

关键参数调优参考:

参数建议值说明
max_batch_size64~128太大延迟高,太小利用率低
max_wait_time20~50ms平衡延迟和吞吐量
prefill_interval8~16Prefill 和 Decode 切换频率

四、异常检测算法

4.1 基于统计的异常检测

python
import numpy as np

def detect_anomaly_std(values: list, threshold: float = 3.0) -> list:
    """
    基于标准差的异常检测(3-sigma 原则)。
    超出均值 ± 3倍标准差的点视为异常。
    适用:单指标、分布较正态的场景(如 CPU 使用率)。
    """
    mean = np.mean(values)
    std = np.std(values)
    return [v for v in values if abs(v - mean) > threshold * std]


def detect_anomaly_ma(values: list, window: int = 5, threshold: float = 2.0) -> list:
    """
    基于移动平均的异常检测。
    当前值与近 window 个点的均值偏差超过 threshold 倍标准差时告警。
    适用:有趋势变化的时序指标(如内存缓慢增长)。
    """
    # 计算移动平均
    ma = np.convolve(values, np.ones(window) / window, mode='valid')
    anomalies = []
    for i, v in enumerate(values[window:]):
        if abs(v - ma[i]) > threshold * np.std(values):
            anomalies.append(i + window)
    return anomalies

4.2 Isolation Forest 多指标异常检测

python
from sklearn.ensemble import IsolationForest

def detect_by_isolation_forest(features: list, contamination: float = 0.1) -> list:
    """
    Isolation Forest 隔离森林:通过随机切分特征空间,
    异常点因为"孤立"所以需要更少的切分次数。
    适用:多指标联合异常检测(如 CPU + 内存 + IO 同时异常)。
    contamination:预期异常比例,通常设 0.05~0.1。
    """
    clf = IsolationForest(contamination=contamination, random_state=42)
    predictions = clf.fit_predict(features)
    # -1 表示异常,1 表示正常
    return [i for i, p in enumerate(predictions) if p == -1]

4.3 LSTM AutoEncoder 时序异常检测

python
class TimeSeriesAnomalyDetector:
    """
    LSTM AutoEncoder:学习正常时序模式,
    重建误差大的点视为异常。
    适用:复杂时序模式(如业务流量的周期性波动中的异常)。
    """
    def __init__(self, threshold: float = 0.05):
        self.encoder = None   # LSTM 编码器
        self.decoder = None   # LSTM 解码器
        self.threshold = threshold  # 重建误差阈值

    def train(self, normal_data):
        """用正常数据训练,让模型学会正常模式"""
        # 训练过程:编码 → 解码 → 最小化重建误差
        pass

    def detect(self, data) -> bool:
        """
        检测输入序列是否异常。
        重建误差 = 原始序列与重建序列的均方误差。
        误差超过阈值则判定为异常。
        """
        reconstructed = self.decoder.predict(self.encoder.transform(data))
        error = np.mean((data - reconstructed) ** 2)
        return error > self.threshold

4.4 Prometheus 动态阈值告警规则

yaml
# 基于 predict_linear 预测趋势,提前告警
groups:
  - name: dynamic_alerts
    rules:
      # 预测磁盘 4 小时后用满
      - alert: DiskWillBeFull
        expr: |
          predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) < 0
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "磁盘预计 4 小时后用满,请及时清理"

      # 动态基线:当前值超过过去 1 小时均值的 3 倍
      - alert: AbnormalTrafficSpike
        expr: |
          rate(http_requests_total[5m]) > 
          3 * avg_over_time(rate(http_requests_total[5m])[1h:5m])
        for: 5m
        labels:
          severity: warning

五、告警阈值设计

5.1 分层告警阈值配置示例

yaml
# ── 基础设施层(约 50 项)──────────────────────────────
infrastructure:
  cpu_utilization:
    warning: 70    # 超过 70% 预警,给运维留出处理时间
    critical: 85   # 超过 85% 紧急,可能影响业务

  cpu_loadavg_1min:
    warning: 4     # 负载超过 CPU 核数时需关注
    critical: 8

  memory_usage_percent:
    warning: 75
    critical: 90

  memory_available_mb:
    warning: 4096  # 可用内存低于 4GB 预警
    critical: 1024 # 低于 1GB 紧急

  disk_usage_percent:
    root_partition:
      warning: 80
      critical: 90
    data_partition:
      warning: 70   # 数据盘更严格,提前预警
      critical: 85

# ── 中间件层(约 60 项)──────────────────────────────
middleware:
  mysql:
    connections_active_ratio:
      warning: 0.70   # 活跃连接数超过 max_connections 的 70%
      critical: 0.85
    slow_queries_per_sec:
      warning: 10
      critical: 50

  redis:
    memory_used_ratio:
      warning: 0.70   # 已用内存超过 maxmemory 的 70%
      critical: 0.85
    connected_clients:
      warning: 500
      critical: 1000

  kafka:
    consumer_lag:
      warning: 10000  # 消费积压超过 1 万条预警
      critical: 50000

# ── 应用层(约 80 项)──────────────────────────────
application:
  api_latency_p99_ms:
    warning: 500
    critical: 1000

  api_error_rate:
    warning: 0.01   # 错误率超过 1% 预警
    critical: 0.05  # 超过 5% 紧急

  # 推理服务专项指标
  llm_ttft_ms:          # 首 token 延迟
    warning: 1500
    critical: 3000

  llm_throughput_tokens_per_sec:
    warning: 1500       # 低于 1500 tokens/s 预警
    critical: 800       # 低于 800 tokens/s 紧急

5.2 动态阈值计算(Python 实现)

python
import numpy as np
from datetime import datetime

def dynamic_threshold(values: list, factor: float = 3.0) -> float:
    """
    基于最近 100 个采样点计算动态阈值。
    阈值 = 均值 + factor × 标准差。
    factor 越大,阈值越宽松,误报越少。
    """
    recent = values[-100:]  # 只看最近 100 个点,避免历史异常影响
    mean = np.mean(recent)
    std = np.std(recent)
    return mean + factor * std


def get_threshold_by_hour(metric_config: dict, hour: int) -> dict:
    """
    按业务时段返回不同阈值。
    工作时间(9~18 点)流量大,阈值适当放宽;
    夜间流量小,阈值收紧,更容易发现异常。
    """
    if 9 <= hour <= 18:
        return metric_config['day_threshold']
    else:
        return metric_config['night_threshold']

六、告警降噪与编排

6.1 AlertManager 告警收敛配置

yaml
# AlertManager 路由配置
route:
  # 按告警名称 + 服务名分组,同组告警合并发送
  group_by: ['alertname', 'service']
  group_wait: 30s       # 等待 30s 收集同组告警,避免逐条发送
  group_interval: 5m    # 同组告警最少间隔 5 分钟再次通知
  repeat_interval: 4h   # 持续告警每 4 小时重复通知一次
  receiver: 'default'

  routes:
    # P1 紧急告警:立即通知,不等待
    - match:
        severity: critical
      group_wait: 0s
      receiver: 'pagerduty'

    # P4 提示告警:汇总后发邮件
    - match:
        severity: info
      group_wait: 10m
      receiver: 'email-digest'

# 告警抑制:根因告警触发时,压制衍生告警
inhibit_rules:
  - source_match:
      alertname: DatabaseConnectionPoolFull  # 根因:连接池满
    target_match_re:
      alertname: "APITimeout|OrderFailed"    # 衍生:接口超时、下单失败
    equal: ['env', 'cluster']               # 同环境同集群才抑制

6.2 告警智能编排(Python 实现)

python
from collections import defaultdict
from dataclasses import dataclass
from typing import List

@dataclass
class Alert:
    name: str
    service: str
    time: float
    severity: str

class AlertOrchestrator:
    """
    告警智能编排器:
    1. 按时间窗口聚合相关告警
    2. 基于调用链分析传播路径
    3. 匹配知识图谱推断根因
    4. 输出根因 + 影响范围 + 处置建议
    """

    def __init__(self):
        # 知识图谱:记录已知的故障传播模式
        # key: 根因告警名,value: 衍生告警列表
        self.knowledge_graph = {
            "DatabaseConnectionPoolFull": ["APITimeout", "OrderFailed"],
            "NetworkPacketLoss": ["ServiceUnavailable", "HighLatency"],
            "DiskFull": ["LogWriteFailed", "AppCrash"],
        }

    def group_by_time_window(self, alerts: List[Alert], window_sec: int = 300):
        """将 5 分钟内的告警归为一组"""
        if not alerts:
            return []
        groups = []
        current_group = [alerts[0]]
        for alert in alerts[1:]:
            if alert.time - current_group[0].time <= window_sec:
                current_group.append(alert)
            else:
                groups.append(current_group)
                current_group = [alert]
        groups.append(current_group)
        return groups

    def find_root_cause(self, alert_group: List[Alert]) -> str:
        """
        在一组告警中找根因:
        如果某个告警的衍生告警都在组内,则它是根因。
        """
        alert_names = {a.name for a in alert_group}
        for alert in sorted(alert_group, key=lambda x: x.time):
            derivatives = self.knowledge_graph.get(alert.name, [])
            if any(d in alert_names for d in derivatives):
                return alert.name
        # 找不到已知根因,返回最早的告警
        return min(alert_group, key=lambda x: x.time).name

七、Prometheus 监控

7.1 常用 PromQL 查询

# ── 请求量 ──────────────────────────────────────────
# 每秒请求数(5 分钟滑动窗口)
rate(http_requests_total[5m])

# 按服务聚合 QPS
sum by (service) (rate(http_requests_total[5m]))

# ── 延迟分位数 ──────────────────────────────────────
# P99 延迟(需要 Histogram 类型指标)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# P50 / P95 / P99 对比
histogram_quantile(0.50, rate(http_request_duration_seconds_bucket[5m]))
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# ── 错误率 ──────────────────────────────────────────
# 5xx 错误率
rate(http_requests_total{status=~"5.."}[5m])
  / rate(http_requests_total[5m])

# ── 资源使用 ──────────────────────────────────────────
# 内存使用率
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
  / node_memory_MemTotal_bytes * 100

# CPU 使用率(排除 idle 模式)
1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))

# 磁盘使用率
(node_filesystem_size_bytes - node_filesystem_free_bytes)
  / node_filesystem_size_bytes * 100

# ── 推理服务专项 ──────────────────────────────────────
# 推理吞吐量(tokens/s)
rate(llm_tokens_total[5m])

# 首 token 延迟 P95
histogram_quantile(0.95, rate(llm_ttft_seconds_bucket[5m]))

# NPU 利用率
npu_utilization{instance=~".*"}

7.2 Recording Rules(预计算,提升查询性能)

yaml
# 将高频复杂查询预计算为新指标,避免每次查询都实时计算
groups:
  - name: node_recording_rules
    interval: 1m   # 每分钟计算一次
    rules:
      # 预计算 CPU 使用率,避免每次 Dashboard 刷新都重算
      - record: instance:node_cpu_utilization:rate5m
        expr: |
          1 - avg by (instance) (
            rate(node_cpu_seconds_total{mode="idle"}[5m])
          )

      # 预计算内存使用率
      - record: instance:node_memory_utilization:ratio
        expr: |
          (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
            / node_memory_MemTotal_bytes

7.3 Kubernetes 集群监控部署

yaml
# kube-state-metrics:采集 K8s 对象状态(Pod、Deployment、Node 等)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-state-metrics
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kube-state-metrics
  template:
    spec:
      serviceAccountName: kube-state-metrics
      containers:
        - name: kube-state-metrics
          image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.8.0
          ports:
            - containerPort: 8080   # metrics 端口
            - containerPort: 8081   # telemetry 端口
---
# node-exporter:DaemonSet 部署到每个节点,采集主机指标
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    spec:
      hostNetwork: true    # 使用宿主机网络,采集真实网络指标
      hostPID: true        # 访问宿主机进程信息
      containers:
        - name: node-exporter
          image: prom/node-exporter:v1.6.0
          args:
            - --path.rootfs=/host   # 挂载宿主机根目录
          volumeMounts:
            - name: host-root
              mountPath: /host
              readOnly: true
      volumes:
        - name: host-root
          hostPath:
            path: /

八、ELK 日志体系

8.1 Filebeat 采集配置

yaml
# filebeat.yml - 部署在每台应用服务器,轻量采集日志
filebeat.inputs:
  # 采集 Nginx 访问日志
  - type: log
    paths:
      - /var/log/nginx/access.log
    fields:
      service: nginx
      env: prod
      log_type: access
    fields_under_root: true   # 字段提升到根级别,便于 ES 索引

  # 采集应用 JSON 日志
  - type: log
    paths:
      - /var/log/app/*.log
    json.keys_under_root: true    # JSON 日志自动解析
    json.add_error_key: true      # 解析失败时添加 error 字段
    fields:
      service: myapp
      env: prod

# 输出到 Kafka(生产环境推荐,避免 ES 压力过大)
output.kafka:
  hosts: ["kafka1:9092", "kafka2:9092", "kafka3:9092"]
  topic: 'logs-%{[service]}'   # 按服务名分 topic
  partition.round_robin:
    reachable_only: false
  compression: gzip

8.2 Logstash 日志解析 Pipeline

ruby
# logstash.conf - 解析 Nginx access log
input {
  kafka {
    bootstrap_servers => "kafka1:9092,kafka2:9092"
    topics => ["logs-nginx"]
    group_id => "logstash-nginx"
    codec => "json"
  }
}

filter {
  # grok 解析 Nginx 日志格式
  # 格式:IP - - [时间] "方法 路径 协议" 状态码 字节数 "referer" "UA"
  grok {
    match => {
      "message" => '%{IP:client_ip} - - \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status_code:int} %{NUMBER:bytes:int}'
    }
  }

  # 时间戳转换为 ES 标准格式
  date {
    match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
    target => "@timestamp"
    remove_field => ["timestamp"]
  }

  # IP 地理位置解析
  geoip {
    source => "client_ip"
    target => "geoip"
  }

  # 添加响应时间分级标签,便于统计慢请求
  if [response_time] {
    if [response_time] > 3 {
      mutate { add_tag => ["slow_request"] }
    }
  }
}

output {
  elasticsearch {
    hosts => ["es1:9200", "es2:9200", "es3:9200"]
    index => "nginx-logs-%{+YYYY.MM.dd}"   # 按天分索引,便于清理
    template_name => "nginx-logs"
  }
}

8.3 日志规范化 JSON 格式

json
{
  "timestamp": "2024-04-01T10:15:30.123Z",
  "level": "ERROR",
  "service": "order-service",
  "instance": "order-7d8f9c-xk2p9",
  "trace_id": "abc123def456",
  "span_id": "def456ghi789",
  "message": "Database connection failed",
  "error": {
    "code": "DB_CONN_ERR",
    "message": "Connection refused",
    "stack": "at com.example.db.Pool.getConnection..."
  },
  "context": {
    "user_id": "12345",
    "request_id": "req789",
    "order_id": "ord001"
  }
}

规范要点:timestamp 用 ISO8601;level 只用 DEBUG/INFO/WARN/ERROR;必须带 trace_id 便于跨系统关联;禁止打印密码、密钥等敏感字段;单条日志不超过 10KB。


九、SkyWalking 链路追踪

9.1 Agent 部署配置

yaml
# Java 应用 Agent 配置(agent.config)
agent.service_name = order-service          # 服务名,在 SkyWalking UI 中显示
collector.backend_service = oap-server:11800  # OAP Server 地址
agent.sample_n_per_3_secs = 3              # 每 3 秒采样 3 个请求(生产环境控制采样率)
python
# Python 应用使用 OpenTelemetry 上报到 SkyWalking
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# 初始化 Tracer
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="oap-server:11800")
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer(__name__)

# 在关键函数上添加 Span
def process_order(order_id: str):
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        try:
            result = do_process(order_id)
            span.set_attribute("order.status", "success")
            return result
        except Exception as e:
            span.record_exception(e)
            span.set_status(trace.StatusCode.ERROR, str(e))
            raise

9.2 SkyWalking 告警规则

yaml
# alarm-settings.yml - 慢调用和错误率告警
rules:
  # 服务响应时间 P99 超过 3 秒,持续 10 分钟
  service_resp_time_rule:
    metrics-name: service_resp_time
    op: ">"
    threshold: 3000        # 单位:毫秒
    period: 10             # 检查周期:10 分钟
    count: 3               # 10 分钟内超过 3 次触发
    silence-period: 5      # 告警后静默 5 分钟,避免重复通知
    message: "服务 {name} P99 延迟超过 3 秒"

  # 服务错误率超过 5%
  service_error_rate_rule:
    metrics-name: service_sla
    op: "<"
    threshold: 9500        # SLA < 95%(即错误率 > 5%)
    period: 10
    count: 2
    message: "服务 {name} 错误率超过 5%"

十、CI/CD 流水线

10.1 GitLab CI 完整流水线

yaml
# .gitlab-ci.yml
stages:
  - scan      # 代码扫描
  - build     # 构建镜像
  - test      # 自动化测试
  - deploy    # 部署

variables:
  HARBOR_ADDR: harbor.example.com
  IMAGE_NAME: $HARBOR_ADDR/project/$CI_PROJECT_NAME

# 代码质量扫描(MR 时触发)
code_scan:
  stage: scan
  image: sonarsource/sonar-scanner-cli
  script:
    - sonar-scanner
      -Dsonar.projectKey=$CI_PROJECT_NAME
      -Dsonar.sources=src
      -Dsonar.host.url=$SONAR_URL
      -Dsonar.login=$SONAR_TOKEN
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

# 构建 Docker 镜像并推送 Harbor
build_image:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $HARBOR_USER -p $HARBOR_PASS $HARBOR_ADDR
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHORT_SHA .
    - docker push $IMAGE_NAME:$CI_COMMIT_SHORT_SHA
    # 主分支额外打 latest 标签
    - |
      if [ "$CI_COMMIT_BRANCH" == "main" ]; then
        docker tag $IMAGE_NAME:$CI_COMMIT_SHORT_SHA $IMAGE_NAME:latest
        docker push $IMAGE_NAME:latest
      fi

# 部署到测试环境
deploy_test:
  stage: deploy
  environment: test
  script:
    - kubectl set image deployment/$CI_PROJECT_NAME
        app=$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
        -n test
    - kubectl rollout status deployment/$CI_PROJECT_NAME -n test --timeout=5m
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

# 部署到生产环境(需要手动审批)
deploy_prod:
  stage: deploy
  environment: production
  when: manual    # 手动触发,需要审批
  script:
    - kubectl set image deployment/$CI_PROJECT_NAME
        app=$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
        -n prod
    - kubectl rollout status deployment/$CI_PROJECT_NAME -n prod --timeout=10m
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

10.2 Dockerfile 多阶段构建

dockerfile
# 多阶段构建:构建阶段和运行阶段分离,大幅减小最终镜像体积

# ── 阶段1:构建 ──────────────────────────────────────
FROM golang:1.21-alpine AS builder
WORKDIR /app
# 先复制依赖文件,利用 Docker 层缓存,依赖不变时不重新下载
COPY go.mod go.sum ./
RUN go mod download
# 再复制源码并编译
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp ./cmd/main.go

# ── 阶段2:运行 ──────────────────────────────────────
FROM alpine:3.18
# 只安装必要的 CA 证书(HTTPS 请求需要)
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /app
# 只从构建阶段复制编译好的二进制,不包含源码和编译工具
COPY --from=builder /app/myapp .
# 使用非 root 用户运行,提升安全性
RUN adduser -D -s /bin/sh appuser
USER appuser
EXPOSE 8080
ENTRYPOINT ["./myapp"]

十一、Ansible 自动化运维

11.1 批量配置下发

yaml
# nginx_deploy.yml - 批量下发 Nginx 配置并重载
- hosts: web_servers
  vars:
    nginx_version: "1.24.0"
  tasks:
    - name: 检查 Nginx 是否安装
      command: nginx -v
      register: nginx_check
      ignore_errors: true

    - name: 安装 Nginx(如未安装)
      yum:
        name: "nginx-{{ nginx_version }}"
        state: present
      when: nginx_check.rc != 0

    - name: 下发 Nginx 配置(使用 Jinja2 模板)
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
        backup: yes    # 自动备份旧配置
      notify: reload nginx   # 配置变更时触发 handler

    - name: 验证 Nginx 配置语法
      command: nginx -t
      changed_when: false    # 这个任务不算"变更"

  handlers:
    # handler 只在被 notify 时执行,且无论 notify 多少次只执行一次
    - name: reload nginx
      service:
        name: nginx
        state: reloaded

11.2 批量应用部署

yaml
# app_deploy.yml - Java 应用批量部署
- hosts: app_servers
  vars:
    app_name: order-service
    app_port: 8080
    app_version: "{{ target_version }}"   # 通过命令行传入:-e target_version=1.2.0
    deploy_dir: /opt/apps/{{ app_name }}

  tasks:
    - name: 创建应用目录
      file:
        path: "{{ deploy_dir }}"
        state: directory
        owner: appuser
        mode: '0755'

    - name: 下载应用包
      get_url:
        url: "http://nexus.example.com/{{ app_name }}-{{ app_version }}.jar"
        dest: "{{ deploy_dir }}/app-{{ app_version }}.jar"
        checksum: "sha256:{{ app_checksum }}"   # 校验完整性

    - name: 停止旧版本
      systemd:
        name: "{{ app_name }}"
        state: stopped
      ignore_errors: true   # 首次部署时服务不存在,忽略错误

    - name: 更新软链接到新版本
      file:
        src: "{{ deploy_dir }}/app-{{ app_version }}.jar"
        dest: "{{ deploy_dir }}/app.jar"
        state: link

    - name: 启动新版本
      systemd:
        name: "{{ app_name }}"
        state: started
        enabled: yes
        daemon_reload: yes

    - name: 等待服务健康检查通过
      uri:
        url: "http://localhost:{{ app_port }}/actuator/health"
        status_code: 200
      register: health_check
      retries: 10
      delay: 5    # 每 5 秒重试一次,最多 10 次(50 秒)
      until: health_check.status == 200

11.3 常用 Ad-hoc 命令

bash
# 批量查看所有主机负载
ansible all -m shell -a "uptime" -i inventory/prod

# 批量重启服务
ansible web_servers -m systemd -a "name=nginx state=restarted" -i inventory/prod

# 批量收集日志文件到本地
ansible all -m fetch -a "src=/var/log/app/error.log dest=./logs/ flat=no"

# 批量检查磁盘使用
ansible all -m shell -a "df -h | grep -v tmpfs"

# 使用 vault 加密敏感变量
ansible-vault encrypt_string 'MySecretPassword' --name 'db_password'
# 在 playbook 中使用:db_password: !vault |...

十二、Python 运维脚本

12.1 自动巡检脚本

python
#!/usr/bin/env python3
"""
自动巡检脚本:检查磁盘、端口、API 健康状态,
结果汇总后可扩展为发送钉钉/邮件告警。
"""
import subprocess
import socket
import requests
from datetime import datetime
from typing import Dict, List, Tuple


class HealthChecker:

    def check_disk(self) -> Dict:
        """检查磁盘使用率,超过 80% 记录告警"""
        result = subprocess.run(
            ['df', '-h', '--output=target,pcent,size'],
            capture_output=True, text=True
        )
        alerts = []
        for line in result.stdout.strip().split('\n')[1:]:
            parts = line.split()
            if len(parts) >= 2:
                try:
                    usage = int(parts[1].replace('%', ''))
                    if usage > 80:
                        alerts.append(f"{parts[0]} 使用率 {parts[1]}")
                except ValueError:
                    continue
        return {'status': 'warn' if alerts else 'ok', 'details': alerts}

    def check_port(self, host: str, port: int, timeout: int = 3) -> bool:
        """检查 TCP 端口是否可达"""
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        try:
            return sock.connect_ex((host, port)) == 0
        finally:
            sock.close()

    def check_api(self, url: str, timeout: int = 5) -> Dict:
        """检查 HTTP 接口健康状态"""
        try:
            resp = requests.get(url, timeout=timeout)
            return {
                'status': 'ok' if resp.status_code == 200 else 'error',
                'code': resp.status_code,
                'latency_ms': int(resp.elapsed.total_seconds() * 1000)
            }
        except requests.exceptions.Timeout:
            return {'status': 'error', 'reason': 'timeout'}
        except Exception as e:
            return {'status': 'error', 'reason': str(e)}

    def run_all(self, services: List[Dict]) -> None:
        """执行全量巡检并打印报告"""
        print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 巡检开始")
        print("=" * 60)

        # 磁盘检查
        disk = self.check_disk()
        status_icon = "✅" if disk['status'] == 'ok' else "🚨"
        print(f"{status_icon} 磁盘: {disk['status']}")
        for detail in disk['details']:
            print(f"   ⚠️  {detail}")

        # 服务检查
        for svc in services:
            if svc['type'] == 'port':
                ok = self.check_port(svc['host'], svc['port'])
                icon = "✅" if ok else "🚨"
                print(f"{icon} {svc['name']}: {'UP' if ok else 'DOWN'}")
            elif svc['type'] == 'api':
                result = self.check_api(svc['url'])
                icon = "✅" if result['status'] == 'ok' else "🚨"
                latency = result.get('latency_ms', '-')
                print(f"{icon} {svc['name']}: {result['status']} ({latency}ms)")


if __name__ == '__main__':
    checker = HealthChecker()
    checker.run_all([
        {'name': 'MySQL',    'type': 'port', 'host': '10.0.0.10', 'port': 3306},
        {'name': 'Redis',    'type': 'port', 'host': '10.0.0.11', 'port': 6379},
        {'name': 'API健康',  'type': 'api',  'url': 'http://localhost:8080/health'},
    ])

12.2 重试装饰器

python
import time
import functools
import logging

logger = logging.getLogger(__name__)

def retry(max_attempts: int = 3, delay: float = 1.0, exceptions=(Exception,)):
    """
    通用重试装饰器。
    max_attempts:最大重试次数
    delay:每次重试间隔(秒)
    exceptions:捕获哪些异常才重试
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_exception = None
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    if attempt < max_attempts:
                        logger.warning(
                            f"{func.__name__}{attempt} 次失败: {e},"
                            f"{delay}s 后重试..."
                        )
                        time.sleep(delay)
                    else:
                        logger.error(f"{func.__name__} 重试 {max_attempts} 次后仍失败")
            raise last_exception
        return wrapper
    return decorator


# 使用示例
@retry(max_attempts=3, delay=2.0, exceptions=(ConnectionError, TimeoutError))
def call_external_api(url: str):
    import requests
    return requests.get(url, timeout=5)

12.3 端口扫描工具

python
#!/usr/bin/env python3
"""
多线程端口扫描器,支持端口范围和常见服务识别。
"""
import socket
import concurrent.futures
import argparse
from datetime import datetime

COMMON_SERVICES = {
    21: "FTP", 22: "SSH", 23: "Telnet", 25: "SMTP",
    53: "DNS", 80: "HTTP", 110: "POP3", 143: "IMAP",
    443: "HTTPS", 3306: "MySQL", 3389: "RDP",
    5432: "PostgreSQL", 6379: "Redis", 8080: "HTTP-Alt",
    27017: "MongoDB", 9200: "Elasticsearch", 2181: "ZooKeeper",
}

def scan_port(host: str, port: int, timeout: float = 1.0) -> Tuple[int, bool]:
    """扫描单个端口,返回 (端口号, 是否开放)"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    try:
        result = sock.connect_ex((host, port))
        return port, result == 0
    except Exception:
        return port, False
    finally:
        sock.close()

def scan_host(host: str, ports, max_workers: int = 100) -> List[int]:
    """并发扫描多个端口,返回开放端口列表"""
    open_ports = []
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {executor.submit(scan_port, host, p): p for p in ports}
        for future in concurrent.futures.as_completed(futures):
            port, is_open = future.result()
            if is_open:
                open_ports.append(port)
                service = COMMON_SERVICES.get(port, "Unknown")
                print(f"  [+] {port:5d}/tcp  {service}")
    return sorted(open_ports)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('host')
    parser.add_argument('-p', '--ports', default='1-1000')
    args = parser.parse_args()

    if '-' in args.ports:
        start, end = map(int, args.ports.split('-'))
        ports = range(start, end + 1)
    else:
        ports = [int(p) for p in args.ports.split(',')]

    print(f"扫描 {args.host},共 {len(list(ports))} 个端口")
    open_ports = scan_host(args.host, ports)
    print(f"\n共发现 {len(open_ports)} 个开放端口")

十三、Shell 日志分析

13.1 Nginx 访问日志分析脚本

bash
#!/bin/bash
# nginx_analysis.sh - 分析 Nginx access.log
# 用法:bash nginx_analysis.sh [日志文件] [TOP N]

LOG_FILE=${1:-"/var/log/nginx/access.log"}
LIMIT=${2:-10}

[[ ! -f "$LOG_FILE" ]] && { echo "文件不存在: $LOG_FILE"; exit 1; }

echo "============================================"
echo "Nginx 日志分析 | $(date '+%Y-%m-%d %H:%M:%S')"
echo "文件: $LOG_FILE"
echo "============================================"

# 总体统计
total=$(wc -l < "$LOG_FILE")
unique_ips=$(awk '{print $1}' "$LOG_FILE" | sort -u | wc -l)
echo -e "\n【总体】请求数: $total | 独立IP: $unique_ips"

# TOP N 访问 IP
echo -e "\n【TOP $LIMIT 访问 IP】"
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -"$LIMIT" | \
  awk '{printf "  %-20s %s 次\n", $2, $1}'

# HTTP 状态码分布
echo -e "\n【状态码分布】"
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn | \
  awk '{printf "  %s  %s 次\n", $2, $1}'

# 每分钟请求量(TOP 20)
echo -e "\n【每分钟请求量 TOP 20】"
awk '{print $4}' "$LOG_FILE" | cut -d: -f1,2 | tr -d '[' | \
  sort | uniq -c | sort -rn | head -20 | \
  awk '{printf "  %-25s %s 次\n", $2, $1}'

# 最近 20 条 5xx 错误
echo -e "\n【最近 5xx 错误】"
awk '$9 ~ /^5[0-9][0-9]$/ {print $4, $9, $7}' "$LOG_FILE" | \
  tail -20 | awk '{printf "  %s | %s | %s\n", $1, $2, $3}'

echo -e "\n============================================"

13.2 常用 Shell 运维命令

bash
# ── 进程排查 ──────────────────────────────────────────
# 按 CPU 使用率排序,查看 TOP 10 进程
ps aux --sort=-%cpu | head -11

# 按内存使用率排序
ps aux --sort=-%mem | head -11

# 查看 Java 进程的线程 CPU 使用(定位热点线程)
top -H -p $(pgrep -f java | head -1)

# ── IO 排查 ──────────────────────────────────────────
# 实时查看磁盘 IO(%util 接近 100% 说明 IO 瓶颈)
iostat -x 1 5

# 查看哪个进程 IO 最高
iotop -ao

# ── 网络排查 ──────────────────────────────────────────
# 统计各状态 TCP 连接数
ss -s

# 查看 80 端口连接数
ss -tn state established '( dport = :80 or sport = :80 )' | wc -l

# 测试接口各阶段耗时(DNS/TCP/SSL/TTFB/总时间)
curl -o /dev/null -s -w \
  "DNS: %{time_namelookup}s\nTCP: %{time_connect}s\nSSL: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  https://example.com

# ── 日志快速分析 ──────────────────────────────────────
# 统计最近 1 小时的 ERROR 日志数量
awk -v d="$(date -d '1 hour ago' '+%Y-%m-%d %H')" '$0 ~ d && /ERROR/' app.log | wc -l

# 清空日志文件但不影响正在写入的进程(不能用 rm!)
truncate -s 0 /var/log/app/app.log
# 或者
> /var/log/app/app.log

十四、Linux 系统排查

14.1 SSH 登录不上排查流程

bash
# 1. 确认网络连通性
ping -c 4 <server_ip>

# 2. 确认 SSH 端口是否监听
nc -zv <server_ip> 22

# 3. 登录物理机或带外管理(IPMI/iLO)后排查
systemctl status sshd          # 查看 SSH 服务状态
systemctl restart sshd         # 尝试重启

# 4. 防火墙检查
iptables -L -n | grep 22
firewall-cmd --list-all

# 5. 资源耗尽检查
free -h                        # 内存是否不足
df -h                          # 磁盘是否满了
ulimit -n                      # 文件描述符限制

# 6. 查看 SSH 日志
journalctl -u sshd -n 50 --no-pager
cat /var/log/secure | tail -50  # CentOS
cat /var/log/auth.log | tail -50 # Ubuntu

# 7. fail2ban 是否封禁了 IP
fail2ban-client status sshd
fail2ban-client set sshd unbanip <your_ip>

14.2 服务器负载高排查

bash
# 第一步:看负载和 CPU
uptime                         # 1/5/15 分钟平均负载
top -b -n 1 | head -20         # 快照模式,看 CPU 占用 TOP 进程

# 第二步:判断瓶颈类型
vmstat 1 5                     # si/so 高 → 内存不足在用 swap
                               # wa 高 → IO 等待
iostat -x 1 5                  # %util 接近 100% → IO 瓶颈
iotop -ao                      # 哪个进程 IO 最高

# 第三步:CPU 密集型定位
ps aux --sort=-%cpu | head -11
# Java 进程热点线程
top -H -p $(pgrep -f java | head -1)
# 找到高 CPU 线程 TID,转 16 进制后在 jstack 中定位
printf '%x\n' <tid>
jstack <pid> | grep -A 20 <hex_tid>

# 第四步:内存问题
free -h
ps aux --sort=-%mem | head -11
# Java 堆内存
jstat -gc <pid> 1000 5
jmap -histo <pid> | head -30

# 第五步:网络连接数
ss -s
ss -tn state established | wc -l
netstat -an | awk '{print $6}' | sort | uniq -c | sort -rn

14.3 磁盘满了快速处理

bash
# 定位大文件
du -sh /* 2>/dev/null | sort -rh | head -20
du -sh /var/log/* | sort -rh | head -10

# 找出超过 100MB 的文件
find / -size +100M -type f 2>/dev/null | xargs ls -lh | sort -k5 -rh | head -20

# 清空日志(不能 rm,要用 truncate)
truncate -s 0 /var/log/app/app.log
> /var/log/nginx/access.log

# 清理 Docker 占用
docker system prune -f
docker volume prune -f

# 清理 yum/apt 缓存
yum clean all
apt-get clean

# 查看已删除但仍被进程占用的文件(占用空间但 ls 看不到)
lsof | grep deleted | awk '{print $7, $9}' | sort -rn | head -10
# 重启对应进程即可释放

十五、网络基础

15.1 TCP 三次握手 / 四次挥手

三次握手(建立连接):
  Client ──── SYN(seq=x) ────────────────────> Server
  Client <─── SYN-ACK(seq=y, ack=x+1) ──────── Server
  Client ──── ACK(ack=y+1) ──────────────────> Server

四次挥手(关闭连接):
  Client ──── FIN ────────────────────────────> Server
  Client <─── ACK ────────────────────────────  Server
  Client <─── FIN ────────────────────────────  Server
  Client ──── ACK ────────────────────────────> Server
  (Client 进入 TIME_WAIT,等 2MSL 后彻底关闭)

TIME_WAIT 的意义:防止最后一个 ACK 丢失后服务端重发 FIN 时找不到连接;等待旧数据包在网络中消失,避免影响新连接。

15.2 网络访问慢排查

bash
# DNS 解析耗时
time nslookup example.com
dig example.com

# 各阶段耗时(DNS/TCP/SSL/TTFB/总时间)
curl -o /dev/null -s -w \
  "DNS:%{time_namelookup}s TCP:%{time_connect}s SSL:%{time_appconnect}s TTFB:%{time_starttransfer}s Total:%{time_total}s\n" \
  https://example.com

# 路由追踪
traceroute example.com

# 服务端连接数
ss -s
netstat -an | grep :80 | wc -l

# 带宽占用
iftop -i eth0

分层定位思路

  • DNS 慢 → 检查 DNS 服务器配置
  • TCP 连接慢 → 网络/防火墙问题
  • SSL 握手慢 → 证书或服务器性能
  • TTFB 慢 → 后端应用处理慢
  • 内容下载慢 → 带宽瓶颈或资源过大

15.3 负载均衡算法对比

算法原理优点缺点适用场景
轮询依次分配简单公平不考虑负载无状态服务
加权轮询按权重比例可手动调配权重固定异构服务器
最少连接分给连接数最少的动态适应需维护状态长连接场景
IP Hash按客户端 IP 哈希会话保持扩缩容影响大有状态服务
一致性哈希哈希环,扩缩容影响最小扩缩容友好实现复杂分布式缓存

十六、Docker 与 Kubernetes

16.1 Dockerfile 多阶段构建

dockerfile
# 阶段1:构建(包含编译工具,体积大)
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download          # 先复制依赖,利用层缓存
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp ./cmd/main.go

# 阶段2:运行(只含二进制,体积小)
FROM alpine:3.18
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /app
COPY --from=builder /app/myapp .
RUN adduser -D appuser
USER appuser                 # 非 root 运行,提升安全性
EXPOSE 8080
ENTRYPOINT ["./myapp"]

多阶段构建可将镜像从 800MB+ 压缩到 20MB 以内。

16.2 Kubernetes 常用排查命令

bash
# ── Pod 排查 ──────────────────────────────────────────
kubectl get pods -n <ns> -o wide          # 查看 Pod 状态和所在节点
kubectl describe pod <pod> -n <ns>        # 详细事件,排查 Pending/CrashLoop
kubectl logs <pod> -n <ns> --tail=100     # 查看日志
kubectl logs <pod> -n <ns> -c <container> --previous  # 上一次崩溃的日志
kubectl exec -it <pod> -n <ns> -- /bin/sh # 进入容器

# ── 常见问题判断 ──────────────────────────────────────
# Pending → 资源不足或节点选择器不匹配
kubectl describe pod <pod> | grep -A 10 Events

# CrashLoopBackOff → 容器启动后立即退出
kubectl logs <pod> --previous             # 看上次退出原因

# ImagePullBackOff → 镜像拉取失败
kubectl describe pod <pod> | grep image   # 确认镜像地址和 tag

# OOMKilled → 内存超限
kubectl describe pod <pod> | grep -i oom

# ── 节点排查 ──────────────────────────────────────────
kubectl get nodes                         # 查看节点状态
kubectl describe node <node>              # 查看节点资源和事件
kubectl top nodes                         # 节点资源使用(需 metrics-server)
kubectl top pods -n <ns>                  # Pod 资源使用

# ── 网络排查 ──────────────────────────────────────────
# 测试 Pod 间连通性
kubectl run test --image=busybox --rm -it -- wget -qO- http://<svc>.<ns>.svc.cluster.local

# 查看 Service 端点
kubectl get endpoints <svc> -n <ns>

16.3 K8s 资源配置规范

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: harbor.example.com/prod/order-service:v1.2.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "500m"       # 调度依据,保证最低资源
              memory: "512Mi"
            limits:
              cpu: "2"          # 上限,防止单 Pod 抢占过多
              memory: "2Gi"
          readinessProbe:       # 就绪探针:通过才接收流量
            httpGet:
              path: /actuator/health
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
          livenessProbe:        # 存活探针:失败则重启容器
            httpGet:
              path: /actuator/health
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
            failureThreshold: 3
      affinity:
        podAntiAffinity:        # 反亲和:同一服务的 Pod 分散到不同节点
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app: order-service
                topologyKey: kubernetes.io/hostname

十七、MySQL 优化

17.1 慢查询分析

sql
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;          -- 超过 1 秒记录
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 用 EXPLAIN 分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
-- 关注:type(ALL 最差,ref/eq_ref 较好,const 最好)
--       key(实际使用的索引)
--       rows(扫描行数,越小越好)
--       Extra(Using filesort / Using temporary 是警告信号)

-- 查看当前正在执行的慢查询
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;

-- 用 pt-query-digest 分析慢查询日志
pt-query-digest /var/log/mysql/slow.log | head -100

17.2 索引设计原则

sql
-- 联合索引遵循最左前缀原则
-- 索引 (a, b, c),以下查询能用到索引:
-- WHERE a=1                    ✅ 用到 a
-- WHERE a=1 AND b=2            ✅ 用到 a,b
-- WHERE a=1 AND b=2 AND c=3   ✅ 用到 a,b,c
-- WHERE b=2                    ❌ 跳过了 a,用不到
-- WHERE a=1 AND c=3            ✅ 只用到 a(c 跳过了 b)

-- 覆盖索引:查询字段全在索引中,无需回表
CREATE INDEX idx_user_status ON orders(user_id, status, created_at);
-- 以下查询直接从索引返回,不回表
SELECT user_id, status, created_at FROM orders WHERE user_id = 123;

-- 区分度低的字段不适合单独建索引(如 status 只有几个值)
-- 适合放在联合索引的后面

-- 查看索引使用情况
SELECT * FROM information_schema.INDEX_STATISTICS
WHERE TABLE_NAME = 'orders';

-- 找出未使用的索引
SELECT * FROM sys.schema_unused_indexes;

17.3 连接池与参数优化

ini
# my.cnf 关键参数
[mysqld]
# 连接数
max_connections = 1000
max_connect_errors = 100000

# InnoDB 缓冲池(设为物理内存的 70%~80%)
innodb_buffer_pool_size = 16G
innodb_buffer_pool_instances = 8   # 每个实例 2G,减少锁竞争

# 日志
innodb_log_file_size = 2G          # 越大崩溃恢复越慢,但写入性能越好
innodb_flush_log_at_trx_commit = 1 # 1=最安全,2=性能好但断电可能丢1秒数据

# 慢查询
slow_query_log = ON
long_query_time = 1
log_queries_not_using_indexes = ON
bash
# 监控连接数
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
mysql -e "SHOW STATUS LIKE 'Max_used_connections';"

# 监控缓冲池命中率(应 > 99%)
mysql -e "SHOW STATUS LIKE 'Innodb_buffer_pool_read%';"

十八、Redis 实战

18.1 常用数据结构与场景

bash
# String:计数器、缓存、分布式锁
SET user:1001:name "张三" EX 3600    # 带过期时间
INCR page:view:count                  # 原子计数
SETNX lock:order:1001 1              # 分布式锁(NX=不存在才设置)

# Hash:对象存储(比 JSON 字符串更节省内存,支持单字段更新)
HSET user:1001 name "张三" age 30 city "杭州"
HGET user:1001 name
HGETALL user:1001

# List:消息队列、最新列表
LPUSH news:list "新闻标题1"           # 左侧插入
LRANGE news:list 0 9                  # 取前 10 条
BRPOP task:queue 30                   # 阻塞式消费(超时 30s)

# Set:去重、标签、共同好友
SADD user:1001:tags "python" "k8s"
SISMEMBER user:1001:tags "python"     # 是否包含
SINTER user:1001:tags user:1002:tags  # 交集(共同标签)

# ZSet:排行榜、延迟队列
ZADD leaderboard 9800 "user:1001"
ZREVRANGE leaderboard 0 9 WITHSCORES  # TOP 10
ZADD delay:queue <timestamp> "task:123"  # 延迟队列(score=执行时间戳)

18.2 缓存常见问题

缓存穿透:查询不存在的 key,每次都打到数据库
  解决:① 缓存空值(TTL 短一些)
        ② 布隆过滤器(BloomFilter)拦截不存在的 key

缓存击穿:热点 key 过期瞬间,大量请求同时打到数据库
  解决:① 互斥锁(SETNX),只让一个请求重建缓存
        ② 热点 key 不设过期时间,后台异步更新

缓存雪崩:大量 key 同时过期,或 Redis 宕机
  解决:① 过期时间加随机抖动(base_ttl + random(0, 300))
        ② Redis 集群/哨兵保证高可用
        ③ 本地缓存(Caffeine)作为二级缓存兜底

18.3 Redis 运维常用命令

bash
# 内存分析
redis-cli info memory | grep used_memory_human
redis-cli --bigkeys                    # 找出大 key(慎用,会扫全库)
redis-cli --memkeys                    # 按内存排序

# 慢查询
redis-cli config set slowlog-log-slower-than 10000  # 超过 10ms 记录
redis-cli slowlog get 10               # 查看最近 10 条慢查询

# 连接数
redis-cli info clients | grep connected_clients

# 持久化状态
redis-cli info persistence | grep -E "rdb|aof"

# 主从状态
redis-cli info replication

# 清理过期 key(生产慎用 FLUSHDB)
redis-cli --scan --pattern "session:*" | xargs redis-cli del

十九、根因分析

19.1 故障定位标准流程

1. 发现告警
   └── 确认影响范围(哪些服务/用户受影响)

2. 快速止血(先恢复,再分析)
   └── 重启服务 / 回滚版本 / 切换流量

3. 分层排查
   ├── 应用层:日志 ERROR、接口错误率、响应时间
   ├── 中间件层:DB 慢查询、Redis 连接数、MQ 积压
   ├── 基础设施层:CPU/内存/磁盘/网络
   └── 外部依赖:第三方接口、DNS、CDN

4. 根因确认
   └── 时间线对齐:告警时间 vs 变更时间 vs 指标异常时间

5. 复盘
   └── 5-Why 分析 → 改进措施 → 跟踪落地

19.2 常见故障传播模式

数据库连接池耗尽
  → 应用线程全部阻塞等待连接
    → 接口响应超时
      → 前端报错 / 用户投诉

磁盘写满
  → 日志无法写入 → 应用崩溃
  → 数据库无法写 binlog → 主从同步中断

内存不足(OOM)
  → 系统 kill 进程(OOM Killer)
    → 服务不可用
      → 告警风暴(衍生告警淹没根因告警)

网络丢包
  → TCP 重传增加 → 延迟升高
    → 超时告警 → 服务降级

19.3 告警根因推断(Python 实现)

python
class RootCauseAnalyzer:
    """
    基于知识图谱的根因推断:
    当一组告警同时出现时,找出最可能的根因。
    """
    # 已知故障传播模式:根因 → 衍生告警列表
    KNOWLEDGE_GRAPH = {
        "DatabaseConnectionPoolFull": ["APITimeout", "OrderFailed", "SlowQuery"],
        "DiskFull":                   ["LogWriteFailed", "AppCrash", "DBWriteError"],
        "NetworkPacketLoss":          ["ServiceUnavailable", "HighLatency", "TCPRetransmit"],
        "MemoryOOM":                  ["ProcessKilled", "ServiceRestart", "HighSwap"],
    }

    def find_root_cause(self, active_alerts: list) -> str:
        alert_set = set(active_alerts)
        best_match = None
        best_score = 0

        for root, derivatives in self.KNOWLEDGE_GRAPH.items():
            # 计算命中率:衍生告警中有多少出现在当前告警组里
            hits = len(set(derivatives) & alert_set)
            score = hits / len(derivatives)
            if score > best_score:
                best_score = score
                best_match = root

        return best_match if best_score > 0.3 else "Unknown"

二十、容量规划与成本优化

20.1 容量评估方法

python
def estimate_capacity(current_qps: float, growth_rate: float,
                      months: int, safety_factor: float = 1.3) -> dict:
    """
    容量预测:基于当前 QPS 和增长率,预测未来资源需求。
    safety_factor:安全系数,通常 1.2~1.5(留 20%~50% 余量)
    """
    future_qps = current_qps * ((1 + growth_rate) ** months)
    required_qps = future_qps * safety_factor

    # 假设单核可处理 200 QPS(根据实际压测结果调整)
    qps_per_core = 200
    required_cores = required_qps / qps_per_core

    return {
        "current_qps":   current_qps,
        "future_qps":    round(future_qps, 1),
        "required_qps":  round(required_qps, 1),
        "required_cores": round(required_cores, 1),
        "months":        months,
    }

# 示例:当前 1000 QPS,月增长 10%,预测 6 个月后
result = estimate_capacity(1000, 0.10, 6)
# → future_qps=1771, required_qps=2302, required_cores=11.5

20.2 K8s HPA 自动扩缩容

yaml
# 基于 CPU 使用率自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: order-service-hpa
  namespace: prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  minReplicas: 2      # 最少保持 2 个副本
  maxReplicas: 20     # 最多扩到 20 个
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70   # CPU 超过 70% 触发扩容
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60    # 扩容稳定窗口 60s,避免抖动
      policies:
        - type: Pods
          value: 4
          periodSeconds: 60             # 每分钟最多扩 4 个 Pod
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容稳定窗口 5 分钟,避免频繁缩容
      policies:
        - type: Pods
          value: 2
          periodSeconds: 60

20.3 成本优化策略

计算资源优化:
  ① 合理设置 requests/limits,避免资源浪费
     - requests 过高 → 节点利用率低,浪费钱
     - limits 过低 → 容器频繁 OOM,影响稳定性
  ② 使用 VPA(垂直 Pod 自动扩缩容)自动推荐合理的 requests 值
  ③ 离线任务使用 Spot/竞价实例,节省 60%~80% 费用

存储优化:
  ① 日志按天分索引,超过 30 天自动删除(ILM 策略)
  ② 冷数据迁移到对象存储(OSS/S3),比块存储便宜 10 倍
  ③ 镜像定期清理,Harbor 设置保留策略(只保留最近 10 个 tag)

网络优化:
  ① 同 Region 内流量走内网,避免公网流量费用
  ② 静态资源走 CDN,减少源站带宽
  ③ 合理设置 Keep-Alive,减少 TCP 连接建立开销

20.4 Prometheus 容量告警规则

yaml
groups:
  - name: capacity_alerts
    rules:
      # 磁盘预计 4 小时后用满
      - alert: DiskWillBeFull
        expr: |
          predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) < 0
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 磁盘预计 4 小时后用满"

      # 内存使用率持续超过 85%
      - alert: HighMemoryUsage
        expr: |
          (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
            / node_memory_MemTotal_bytes > 0.85
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 内存使用率超过 85%"

      # K8s 节点资源超分
      - alert: NodeResourceOvercommit
        expr: |
          sum by (node) (kube_pod_container_resource_requests{resource="cpu"})
            / kube_node_status_allocatable{resource="cpu"} > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "节点 {{ $labels.node }} CPU 请求超过可分配量的 90%"

手册说明:本手册整理自项目实战问答,所有代码片段均可直接使用或按需调整。建议结合具体业务场景做参数调优,不要照搬数值。

褚成志 · 简历中心