一、卡慢来源
1.分析:卡慢感受来源与原因
1.1 卡慢感受来源
- 用户使用前端页面卡慢
- Web接口响应慢。
- 前端渲染逻辑不合理(数据量大时阻塞)。
- 外部调用 ASM 服务卡慢
- 对外 API 接口响应慢。
1.2 卡慢原因深度分析
(1)MongoDB 问题
- 内存不足,缓存频繁淘汰,磁盘IO高
- 大表(如
资产表)未分片,导致分片间内存使用不均衡。 - 索引过多且部分不合理,占用大量内存。
- 大表(如
- IO 压力大
- 后台任务对 MongoDB 读写频率过高(需增加缓存机制)。
- 锁竞争(SchemaLock)
- 库表太多,导致
schemaLock锁竞争严重,阻塞语句执行。 - 解决措施:中台调整 WiredTiger Hash 桶;合并小表减少表数量。
- 库表太多,导致
(2)后端代码问题
- 鉴权开销:每个接口都重复请求
auth认证接口(~100ms)。 - 级联树依赖:请求级联树接口(缓存过期后耗时 500-600ms)。
- 接口功能臃肿:
- 单接口包含过多逻辑(如
on_list查太多表)。 资产组接口被多处调用,需求不一但混用同一接口。
- 单接口包含过多逻辑(如
- 业务逻辑复杂/不合理:
- 存在全表扫描统计(如资产清点)。
- 循环查库代码。
所属主机逻辑冗余,几乎所有查询都带,导致业务复杂化。
- 慢查询:
- 缺乏缓存(实时性不高的统计)。
- 接口间依赖过重。
(3)前端代码问题
- 前端逻辑不合理,导致后端返回快但前端渲染慢。
(4)特定环境问题
- OpenAPI 频繁请求:请求过于频繁导致 CPU 飙升。
- 解决措施:开分片;增加限流措施。
1.3 目标及判定标准
- 网上问题:实现 0 网上卡慢问题。
- 页面响应速度:保5争3(不超5秒,最好3秒内)。
- 判定标准:从第一个元素就绪到触发
load事件的时间(或特定核心 DIV 可视)。
- 判定标准:从第一个元素就绪到触发
- 接口响应速度:简单接口 <500ms,复杂接口 <2s。
- 判定工具:
Server-Timing响应头。
- 判定工具:
- 资源占用:降低 Mongo 读写 QPS 及内存占用。
2.优化思路总结
这是一个基于你提供的详细报告整理出的优化思路思维导图。
核心策略总结:
- 做减法:接口字段裁剪、移除冗余业务逻辑(如循环查库)。
- 做拆分:大接口拆解为多个独立小接口(资产列表)、同步转异步。
- 按需取:全量加载改为逐级/分页加载(资产树、OpenAPI)。
- 底座优化:Mongo分片、索引治理与锁冲突解决。
1 | flowchart TD |
二、MongoDB 索引治理
索引过多不仅会占用大量的内存(WiredTiger 缓存),还会严重拖慢写入性能(Insert/Update/Delete)。为了解决当前索引冗余、顺序混乱以及查询效率低下的问题,请遵循以下原则:
“先规范数据(去 $or),再复用索引(找前缀),最后才考虑新增。”
1. 索引设计核心原则 (ESR)
创建复合索引时,字段顺序必须按照 E -> S -> R 的优先级进行排列:
- **Equal (等值查询)**:最先放置。如
平台id、所属主机等。 - **Sort (排序字段)**:中间放置。如果有
sort操作,字段必须紧跟在等值字段后。 - **Range (范围查询)**:最后放置。如
$gt、$lt、$in、$ne等。
2. 索引瘦身与复用原则
禁止盲目新增索引,优先考虑覆盖与去冗:
- 利用最左前缀匹配:如果已有索引
{A: 1, B: 1, C: 1},则无需再为{A: 1}或{A: 1, B: 1}单独建索引。宽索引可以兼容窄索引的查询。 - 避免唯一标识冗余:如果
{平台id, 资产_id}已经能唯一锁定记录,则禁止再为此组合增加所属主机等额外字段的复合索引。 - 全局视角:新增索引前,必须检查现有索引列表。如果通过给现有索引末尾追加字段能解决问题,则不要新建。
3. 数据建模与状态规范(针对 OR 查询问题)
禁止在代码中使用复杂的 $or 来兼容多种“初始态/空态”:
- 状态唯一性:一种业务含义只能对应一个值。禁止同时用
null、0、""和None表示同一种状态。 - 必须设置默认值:所有新字段在设计时必须明确 Default Value。
- ❌ 错误写法:使用
{"$exists": false}或$or兼容各种空值(这会导致索引扫描效率极低)。 - ✅ 正确写法:入库时字段必须存在。查询未处理状态统一使用
{"用户认领状态": 0}。
- ❌ 错误写法:使用
- 严禁逻辑发散:不要在代码里去猜数据可能有哪些空值(如
[]、{}),应在写入端保证数据的清洁和规范。
使用 Partial Index 避免无效数据
7. 性能对比:
4. 流程规范:先评审,后上线
- 索引评审制:涉及 MongoDB 索引的新增或修改,必须在文档中列出查询语句并说明理由。
- Explain 分析:开发者在申请索引前,需自行执行
.explain("executionStats")。- 关注点:使用了索引时的状态为
stage: 'IXSCAN',totalKeysExamined(扫描索引数)应尽可能接近nReturned(返回结果数)。
- 关注点:使用了索引时的状态为
- 定期清理:DBA 或 Owner 会定期统计索引使用率(
db.collection.aggregate([ { $indexStats: {} } ])),对于 Ops(使用次数)为 0 的索引将直接下线。
三、web 接口治理
1. 背景与公共问题
主要性能瓶颈
- Auth 认证:每次请求固定约 100ms
- 资产组树缓存失效:单次请求 500–600ms
- 历史接口问题:
- 大接口一次性返回全部数据
- 多表 Join / 级联查询过多
- 前端一次性渲染压力大
统一规范
- 所有接口 必须携带
平台id - 禁止使用
"all"作为默认查询条件(除非明确支持)
2. 资产组树接口重构(Tree 按需加载)
改造目标
- 避免一次性加载全量资产组树
- 将 “全量返回” → “逐级加载”
核心改动
- 接口语义升级为 Tree 模式
- 页面行为调整为:
- 首次只请求第一层
- 点击展开节点时,再请求子节点
效果
| 项目 | 优化前 | 优化后 |
|---|---|---|
| 接口耗时 | 8–9s | ~300ms |
| 加载方式 | 全量 | 按需 |
| 用户体验 | 卡顿 | 秒开 |
3. 资产列表接口重构(拆接口)
改造目标
- 列表接口只做“核心资产数据查询”
- 所有关联信息拆成独立接口
核心策略
- List 主接口
- 只查 资产 表 + 必要配置表
- 不再 Join 资产组 / 组织 / 平台 / 业务等信息
- 关联信息
- 按需调用
- 前端或中台统一聚合
拆分出的独立能力
- 资产组名称 / 全名
- MAC 来源
- 组织架构全名
- 资产认领信息
- 业务组名称
- 平台名称
性能收益
| 环境 | 优化前 | 优化后 |
|---|---|---|
| ~6s | ~300ms | |
| 157万条数据 | ~600ms | ~200ms |
4. 性能收益
| 维度 | 旧接口 (已弃用) | 新接口 (推荐/合一分支) | 性能提升 |
|---|---|---|---|
| 资产列表 URL | ?method=GET |
?method=GET |
23倍 |
| 资产组树 URL | ?method=get |
?method=get&_style=tree |
20倍+ |
| 资产组 响应耗时 | 7.9s ~ 9s | 300ms ~ 420ms | 显著减少延迟 |
| On_list 响应耗时 | 2.38s | 103ms | 亚秒级实时返回 |
| 核心逻辑耗时 | - | 约 100ms (其余为Auth认证) | 逻辑大幅精简 |
| 性能基线要求 | 无明确标准 | 资产组 < 500ms / On_list < 200ms | 建立硬性准入基线 |
- 接口平均耗时下降 5~30 倍
- 核心列表接口稳定在 200–300ms
- 架构从「胖接口」演进为「能力解耦型接口」
- 为后续缓存 / 并发 / 异步聚合提供空间