本节摘要:本节把 2.1 的架构骨架拆成可操作的部件清单:GMS 的读写接口契约、搜索服务的查询职责、图服务的关系查询能力、前端服务的聚合角色,以及藏在后台的索引构建消费者。每个组件都按"职责、接口、故障特征"三段展开,并在最后用一个真实排错案例演示如何按组件分工定位问题。本节承接 2.1 的分层视图,是 2.3 数据流与 4.4 排错实录的部件基础。
先看一个排错现场。某天下午,数据组反馈:搜索框里能搜到一张表,点进详情页却提示实体不存在;反过来,刚改完的字段描述在详情页立即可见,搜索结果里的摘要却还是旧文案。两个现象方向相反,把人绕得团团转。
如果你记得 2.1 的结论——详情页读主库、搜索读索引、两者靠事件同步——这两个现象立刻就有了结构性解释:前一个是"索引有、主库无",说明实体曾被删除但索引没跟上;后一个是"主库新、索引旧",说明事件同步滞后。同一组组件,两个方向的不一致,排查路径完全不同。这就是为什么排错前必须先认部件:知道症状该找谁,才不会把 GMS 的日志翻到天亮。

GMS 对外暴露的接口围绕实体与 Aspect 两个概念组织。读接口按实体键取回实体的全部 Aspect,或按 Aspect 精确读取;写接口接收变更提案,校验后落主库。血缘写入有专门通道,因为它写的不只是实体属性,还要维护图库里的边。
给运维三个实用判断。其一,GMS 是无状态服务,本身可以随意扩容,压力瓶颈通常出现在它身后的主库连接数上。其二,GMS 的报错信息是排错的富矿:模型校验失败会明确指出哪个 Aspect 的哪个字段非法,摄入报错先看这里的返回再动手改配置,比盲试快得多。其三,所有界面上的写操作最终都汇到 GMS 同一套接口——界面改不动的字段,走 API 同样改不动,反之道通。
搜索服务包裹着搜索引擎索引,向上提供关键词检索、结构化过滤、排序与聚合四类能力。用户对平台的第一印象几乎全部来自它:搜索不准,平台就会被判死刑,无论元数据质量多高。
有三个工程细节值得知道。第一,索引文档是实体的"搜索视图",只包含参与检索与展示的字段,远小于实体全量 Aspect——所以搜索结果里的描述与详情页不一致,几乎总是索引刷新滞后而非数据损坏。第二,排序因子里常混入使用统计(访问热度),一张从未被点击的新表排在老表之后是正常现象,不是故障。第三,过滤条件与关键词是两条独立通道,"搜索结果为空"时要区分是无命中还是过滤条件把结果筛没了。
图服务屏蔽了底层图库的查询语言,暴露三个语义化接口:查上游、查下游、按层级展开影响面。血缘界面上的每一次展开动作,都对应图服务的一次遍历。
它有两个使用要点。第一,图服务的查询有深度与并发约束,前端血缘图默认只展开若干层,"血缘不全"的第一反应应该是确认展开深度,而不是怀疑血缘缺失。第二,图的边在写入时由 GMS 同步维护一份、事件链路异步核对一份,两边短暂不一致时以重新触达的写入为准——个别边的残缺,重放一次对应实体的血缘写入即可修复,不需要重建整图。
这是最容易被忽略的组件:它没有界面、不直接面向用户,却承担着三存储一致性的全部体力活。它订阅消息队列里的元数据变更事件,把每个变更翻译成索引文档更新与图边更新。
它的故障模式很有辨识度:消费者挂掉或消费积压时,主库一切正常,但索引逐渐落后,表现为"刚写入的元数据搜不到、过段时间又自己出现了"。遇到这种"迟到的正确",检查消费者组的积压指标即可确诊。它也是全量重建任务的执行者:索引结构升级或灾难恢复时,从主库批量读出全部实体重灌索引的活由它干,大平台的一次全量重建可能以小时计,安排在业务低峰执行。
给它配一个专属健康动作:盯消费位点。位点(消费者在事件流里读到哪个位置了) lag 值是消费者健康的直接读数——lag 稳定在低位是正常呼吸,lag 单调增长是消化不动,lag 长期不动且队列有新事件则是"装死"。三种形态对应三种处置,6.4 的告警配置会直接引用这组判别。运维周报里固定放一行位点 lag 的周曲线,一图胜千言。
组件手册补上两位边缘成员。前端服务除了聚合整形,还有两个容易被忽略的行为:其一,它对 GMS 的调用是扇出的——详情页一次渲染可能触发对 GMS、搜索、图服务的多次请求,前端副本数不足时,用户感知为"整页慢"而非"某块数据慢",排错时用浏览器开发者工具看请求瀑布,哪一段耗时一望便知。其二,前端的会话状态在容器化部署里默认本地化,多副本负载不均时会出现"刷新一下就要重新登录"的怪象——把会话改到共享存储或启用粘性会话即可。
网关(如果组织统一接入):它承担认证前置、限流与审计日志。元数据平台的查询报文偏大(详情与血缘返回动辄数百 KB),网关的默认报文限制与超时设置要相应放宽,否则会出现"详情页偶发截断"这类难查的症状。
回到开头的两个症状,用部件手册走一遍。症状一"能搜到但详情 404":详情页读主库,404 说明主库无此实体,索引却有——实体被删而索引未同步,处理方式是触发该实体的索引删除补偿,或等待消费者追平。症状二"详情新、搜索旧":主库已更新而索引滞后,查消费者积压指标,若积压为深,扩容消费者或提升其并行度;若积压为零但仍旧,查对应实体的变更事件是否发布失败——极少数情况下事件在队列里丢了,重放该实体的写入即可。两个症状,四步定位,全程不需要重启任何组件。部件认得准,动作就轻。
再补一个更隐蔽的变式。某天用户报告"血缘图上少了一条边,但昨天还在"。按部件手册:详情页两个实体都在,说明主库无恙;血缘缺边找图服务,查它的数据来源——图边由 GMS 同步维护加事件异步核对,双保险下缺边大概率是上游实体的血缘 Aspect 被一次全量覆盖写回退了(某个连接器重新跑了旧快照)。重放该实体最新的血缘写入,边就回来了。这个案例的启示:血缘边不是独立数据,它是血缘 Aspect 的投影,边丢了要去看 Aspect 的版本历史。
部件手册的最后一页留给“谁不属于部件”:摄入执行器、各类连接器、外部的质量与调度系统,都是平台的客户端而非组成部分。排错时把“客户端的错”当成“平台的病”,是绕远路的常见起点——先分清内外,再谈定位。
一次到位的记忆法:四个部件各记一句故障口诀——写入报错找 GMS、搜不到找索引、血缘缺找图库、新旧不一致找消费者。口诀背后是职责边界,边界清楚了,口诀忘了也能推出来。
部件认识了,下一节让数据在部件之间流动起来——沿一条变更的生命周期,看清写入与查询的全链路。