首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >网工如何利用 AI 优化链路巡检?聊聊各技术岗位的 AI 实践路径

网工如何利用 AI 优化链路巡检?聊聊各技术岗位的 AI 实践路径

原创
作者头像
大盘鸡拌面
发布2026-08-09 22:17:45
发布2026-08-09 22:17:45
1370
举报

做网工的朋友应该都有过这种体验——每周固定的链路巡检,几十台上百台设备,逐个 SSH 上去敲 ​​show interface​​、​​show ip route​​、​​show logging​​,然后人肉对比上周的数据看有没有异常。一上午下来眼睛都看花了,还不一定看得准。

这事儿吧,说实话,早就该被自动化掉了。脚本化巡检很多人在做,但脚本只能"采集"和"比对阈值",真正复杂的故障判断——比如某条链路丢包率从 0.01% 涨到 0.03%,脚本不会告诉你这是光模块老化还是对端设备 buffer 不足——还是得靠人。

AI 介入之后,这个事情就变得有意思了。不是说什么"AI 替代网工",而是 AI 帮你把碎片化的设备数据拼成一张完整的网络健康画像,你只需要做最后的判断和决策。

今天就以网工的链路巡检为主线,聊聊各技术岗位怎么找到自己的 AI 实践路径。


一、网工:AI 驱动的链路智能巡检

1.1 传统巡检的痛点

先说传统巡检怎么做的,方便对比:

代码语言:javascript
复制
巡检员 → SSH登录设备 → 逐条敲命令 → 肉眼对比历史数据 → 手动填Excel → 提交巡检报告

这个流程的问题太明显了:

  • 效率低:100 台设备,每台 5 分钟,就是 8 个多小时
  • 容易漏:人眼对比数据,细微的变化很容易忽略
  • 不智能:阈值告警只能判断"超没超",判断不了"为什么超"
  • 没法关联:A 设备的接口问题和 B 设备的路由抖动可能是同一个根因,但你分别看的时候发现不了
1.2 AI 巡检的整体架构

改造之后的流程长这样:

整个链路的核心变化是:从"采集+阈值判断"变成了"采集+AI理解+根因关联"

1.3 实战代码:链路巡检 + AI 分析

下面是一套完整的巡检脚本,用 Netmiko 批量采集,然后把数据喂给大模型做智能分析:

代码语言:javascript
复制
#!/usr/bin/env python3
"""
网络链路智能巡检脚本
- 批量采集设备接口状态、CRC 错误包、光功率、路由表摘要
- AI 分析链路健康度并给出根因建议
"""

import json
import re
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor, as_completed
from netmiko import ConnectHandler
from openai import OpenAI

# ============ 设备清单 ============
DEVICES = [
    {"host": "10.10.1.1", "name": "CORE-SW-01", "type": "cisco_ios"},
    {"host": "10.10.1.2", "name": "CORE-SW-02", "type": "cisco_ios"},
    {"host": "10.10.2.1", "name": "EDGE-RT-01",  "type": "cisco_ios"},
    {"host": "10.10.2.2", "name": "EDGE-RT-02",  "type": "huawei"},
    {"host": "10.10.3.1", "name": "DC-FW-01",    "type": "fortinet"},
]

# 巡检命令模板(按设备类型区分)
INSPECT_COMMANDS = {
    "cisco_ios": [
        "show interfaces | include (Ethernet|input errors|output errors|CRC|runts|giants)",
        "show ip interface brief | exclude unassigned",
        "show logging | last 50",
        "show ip route summary",
    ],
    "huawei": [
        "display interface | include (GigabitEthernet|input error|output error|CRC)",
        "display ip interface brief",
        "display logbuffer | last 50",
        "display ip routing-table summary",
    ],
    "fortinet": [
        "diagnose hardware deviceinfo nic",
        "diagnose sys top",
        "execute log filter category traffic",
    ],
}

# ============ 第一步:批量采集 ============
def collect_device(device):
    """SSH 登录设备执行巡检命令,返回原始输出"""
    result = {
        "device": device["name"],
        "host": device["host"],
        "timestamp": datetime.now().isoformat(),
        "raw_output": {},
    }
    try:
        conn = ConnectHandler(
            host=device["host"],
            device_type=device["type"],
            username="inspect_bot",
            password="REPLACE_WITH_VAULT_TOKEN",
            timeout=20,
        )
        commands = INSPECT_COMMANDS.get(device["type"], [])
        for cmd in commands:
            output = conn.send_command(cmd, read_timeout=30)
            result["raw_output"][cmd] = output
        conn.disconnect()
        result["status"] = "success"
    except Exception as e:
        result["status"] = "failed"
        result["error"] = str(e)
    return result


