> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flashduty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ServiceMap（服务地图）

> 基于 eBPF 实时连接证据自动生成的服务依赖拓扑，帮你确认某台主机或服务当前真实在和谁通信

<Info>
  **Beta 功能**：ServiceMap 处于 Beta 阶段，功能与界面可能继续调整。它依赖 `monit-agent` 的 eBPF 观测能力——Agent 版本过低、运行环境不支持或未启用 ServiceMap 时，主机会显示为「不支持」或「未启用」，没有拓扑数据。
</Info>

ServiceMap 根据 `monit-agent` 通过 eBPF 观测到的真实网络连接，自动构建主机、进程、容器和工作负载之间的依赖拓扑。它不依赖任何手工配置或静态架构图，展示的是"此刻这台机器实际在和谁通信"，而不是"文档里写的应该和谁通信"。

**入口**：监控对象页面（对象列表里每一行的"拓扑"按钮，或工具栏的"ServiceMap 主机"按钮）。

## 概述

拓扑里的每一条依赖（边）来自 Agent 观测到的一次真实连接：源实体（进程、容器或工作负载）向某个目标端点（`ip:port/protocol`）发起了 `connect`。ServiceMap 的解析器会尝试把这个目标端点匹配到同一网络作用域内的某个已知监听者，从而把一条"连接"变成一条"服务依赖"：

* 如果端点唯一匹配到一个监听者，这条依赖标记为**已确认**。
* 如果端点匹配到多个可能的监听者，标记为**候选**，需要你结合上下文判断真正的对端。
* 如果端点没有匹配到任何监听者，标记为**未解析**，默认不进入拓扑画布（避免外部地址、短暂连接等噪音掩盖真实依赖）。

在故障排查时，ServiceMap 用来快速确认"这台主机 / 这个服务当前的直接依赖和被依赖方是谁"，判断变更或异常的影响半径，而不需要临时登录主机逐个排查连接。在监控对象列表中点击"AI分析"时，系统会把该主机的**监控对象上下文**（主机标识、Agent 版本、集群与 Edge 接入信息，以及该对象可用的诊断工具目录）一并提供给 AI-SRE，不需要手动附加。注意：当前版本的 AI 分析**不会**自动附带该主机的 ServiceMap 拓扑摘要。

<Note>
  查看 ServiceMap 需要 `MonitServiceMapVisit` 权限。没有该权限时，拓扑抽屉会提示"需要 ServiceMap Read 权限才能查看当前拓扑"，对象列表和主机列表本身仍可正常使用。
</Note>

## 如何打开 ServiceMap

在监控对象页面（`/monit/targets`），有两个入口：

* **对象列表里的"拓扑"按钮**：当某一行满足以下全部条件时，操作列会出现"拓扑"链接，点击后直接打开该主机的当前拓扑。
  * `host_id` 存在且格式合法；
  * 该对象上报了 `servicemap` 能力且没有错误码；
  * `graph_available` 为真（当前有可读取的图）；
  * ServiceMap 状态为**正常**、**降级**或**已过期**三者之一。
* **工具栏的"ServiceMap 主机"按钮**：打开全账号范围的 ServiceMap 主机列表（见下文"主机列表"），可以按 Agent 版本、Edge 集群、采集模式、状态筛选后再进入某一台主机的拓扑，同样受上面这条规则约束。

打开后的拓扑抽屉包含两个标签页：**拓扑**（可视化画布）和**数据详情**（查询信息 + 依赖明细表格），标题栏会显示当前图是"实时"还是"已过期"、采集模式，以及观测时间。

## 拓扑画布

### 解析状态筛选

画布上方是一组按钮，对应依赖的解析状态，每个按钮都带数量角标：

| 按钮          | 含义                                                         |
| ----------- | ---------------------------------------------------------- |
| **已确认**     | 已解析到唯一对端服务的依赖。点击可切换画布中已确认依赖节点/连线的显示与隐藏。                    |
| **候选**      | 存在多个可能对端、尚未唯一确定的依赖。点击同样可切换显示与隐藏。                           |
| **未解析**（红色） | 点击不是切换画布可见性，而是打开"未解析端点分组"抽屉（见下文）。未解析端点默认不进入画布。数量为 0 时按钮禁用。 |

如果某条依赖的解析状态既不是"已确认"也不是"候选/未解析"（后端返回状态为已确认，但候选数量并不等于 1 的异常数据），工具栏会额外出现一个**未知 N** 的标签作为提示，这类连线在画布中以灰色点划线呈现。

### 跳数与聚焦模式