def batch_collect(devices, max_workers=5):
    """多线程并行采集所有设备"""
    all_results = []
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {executor.submit(collect_device, dev): dev for dev in devices}
        for future in as_completed(futures):
            dev = futures[future]
            try:
                result = future.result()
                all_results.append(result)
                print(f"[OK] {dev['name']} 采集完成")
            except Exception as e:
                print(f"[FAIL] {dev['name']} 采集失败: {e}")
                all_results.append({
                    "device": dev["name"],
                    "status": "failed",
                    "error": str(e),
                })
    return all_results


# ============ 第二步:数据清洗 ============
def parse_interface_errors(raw_text):
    """从 show interfaces 输出中提取错误计数"""
    issues = []
    # 匹配类似 "0 input errors, 0 CRC, 0 frame" 的行
    error_pattern = re.compile(
        r'(\d+)\s+input errors.*?(\d+)\s+CRC.*?(\d+)\s+frame', re.IGNORECASE
    )
    for line in raw_text.split("\n"):
        match = error_pattern.search(line)
        if match:
            input_errors, crc, frame = map(int, match.groups())
            if input_errors > 0 or crc > 0:
                issues.append({
                    "input_errors": input_errors,
                    "crc": crc,
                    "frame": frame,
                    "raw_line": line.strip(),
                })
    return issues


def clean_results(raw_results):
    """清洗原始采集数据,提取关键指标"""
    cleaned = []
    for item in raw_results:
        if item["status"] != "success":
            cleaned.append({
                "device": item["device"],
                "status": "unreachable",
                "issues": [],
            })
            continue
        
        issues = []
        for cmd, output in item["raw_output"].items():
            if "interface" in cmd.lower():
                iface_issues = parse_interface_errors(output)
                issues.extend(iface_issues)
        
        cleaned.append({
            "device": item["device"],
            "host": item["host"],
            "timestamp": item["timestamp"],
            "status": "reachable",
            "interface_issues": issues,
            "raw_output": item["raw_output"],
        })
    return cleaned


# ============ 第三步:AI 智能分析 ============
client = OpenAI(
    base_url="http://10.10.100.50:8000/v1",  # 内网部署的开源模型
    api_key="internal-not-needed",
)

ANALYSIS_PROMPT = """你是一个资深网络工程师,正在分析网络设备巡检数据。

以下是本次巡检采集到的设备状态信息,包括接口错误计数、日志摘要、路由表摘要。
请完成以下分析:

1. **健康度评分**:为每台设备打分(0-100),100 表示完全健康。
2. **异常识别**:找出所有异常项,包括但不限于:
   - 接口 CRC 错误 / input errors 增长
   - 链路带宽利用率异常
   - 路由表条目突变
   - 日志中的告警信息
3. **根因推测**:对每个异常给出可能的原因(光模块老化?线缆问题?对端设备问题?配置变更?)
4. **关联分析**:如果多台设备出现关联性异常(比如两台对端设备的同一链路都有 CRC),指出关联关系。
5. **处置建议**:给出具体的处理步骤和优先级(P0/P1/P2)。

巡检数据:
{data}

请以 JSON 格式输出分析结果。
"""


def ai_analyze(cleaned_data):
    """将清洗后的数据喂给大模型做智能分析"""
    # 压缩数据,避免超出上下文窗口
    compressed = []
    for item in cleaned_data:
        # 只传关键信息,不传完整 raw_output
        entry = {
            "device": item["device"],
            "status": item["status"],
        }
        if "interface_issues" in item:
            entry["interface_issues"] = item["interface_issues"]
        # 日志只取最近的关键行
        if "raw_output" in item:
            for cmd, output in item["raw_output"].items():
                if "log" in cmd.lower():
                    lines = output.strip().split("\n")
                    entry["recent_logs"] = lines[-10:] if len(lines) > 10 else lines
        compressed.append(entry)
    
    prompt = ANALYSIS_PROMPT.format(data=json.dumps(compressed, ensure_ascii=False, indent=2))
    
    response = client.chat.completions.create(
        model="qwen2.5-14b-instruct",
        messages=[
            {"role": "system", "content": "你是网络运维专家,擅长从设备巡检数据中发现潜在问题并给出专业建议。"},
            {"role": "user", "content": prompt},
        ],
        temperature=0.3,
        max_tokens=4096,
    )
    
    return response.choices[0].message.content


# ============ 第四步:生成报告 ============
def generate_report(cleaned_data, ai_analysis):
    """生成最终的巡检报告"""
    report = f"""
# 网络链路智能巡检报告

**巡检时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
**巡检设备数**: {len(cleaned_data)}
**正常设备**: {sum(1 for d in cleaned_data if d['status'] == 'reachable' and not d.get('interface_issues'))}
**异常设备**: {sum(1 for d in cleaned_data if d.get('interface_issues'))}
**不可达设备**: {sum(1 for d in cleaned_data if d['status'] == 'unreachable')}

---

## AI 分析结果

{ai_analysis}

---

## 设备明细

"""
    for item in cleaned_data:
        status_emoji = "✅" if item["status"] == "reachable" and not item.get("interface_issues") else "⚠️"
        report += f"### {status_emoji} {item['device']}\n"
        report += f"- 状态: {item['status']}\n"
        if item.get("interface_issues"):
            report += f"- 接口异常: {len(item['interface_issues'])} 项\n"
            for issue in item["interface_issues"]:
                report += f"  - input_errors={issue['input_errors']}, CRC={issue['crc']}\n"
        report += "\n"
    
    return report


# ============ 主流程 ============
if __name__ == "__main__":
    print("=" * 60)
    print("开始网络链路智能巡检")
    print("=" * 60)
    
    # 1. 批量采集
    print("\n[1/4] 采集设备状态...")
    raw_data = batch_collect(DEVICES)
    
    # 2. 数据清洗
    print("\n[2/4] 清洗巡检数据...")
    cleaned = clean_results(raw_data)
    
    # 3. AI 分析
    print("\n[3/4] AI 智能分析中...")
    ai_result = ai_analyze(cleaned)
    print(f"AI 分析完成,结果长度: {len(ai_result)} 字符")
    
    # 4. 生成报告
    print("\n[4/4] 生成巡检报告...")
    report = generate_report(cleaned, ai_result)
    
    # 保存报告
    report_file = f"inspection_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
    with open(report_file, "w", encoding="utf-8") as f:
        f.write(report)
    
    print(f"\n巡检完成!报告已保存到 {report_file}")
1.4 实际场景:数据中心互联链路质量劣化

说个真实场景。我们有两个数据中心通过裸光纤互联,跑 OSPF,平时链路利用率不高,一直挺稳定。某天巡检脚本跑完之后,AI 分析报告里冒出来一条:

DCI-LINK-01 (CORE-SW-01 ↔ CORE-SW-02)

  • CRC 错误:本周累计 347 次(上周 12 次,环比增长 2792%)
  • input errors:本周 1284 次(上周 45 次)
  • 健康度评分:62/100
  • 根因推测:CRC 错误暴增但链路未 down,最可能的原因是光模块接收功率劣化或光纤接头污染。建议检查光功率。
  • 优先级:P1
  • 建议操作
  1. 查看 ​​show interfaces transceiver​​ 确认光功率是否在阈值内
  2. 如 Rx power < -14 dBm,安排窗口清洁光纤接头
  3. 如清洁后仍异常,准备更换光模块

要是搁以前,这种 CRC 从 12 涨到 347 的变化,人眼看 Excel 可能就忽略了——毕竟链路没 down,业务没报障,谁会注意到一个几百次的错误计数?但 AI 不一样,它会把环比变化算出来,而且直接告诉你"大概率是光模块问题,去查光功率"。

这个场景的核心价值在于:AI 不是替代你做判断,而是帮你从海量数据里把"值得关注的"筛出来。你一看就知道该怎么处理了。

1.5 巡检时序图

一次完整的 AI 巡检流程是这样的:


二、开发岗:AI 辅助代码审查与依赖升级评估

2.1 为什么不是"AI 写代码"