* 未进入聚焦模式时，工具栏左侧是"范围"选择器，可选 **1 跳 / 2 跳 / 3 跳**。这是一次新的后端查询（不是纯前端过滤）：跳数越大，加载的节点和边越多，也更容易触发查询上限。单次查询默认最多返回 100 个节点、200 条边。
* **双击任意节点**进入聚焦模式：画布只保留以该节点为中心、按上下游方向展开的局部依赖图。进入聚焦时上游跳数固定重置为 1 跳，下游跳数保留你上次设置的值（初始为 1 跳）；上游、下游跳数可以分别独立调整为 0～3 跳。上游边代表调用你的一方，下游边代表你依赖的一方。
* 也可以用画布右上角的搜索框（按名称、ID、容器或工作负载搜索）直接定位并聚焦某个节点。
* 点击"退出聚焦"或按 <kbd>Esc</kbd> 可退出聚焦，回到当前跳数范围内的整体拓扑。

### 画布控制与交互

* 左下角提供**放大 / 缩小**、当前缩放百分比，以及**显示/隐藏小地图**。
* **适应画布**把整张图缩放到可见范围；**重新布局**用新的随机种子重新排列节点位置（用于拆开重叠严重的节点）。
* 悬停在某个节点上时，与它直接相连的节点/连线保持高亮，其余整体变淡；从该节点**发出**的连线（它的下游依赖）会额外显示指标标签，例如 `↑ 12.3 KB/s` / `↓ 4.1 KB/s`（发送/接收速率）、`✕ 3`（观测窗口内的连接失败次数）、`↻ 2`（重传次数），或在没有明显速率数据时显示 `● 5`（当前活跃连接数）。速率只在该窗口指标完整时才展示。
* 单击节点或连线会在右侧打开详情面板（见下文），面板宽度可拖拽调整；单击画布空白处清除选中。
* 画布左上角常驻一组统计卡片：**服务**（节点数）、**已确认依赖**、**已检查依赖**（本次查询实际检查过的依赖总数，含已确认/候选/未解析）。
* 当本次查询触发截断（达到节点/边上限）时，画布上方会出现"已检查 N 条依赖，达到查询上限"的提示条，附带"聚焦服务"按钮，方便你直接搜索并聚焦到关心的服务，缩小范围重新查看。

节点形状和连线颜色是判断依赖可信度的第一层信号：

| 视觉表现        | 含义                                               |
| ----------- | ------------------------------------------------ |
| 圆形节点        | 已知实体（进程 / 容器 / 工作负载）                             |
| 圆形节点 + 问号图标 | 候选节点：某条"候选"依赖的一个可能对端实体                           |
| 菱形节点        | 尚未归并为实体的目标端点：候选依赖展开出的端点节点，或通过"未解析端点"面板临时定位的未解析端点 |
| 绿色实线        | 已确认依赖                                            |
| 橙色虚线（带动画）   | 候选依赖，会从端点菱形节点分别连向多个候选实体                          |
| 红色点划线       | 未解析依赖，仅在你主动"定位来源"时临时出现                           |
| 灰色点划线       | 未知（后端标记为已确认但候选数量异常的数据）                           |

## 节点详情

单击一个实体或候选节点，右侧详情面板会按三组展示信息：

| 分组  | 字段           | 说明                                                   |
| --- | ------------ | ---------------------------------------------------- |
| 身份  | 显示名称         | 该实体在页面上展示的名称                                         |
|     | 类型           | 实体类型（如 `process_workload`、`container`）               |
|     | Entity ID    | 实体的唯一标识                                              |
|     | Host ID      | 实体所在主机的标识                                            |
| 运行时 | 可执行文件        | 该实体对应的可执行文件名                                         |
|     | Systemd Unit | 该实体对应的 systemd 服务单元（如有）                              |
|     | 容器           | 容器名称（如实体运行在容器内）                                      |
|     | 镜像           | 镜像仓库和版本，格式为 `repository:version`                     |
|     | 工作负载         | Kubernetes 命名空间/工作负载名称，格式为 `namespace/workload_name` |
|     | 实例数          | 归并到该实体下的实例数量                                         |
| 观测  | 首次观测         | 该实体首次被观测到的时间                                         |
|     | 最近观测         | 该实体最近一次被观测到的时间                                       |
|     | 实体身份         | 后端返回的原始身份标识（JSON），用于精确排查                             |

每一行右侧悬停会出现复制按钮，可以直接复制该字段的原始值。面板顶部还有一个"只看它的上下游"按钮，可以从详情面板直接对该节点发起聚焦。

## 依赖详情