前面几篇文章说了很多 AI 写代码的场景,这次换个角度。对于有一定经验的后端开发来说,"AI 帮我写个 CRUD"其实价值不大——那些代码你自己写也就十分钟。真正费时间的是这些事:

  • 代码审查:一个 2000 行的 PR,逐行看完得半小时,而且容易走神
  • 依赖升级评估:Spring Boot 从 2.7 升到 3.0,几十个依赖变了,哪些会影响你的代码?
  • 遗留代码理解:接手一个没文档的老模块,看代码看到怀疑人生

这些场景的共同点是:信息量大、需要理解上下文、但不需要从零创造。这恰恰是 AI 最擅长的事。

2.2 实战:AI 辅助 PR 审查
代码语言:javascript
复制
#!/usr/bin/env python3
"""
AI 辅助代码审查
- 从 GitLab/GitHub 获取 PR diff
- 按文件拆分后喂给 AI 审查
- 输出结构化的审查意见
"""

import re
import json
import subprocess
from openai import OpenAI

client = OpenAI(
    base_url="http://10.10.100.50:8000/v1",
    api_key="internal-not-needed",
)

# 团队代码规范(喂给 AI 作为审查标准)
TEAM_CODING_STANDARDS = """
团队代码规范摘要:
1. 所有外部输入必须做参数校验,推荐使用 @Valid + 自定义 Validator
2. Service 层方法必须有日志记录(入参 + 执行耗时)
3. 数据库查询禁止使用 SELECT *,必须指定字段
4. 所有 HTTP 接口必须有 @Operation 注解(Swagger 文档)
5. 异常处理统一走 GlobalExceptionHandler,禁止在 Controller 里 try-catch
6. 线程池禁止使用 new Thread(),必须走 ThreadPoolExecutor 或 @Async
7. 敏感信息(密码、密钥)禁止硬编码,必须走配置中心
8. SQL 语句中禁止拼接字符串,必须使用参数化查询
"""

REVIEW_PROMPT = """你是一个严格的代码审查员。请基于以下团队代码规范审查这段代码变更。

## 团队代码规范
{standards}

## 变更文件
文件名: {filename}
变更类型: {change_type}

## 代码 Diff
```diff
{diff_content}

请从以下维度审查:

  1. 规范符合性:是否违反团队编码规范?逐条检查。
  2. 安全隐患:SQL 注入、XSS、硬编码密钥、越权风险?
  3. 性能问题:N+1 查询、大对象内存泄漏、循环中的 IO 操作?
  4. 逻辑缺陷:边界条件、空指针、并发安全、事务一致性?
  5. 可维护性:命名是否清晰、复杂度是否过高、是否有魔法数字?

输出 JSON 格式: {{ "severity": "blocker|major|minor|suggestion", "issues": [ {{ "line": "行号或行号范围", "type": "security|performance|logic|style", "severity": "blocker|major|minor", "message": "问题描述", "suggestion": "修改建议" }} ], "summary": "整体评价(一句话)" }} """

def get_pr_diff(pr_url): """获取 PR 的 diff 内容(这里用 git 命令模拟)""" \# 实际环境中用 GitLab/GitHub API 获取 result = subprocess.run( ["git", "diff", "--unified=5", "main...feature-branch"], capture_output=True, text=True, encoding="utf-8" ) return result.stdout

def split_diff_by_file(diff_text): """将 diff 按文件拆分""" files = [] current_file = None current_lines = []

代码语言:javascript
复制
for line in diff_text.split("\n"):
    if line.startswith("diff --git"):
        if current_file:
            files.append({
                "filename": current_file,
                "diff": "\n".join(current_lines),
            })
        match = re.search(r'diff --git a/(.+?) b/', line)
        current_file = match.group(1) if match else "unknown"
        current_lines = [line]
    else:
        current_lines.append(line)

if current_file:
    files.append({
        "filename": current_file,
        "diff": "\n".join(current_lines),
    })

return files

def review_file(file_info): """用 AI 审查单个文件的变更""" \# 跳过非代码文件 if not any(file_info["filename"].endswith(ext) for ext in [".java", ".py", ".go", ".ts", ".js"]): return {"filename": file_info["filename"], "skipped": True}

代码语言:javascript
复制
prompt = REVIEW_PROMPT.format(
    standards=TEAM_CODING_STANDARDS,
    filename=file_info["filename"],
    change_type="modified",
    diff_content=file_info["diff"][:8000],  # 截断超长 diff
)

response = client.chat.completions.create(
    model="qwen2.5-coder-14b",
    messages=[
        {"role": "system", "content": "你是资深代码审查员,严格但不过度吹毛求疵。"},
        {"role": "user", "content": prompt},
    ],
    temperature=0.2,
    max_tokens=2048,
)

return {
    "filename": file_info["filename"],
    "review": response.choices[0].message.content,
}

def run_review(pr_diff): """执行完整的 PR 审查""" files = split_diff_by_file(pr_diff) print(f"共 {len(files)} 个文件变更")

代码语言:javascript
复制
all_reviews = []
for f in files:
    print(f"  审查中: {f['filename']}")
    review = review_file(f)
    all_reviews.append(review)

return all_reviews

执行

if name == "main": diff = get_pr_diff("<​​https://gitlab.example.com/project/merge_requests/123​​>") reviews = run_review(diff)

代码语言:javascript
复制
print("\n" + "=" * 60)
print("代码审查报告")
print("=" * 60)
for r in reviews:
    if r.get("skipped"):
        continue
    print(f"\n📄 {r['filename']}")
    print(r["review"])
代码语言:javascript
复制
### 2.3 实际场景:一次差点上线的 SQL 注入

有次我们团队一个新人提了个 PR,在 Controller 里直接拼 SQL 查数据。代码大概是:

```java
// ❌ 危险代码
@GetMapping("/search")
public List<User> searchUsers(@RequestParam String keyword) {
    String sql = "SELECT * FROM users WHERE name LIKE '%" + keyword + "%'";
    return jdbcTemplate.query(sql, new UserRowMapper());
}

AI 审查结果直接给了 blocker:

代码语言:javascript
复制
{
  "severity": "blocker",
  "issues": [
    {
      "line": "第 42 行",
      "type": "security",
      "severity": "blocker",
      "message": "SQL 注入风险:keyword 参数直接拼接进 SQL 语句,攻击者可通过构造特殊输入执行任意 SQL。",
      "suggestion": "使用参数化查询:jdbcTemplate.query(\"SELECT id, name, email FROM users WHERE name LIKE ?\", new Object[]{\"%\" + keyword + \"%\"}, new UserRowMapper())"
    },
    {
      "line": "第 42 行",
      "type": "style",
      "severity": "major",
      "message": "违反规范第 3 条:使用了 SELECT *,应指定具体字段。",
      "suggestion": "改为 SELECT id, name, email FROM users"
    }
  ]
}

人工 review 的时候如果走神了,这个真有可能漏过去。但 AI 不会走神,它每次都逐条比对规范。当然,AI 也会误报,所以最终拍板的还是人。


三、运维岗:AI 驱动的容量规划与趋势预测

3.1 从"被动扩容"到"主动预测"

运维同学最怕什么?不是故障本身,而是"明明监控都有,但就是没提前发现容量快不够了"。

传统的容量管理基本是两种模式:

  • 阈值告警:磁盘超过 80% 就告警,但等到 80% 的时候已经有点晚了
  • 定期巡检:每周看一次资源使用率,但看不出趋势

AI 介入后可以做的是趋势预测——根据历史数据预测未来 N 天的资源使用趋势,提前预警。

3.2 实战:容量趋势预测
代码语言:javascript
复制
#!/usr/bin/env python3
"""
AI 容量趋势预测
- 从 Prometheus 拉取历史指标
- AI 分析趋势并给出扩容建议
"""

import json
import requests
from datetime import datetime, timedelta
from openai import OpenAI

PROMETHEUS_URL = "http://prometheus:9090"
client = OpenAI(base_url="http://10.10.100.50:8000/v1", api_key="internal")

# 关键监控指标
METRICS_TO_TRACK = {
    "cpu_usage": '100 - (avg(rate(node_cpu_seconds_total{{instance="{inst}",mode="idle"}}[5m])) * 100)',
    "memory_usage": '(1 - (node_memory_MemAvailable_bytes{{instance="{inst}"}} / node_memory_MemTotal_bytes{{instance="{inst}"}})) * 100',
    "disk_usage": '100 - ((node_filesystem_avail_bytes{{instance="{inst}",mountpoint="/"}} / node_filesystem_size_bytes{{instance="{inst}",mountpoint="/"}}) * 100)',
}

# 要监控的服务器
SERVERS = [
    {"name": "app-server-01", "instance": "10.10.1.10:9100"},
    {"name": "app-server-02", "instance": "10.10.1.11:9100"},
    {"name": "db-server-01",  "instance": "10.10.1.20:9100"},
]


def query_prometheus(query, days=30):
    """从 Prometheus 查询过去 N 天的历史数据(每天一个数据点)"""
    end = datetime.now()
    start = end - timedelta(days=days)
    
    resp = requests.get(f"{PROMETHEUS_URL}/api/v1/query_range", params={
        "query": query,
        "start": start.timestamp(),
        "end": end.timestamp(),
        "step": "1d",  # 每天一个点
    })
    data = resp.json()
    if data["status"] != "success":
        return []
    
    result = data["data"]["result"]
    if not result:
        return []
    
    # 提取时间序列
    values = []
    for ts, val in result[0]["values"]:
        values.append({
            "date": datetime.fromtimestamp(float(ts)).strftime("%m-%d"),
            "value": float(val),
        })
    return values


def collect_capacity_data():
    """采集所有服务器的容量数据"""
    all_data = []
    for server in SERVERS:
        server_data = {"name": server["name"], "metrics": {}}
        for metric_name, query_template in METRICS_TO_TRACK.items():
            query = query_template.format(inst=server["instance"])
            history = query_prometheus(query)
            server_data["metrics"][metric_name] = history
        all_data.append(server_data)
        print(f"[OK] {server['name']} 数据采集完成")
    return all_data


PREDICT_PROMPT = """你是一个运维容量规划专家。以下是服务器过去 30 天的资源使用数据。

请分析:
1. **当前状态**:每台服务器的 CPU/内存/磁盘当前使用率
2. **增长趋势**:哪个指标在持续增长?日均增长率是多少?
3. **预测**:按当前趋势,预计多少天后会触及告警阈值(CPU>80%, 内存>85%, 磁盘>80%)?
4. **建议**:是否需要扩容?扩容方案是什么(加机器?升配?清理数据?)
5. **风险提示**:有没有突增迹象?是否需要关注特定业务事件的影响?

数据:
{data}

以 JSON 格式输出,包含每台服务器的分析结果。
"""


def ai_predict(data):
    """AI 分析容量趋势"""
    prompt = PREDICT_PROMPT.format(data=json.dumps(data, ensure_ascii=False, indent=2))
    response = client.chat.completions.create(
        model="qwen2.5-14b-instruct",
        messages=[
            {"role": "system", "content": "你是运维容量规划专家。"},
            {"role": "user", "content": prompt},
        ],
        temperature=0.3,
        max_tokens=4096,
    )
    return response.choices[0].message.content


if __name__ == "__main__":
    print("采集容量数据...")
    data = collect_capacity_data()
    
    print("\nAI 趋势分析中...")
    result = ai_predict(data)
    
    print("\n" + "=" * 60)
    print("容量规划报告")
    print("=" * 60)
    print(result)
3.3 实际场景:提前发现磁盘容量瓶颈

有一次 AI 分析报告说:

db-server-01 磁盘使用率趋势分析

  • 当前值:67%
  • 日均增长:0.8%
  • 预计 16 天后达到 80% 告警阈值
  • 根因:数据库 binlog 未开启自动清理,每天产生约 2GB
  • 建议:P2 优先级,本周内配置 ​​expire_logs_days=7​​,预计释放约 14GB

说实话这个场景不算复杂,但关键在于"提前 16 天预警"。如果是传统的阈值告警,等到 80% 的时候你只剩几天时间处理了,可能还赶不上周末维护窗口。AI 给你留了充足的时间去规划。

3.4 容量预测流程


四、DBA 岗:AI 辅助慢查询分析

4.1 DBA 的痛点

DBA 日常最大的时间黑洞是什么?慢查询优化

一个中等规模的业务系统,每天产生的慢查询可能有几百上千条。DBA 不可能逐条分析,通常是挑 Top 10 看看。但很多时候,真正有问题的查询可能不在 Top 10 里——它执行次数不多,但每次都扫全表,影响的是关键接口的响应时间。

AI 可以帮你做到:批量分析慢查询,按影响面排序,给出优化建议

4.2 实战代码
代码语言:javascript
复制
#!/usr/bin/env python3
"""
AI 慢查询分析助手
- 从 MySQL slow log 采集慢查询
- AI 分析执行计划 + 给出优化建议
"""

import re
import json
import pymysql
from collections import defaultdict
from openai import OpenAI

client = OpenAI(base_url="http://10.10.100.50:8000/v1", api_key="internal")

# 数据库连接配置
DB_CONFIG = {
    "host": "10.10.1.20",
    "port": 3306,
    "user": "monitor",
    "password": "REPLACE_WITH_VAULT",
    "database": "mysql",
}


def get_slow_queries(limit=50):
    """从 performance_schema 获取慢查询"""
    conn = pymysql.connect(**DB_CONFIG)
    try:
        sql = """
        SELECT 
            DIGEST_TEXT as normalized_sql,
            COUNT_STAR as exec_count,
            AVG_TIMER_WAIT/1000000000 as avg_ms,
            SUM_ROWS_EXAMINED as total_rows_scanned,
            SUM_ROWS_SENT as total_rows_returned,
            FIRST_SEEN,
            LAST_SEEN
        FROM performance_schema.events_statements_summary_by_digest
        WHERE AVG_TIMER_WAIT/1000000000 > 1000  -- 平均执行时间 > 1秒
        ORDER BY AVG_TIMER_WAIT DESC
        LIMIT %s
        """
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        cursor.execute(sql, (limit,))
        return cursor.fetchall()
    finally:
        conn.close()


def get_explain(sql_text):
    """获取查询的执行计划"""
    conn = pymysql.connect(**DB_CONFIG)
    try:
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        # 注意:生产环境需要做 SQL 安全校验
        cursor.execute(f"EXPLAIN {sql_text}")
        return cursor.fetchall()
    except Exception as e:
        return [{"error": str(e)}]
    finally:
        conn.close()


ANALYSIS_PROMPT = """你是资深 DBA。请分析以下慢查询并给出优化建议。

## 慢查询信息
- 规范化 SQL: {sql}
- 执行次数: {count}
- 平均耗时: {avg_ms}ms
- 扫描行数: {rows_scanned}
- 返回行数: {rows_returned}
- 扫描/返回比: {scan_ratio}

## 执行计划
{explain}

请分析:
1. **性能瓶颈**:全表扫描?索引未命中?临时表?文件排序?
2. **扫描效率**:扫描/返回比是否过高?是否需要优化 LIMIT 或分页?
3. **索引建议**:建议创建什么索引?给出 CREATE INDEX 语句。
4. **SQL 改写**:是否可以改写 SQL 提升效率?
5. **影响评估**:这个查询影响什么业务?优化后预期提升多少?

以 JSON 格式输出。
"""


def analyze_slow_query(query):
    """AI 分析单条慢查询"""
    rows_scanned = query.get("total_rows_scanned", 0) or 0
    rows_returned = query.get("total_rows_returned", 0) or 1
    scan_ratio = rows_scanned / max(rows_returned, 1)
    
    # 获取执行计划
    explain = get_explain(query["normalized_sql"])
    
    prompt = ANALYSIS_PROMPT.format(
        sql=query["normalized_sql"][:500],
        count=query["exec_count"],
        avg_ms=round(query["avg_ms"], 2),
        rows_scanned=rows_scanned,
        rows_returned=rows_returned,
        scan_ratio=round(scan_ratio, 2),
        explain=json.dumps(explain, default=str, indent=2),
    )
    
    response = client.chat.completions.create(
        model="qwen2.5-14b-instruct",
        messages=[
            {"role": "system", "content": "你是资深 MySQL DBA。"},
            {"role": "user", "content": prompt},
        ],
        temperature=0.2,
        max_tokens=2048,
    )
    
    return response.choices[0].message.content


if __name__ == "__main__":
    print("采集慢查询...")
    slow_queries = get_slow_queries(limit=20)
    print(f"共 {len(slow_queries)} 条慢查询")
    
    results = []
    for i, q in enumerate(slow_queries, 1):
        print(f"[{i}/{len(slow_queries)}] 分析中: {q['normalized_sql'][:60]}...")
        analysis = analyze_slow_query(q)
        results.append({
            "sql": q["normalized_sql"],
            "avg_ms": round(q["avg_ms"], 2),
            "exec_count": q["exec_count"],
            "analysis": analysis,
        })
    
    # 生成报告
    print("\n" + "=" * 60)
    print("慢查询分析报告")
    print("=" * 60)
    for r in results:
        print(f"\n📋 平均 {r['avg_ms']}ms | 执行 {r['exec_count']} 次")
        print(f"SQL: {r['sql'][:100]}")
        print(f"分析: {r['analysis'][:200]}")
4.3 实际场景:一个隐藏的分页性能炸弹

有次 AI 分析报告里标了一条慢查询,执行次数不多(每天 200 次左右),平均耗时 3.2 秒,但扫描了 480 万行只返回 20 行。SQL 大概是:

代码语言:javascript
复制
SELECT * FROM orders WHERE user_id = ? AND status = 1 ORDER BY create_time DESC LIMIT 20 OFFSET 10000;

AI 的分析:

问题:深度分页查询,OFFSET 10000 导致 MySQL 需要扫描前 10000 条记录再丢弃。 扫描/返回比:240,000:1(极差) 索引建议:已有 ​​idx_user_status_time(user_id, status, create_time)​​ 索引,但深度分页导致索引效果递减。 改写建议:使用游标分页替代 OFFSET: SELECT * FROM orders WHERE user_id = ? AND status = 1 AND create_time < ? ORDER BY create_time DESC LIMIT 20; 预期效果:扫描行数从 480 万降到 20,响应时间从 3.2s 降到 <10ms。

这条查询不在慢日志 Top 10 里(因为执行次数少,总耗时不是最高),但 AI 按扫描效率排序时把它捞出来了。改完之后,用户"订单历史"翻页的接口直接从 3 秒变成了 10 毫秒。


五、各岗位 AI 实践路径总结

聊了这么多岗位的实战,最后梳理一下各技术岗位找到自己 AI 实践路径的方法论:

说到底就三句话:

  1. 别想"AI 能干什么",想"我每周哪些时间花得最不值" —— 那些重复的、看数据的、按规则执行的事,就是 AI 的切入点。
  2. 不是所有事都需要 AI —— 纯阈值判断用脚本就行了,别为了用 AI 而 AI。AI 的价值在于"理解和关联",不在于"判断超没超"。
  3. 从最小闭环开始 —— 不要一上来就搞"AI 运维平台"。先拿一个具体场景(比如链路巡检),跑通"采集→AI分析→人工验证→固化"这个闭环,再逐步扩展。
避坑提醒

最后说几个实际落地中容易踩的坑:

  • AI 会幻觉:它可能说"建议创建索引 idx_xxx",但这个索引可能已经存在了。所有 AI 给的建议都要人工验证后再执行,别盲目信任。
  • 数据安全:如果你用的是公网 API,别把真实 SQL、IP 地址、密码哈希这些喂进去。有条件就内网部署开源模型,前面那篇文章讲过 vLLM 的部署方法。
  • Prompt 调优是个体力活:第一次写 prompt 效果通常不好,需要反复调。建议把好的 prompt 沉淀下来,团队共享。
  • 别试图一步到位:先解决"看得见"的问题(比如 CRC 暴增、慢查询),再追求"看不见"的问题(比如趋势预测、根因关联)。能力是逐步积累的。

网工也好、开发也好、运维也好、DBA 也好,每个技术岗位都有自己独特的"信息处理瓶颈"。AI 不是万能药,但它确实是放大你能力的杠杆。关键不在于 AI 有多强,而在于你能不能找到那个"用 AI 之前要花 2 小时、用了之后只要 10 分钟"的场景。

找到了,你就上路了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、网工:AI 驱动的链路智能巡检
    • 1.1 传统巡检的痛点
    • 1.2 AI 巡检的整体架构
    • 1.3 实战代码:链路巡检 + AI 分析
    • 1.4 实际场景:数据中心互联链路质量劣化
    • 1.5 巡检时序图
  • 二、开发岗:AI 辅助代码审查与依赖升级评估
    • 2.1 为什么不是"AI 写代码"
    • 2.2 实战:AI 辅助 PR 审查
  • 执行
    • 三、运维岗:AI 驱动的容量规划与趋势预测
      • 3.1 从"被动扩容"到"主动预测"
      • 3.2 实战:容量趋势预测
      • 3.3 实际场景:提前发现磁盘容量瓶颈
      • 3.4 容量预测流程
    • 四、DBA 岗:AI 辅助慢查询分析
      • 4.1 DBA 的痛点
      • 4.2 实战代码
      • 4.3 实际场景:一个隐藏的分页性能炸弹
    • 五、各岗位 AI 实践路径总结
      • 避坑提醒
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档