单击一条连线（或一个候选/端点节点），详情面板会展示这条依赖的三组信息：

| 分组 | 字段          | 说明                                                      |
| -- | ----------- | ------------------------------------------------------- |
| 标识 | Edge ID     | 该依赖的唯一标识                                                |
|    | 源 Entity ID | 发起连接的源实体 ID                                             |
|    | 源 NetNS ID  | 源实体所在的网络命名空间 ID                                         |
|    | 目标端点        | 目标端点，格式为 `ip:port/protocol`                             |
|    | 证据          | 该依赖被观测到的方式（自由文本，例如 `connect`，表示通过一次 connect 系统调用观测到该连接） |
| 解析 | 解析状态        | `resolved` / `ambiguous` / `unresolved` 等原始解析状态         |
|    | 解析原因        | 解析器返回的原因说明                                              |
|    | 候选数量        | 解析器为该端点找到的可能对端服务数量，大于 1 时依赖标记为候选                        |
|    | 候选被截断       | 候选列表超过返回上限时为"是"，此时只返回了部分候选                              |
|    | 匹配类型        | 候选的匹配方式（如 `exact` 精确匹配、`wildcard` 通配匹配）                 |
|    | 置信度         | 该候选的置信度数值                                               |
|    | Listener ID | 候选对端实际监听器的标识                                            |
| 观测 | 首次观测        | 该依赖首次被观测到的时间                                            |
|    | 最近观测        | 该依赖最近一次被观测到的时间                                          |

判断一条依赖是否可信，优先看**解析状态**和**候选数量**：候选数量为 1 才会被判定为已确认；候选数量大于 1 时属于候选依赖，需要结合**匹配类型**和**置信度**判断哪个候选更可能是真实对端。

## 数据详情标签页

拓扑抽屉的"数据详情"标签页提供一个不依赖画布交互的表格视图，标签本身会显示已确认依赖的数量角标，包含两部分：

**查询信息**：展示本次查询的 Host ID、Network Scope、观测时间、方向与深度、覆盖主机数等（字段含义详见下一节"如何判断拓扑是否可信"）。

**依赖明细**：仅列出已确认和候选依赖（不含未解析），每行包含来源、目标、协议端口、置信度（高 / 中 / 低）、最近观测时间。置信度按该依赖候选中的最高置信度值分级：不低于 0.85 为高，不低于 0.5 为中，其余为低。

## 未解析端点

未解析端点指目标端点没有匹配到任何已知监听者的依赖。它们默认不进入拓扑画布，而是通过独立的"未解析端点分组"抽屉按原因分组展示。

打开方式：点击画布顶部的"未解析"筛选按钮。首次打开时，如果当前拓扑查询使用的是摘要模式（只有分组计数、没有具体端点列表），会自动发起一次补充查询加载完整列表。

已知的分组原因及说明：

| 原因                                | 说明       |
| --------------------------------- | -------- |
| `no_current_listener`             | 未发现当前监听器 |
| `listener_address_family_unknown` | 监听地址族不确定 |
| `invalid_endpoint`                | 端点信息无效   |

后端返回其他未预置文案的原因时，会用通用的"未解析"标签展示，原始原因字符串仍会一并显示。

在某个分组内，你可以：

* 用左上角的搜索框按目标端点或来源服务过滤当前分组内的记录；
* 点击某一行的"定位来源"图标，关闭抽屉并在画布上临时高亮这条未解析依赖的来源实体和目标端点（对应画布上的"正在定位未解析端点"提示条，点击"退出定位"或按 <kbd>Esc</kbd> 退出）；
* 点击右上角"导出 CSV"，导出全部未解析端点（不限于当前选中分组），CSV 列依次为：**目标端点**、**来源服务**、**源 Entity ID**、**解析原因**。

## 主机列表

从工具栏的"ServiceMap 主机"按钮打开，展示账号下所有上报了 ServiceMap 能力的主机，独立于单台主机的拓扑视图。

**筛选条件**：Agent 版本（多值输入，回车确认，最多 20 个）、Edge 集群（多值输入，回车确认，最多 20 个）、采集模式（多选：eBPF / Polling / 未知）。

**状态分布**：一组统计卡片，按固定顺序展示"正常 / 降级 / 已过期 / 初始化中 / 未启用 / 不支持 / 暂无数据"七种状态各自的主机数，点击某个卡片即可按该状态筛选下方列表（再点击一次或点"清除状态筛选"取消）。卡片上方展示扫描覆盖信息："扫描 N 台（上限 M），匹配 X 台，成功分类 Y 台，失败 Z 台"，以及计数生成时间。如果本次统计是有界扫描（达到扫描上限）或部分主机状态读取失败，会分别提示"仅代表本次有界扫描"或"计数不完整"。

各状态的含义：

| 状态   | 含义                               |
| ---- | -------------------------------- |
| 正常   | 当前拓扑新鲜且可用于分析                     |
| 降级   | 采集仍在运行，但当前证据不完整或不是 authoritative |
| 已过期  | 最后可信拓扑已超过新鲜度窗口                   |
| 初始化中 | Agent 正在生成首个可用快照                 |
| 未启用  | 该 Agent 未启用 ServiceMap           |
| 不支持  | 当前 Agent 或运行环境不支持 ServiceMap     |
| 暂无数据 | 已发现能力，但还没有可用的当前拓扑                |

<Note>
  监控对象列表和主机列表还可能出现三种额外的展示态：**未上报**（Agent 未上报 ServiceMap 能力，不能直接判断为不支持）、**状态不可用**（ServiceMap 状态暂时无法读取，监控对象本身仍可用）和**未知状态**（服务端返回了当前前端尚未识别的状态，此时状态列会以「未知状态 (原始值)」的形式展示原始状态值）。这三种不是 ServiceMap 状态的正式取值，只是状态列自身的容错展示。
</Note>

监控对象列表新增了三列与 ServiceMap 相关的列：**ServiceMap 状态**、**采集模式**、**拓扑观测时间**，这三列默认展示，可在列设置中调整显隐；**Host ID** 列默认隐藏，可在列设置中开启。当部分监控对象的 ServiceMap 状态暂时读取失败时，列表顶部会显示提示条「部分 ServiceMap 状态暂时不可用，监控对象列表不受影响」，其余列表功能不受影响。

**主机列表**：列出 Host ID、Agent 版本、Edge 集群（即接入该主机 Agent 的 monitedge 集群名）、ServiceMap 状态、采集模式、拓扑观测时间；满足前文"如何打开 ServiceMap"条件的行会出现"拓扑"操作按钮，点击直接打开该主机的拓扑。

列表采用游标分页、按需加载，因此在加载完所有匹配结果之前无法知道精确总数：底部会显示"已加载 N 台主机"（还有更多可加载）或"共 N 台主机"（已经是全部结果）。如果本次浏览达到扫描边界或部分主机状态不可用，列表上方会提示"主机列表达到扫描边界或部分状态不可用，请继续翻页或收窄筛选"。

## 如何判断拓扑是否可信

拓扑是根据近期观测窗口内的连接证据生成的，不是实时快照，也不保证完整。打开任意一台主机的拓扑后，可以从"数据详情"标签页的"查询信息"区块（以及拓扑抽屉标题栏、画布顶部提示条）综合判断这份拓扑有多可信：

| 字段                    | 说明                                                                                               |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| Network Scope         | 网络作用域标识，端点解析只在同一作用域内进行。默认按 Edge 集群自动划分作用域，无需手动配置。                                                |
| 采集模式                  | 产生这份拓扑证据的采集方式，例如 `ebpf` 内核观测；也可能是 `polling` 或 `hybrid`。                                          |
| 新鲜度                   | `fresh` 表示证据在观测窗口内、可视为实时；其他状态说明这份图已经过期，抽屉标题栏会显示"已过期"标签，并额外提示"请结合观测时间和 coverage 判断，不要将过期图当作实时依赖"。 |
| 覆盖主机                  | 本次拓扑查询实际加载的主机数量。                                                                                 |
| Network Inventory     | 监听端点清单投影的状态，影响端点解析的完整性（例如该投影是否完整可用）。                                                             |
| Kubernetes Enrichment | Kubernetes 元数据富化状态，影响容器与工作负载信息是否完整。                                                              |
| 查询限制                  | 本次查询触发的截断原因列表，**出现即说明这份图不完整**（例如达到节点或边数上限）。                                                      |

<Warning>
  当拓扑存在降级或不完整证据时（`degraded_hosts` 大于 0，或存在降级原因），抽屉会额外提示"当前拓扑包含降级或不完整证据"；查询本身超时或被限流时，会分别提示"请稍后重试或降低深度"和"请稍后重试"。这些都不是错误，而是提醒你此时看到的依赖关系可能不完整，建议缩小跳数范围或稍后重试。
</Warning>

简单来说：**新鲜度不是 `fresh`**、**查询限制列表不为空**、或**降级/不完整证据提示出现**，都说明当前这份拓扑不能当作实时、完整的依赖关系直接下结论，需要结合观测时间进一步确认。
