运营中心大数据架构:毫秒级交互响应的秘密
|
线上报警那一刻,我正把咖啡杯底最后半口晃荡着往嘴里送,凉得像隔夜茶——结果手机在裤兜里震,钉钉弹窗盖住屏幕,监控平台红得跟过年贴的福字似的。前端老张秒语音进来:“你那边查查缓存穿透是不是又漏了?用户说点个运营报表,转圈转到想辞职。” 我说好,顺手切了三个终端窗口:redis-cli monitor 看命,tail -f 日志滚屏,再开个 curl 模拟压测。没两秒,运维小李直接甩我一条命令行:“刚 kill 了两个 stuck 在 join 路径上的 Spark Streaming 实例,你别动 cache key 前缀。”——他敲回车那声特别重,键盘声“咔”一下,隔壁工位都停了三秒。 我原以为是 Flink 窗口触发延迟,结果扒了一分钟日志发现根本不是流式的问题。真正卡住的是个叫 getBizSummaryV3WithCacheAndFallback 的方法——就这名字,我数了三遍:withCacheAndFallback,还带个 V3,谁起的?它上头包着一层 try-catch,catch 里直接 return new BizSummaryDto(),字段全 null。连 fallback 都懒得 mock 一个时间戳,更别说降级策略了。我就盯着那个类名发了会儿呆,手机又亮了一下,工单系统弹了条新消息:“【高优】运营中心-用户画像看板响应超时率升至 12%”,我看都没点开,先给删了。 其实真要讲毫秒级响应的秘密……不是用了什么新型向量索引,也不是把 OLAP 引擎换成了 ClickHouse 云原生版——是我们组上周裁掉的那个外包兄弟,写了个定时任务每五分钟刷一次预计算表,逻辑是拿 user_id % 64 分桶,跑完立刻 update ts_last_precomputed。结果上个月他走后没人动 cron 表达式,服务器重启过三回,但 crontab 没重载,所以那六十四张预热表,有七张根本没刷新过。昨天产品王姐拿着平板当面点,正好戳中一张三年没动过的冷表,耗时从 40ms 直接飙到 2.8s。她说:“这不像大数据架构,像抽盲盒。” 窗外天黑得挺快,办公室灯还没全亮,只有我这排的LED白光刺眼。我点了支烟(早该戒了),一边吸一边翻 git blame——发现那个分桶逻辑里有个常量叫 BUCKET_SIZE_FOR_PRECOMPUTE,值设成 64 是因为 2021 年初他们搭 HBase RowKey 的时候图省事;后来全换成 ES 了,这个常量没删,只被 copy-paste 进了新的服务,改名叫 PRECOMPUTE_BUCKET_COUNT,还加了注释:“兼容旧数据结构(已下线)”。说白了,现在没人知道它到底兼不兼容,但没人敢动,因为测试环境连个能跑通的 user_id 都凑不齐——mock 工具生成的 id 全是 UUID,而线上真实流量里 92% 是数字型 uid,hash 结果压根不在同一个桶里。 产品王姐今天又来过,端着保温杯站我工位边,问:“你们这‘毫秒级交互响应’,是按 P95 算的吧?”我没接话,她自己笑了:“我上个月让测试压测了三次,每次都用同一组用户 ID,结果第二轮开始全 hit 缓存……你们缓存 key 里带了 userId + timestamp,但 timestamp 取的是 new Date().getTime() / 1000 1000,秒级对齐,等于一秒钟内所有人请求都算同一个 key。”——我听着有点耳熟,下午翻了下代码,果然,这逻辑是我两年前写的,当时为了抗住某次双十一大促的突发流量,临时加的。现在促销早过了,缓存过期时间却调到了 7 天,没人记得改。 其实最扯的是灰度策略。上线新版本那天,我们搞了个「动态特征开关」,开关名叫做 enable_new_summary_engine_v2,值存在 Apollo 里,配置类型选的 Boolean。但 Apollo 界面默认把空字符串、null、"false"、"0" 全识别为 false,而某个接口的初始化模块里,读取开关时忘了判空,直接 parseBoolean(""),结果返回 true。于是前两天所有灰度机器在凌晨三点同时切到了新版引擎——它压根没做限流,一上来就被上游调度器喂了 17 个并发请求,全部打到同一条 Redis pipeline 上,其中五条卡死在 eval Lua 脚本里,超时设置还是 30 秒……运维小李是被告警电话叫醒的,起来第一件事是 ssh 进去手动 redis-cli --scan-and-delete-keys 'summary:precompute:'。
文章配图,仅供参考 所以啊,什么「毫秒级交互响应的秘密」?就是没人敢碰、没人愿修、没人记得删的那堆破东西,在互相咬合着转动而已。所谓优胜劣汰,不是技术淘汰人,是人淘汰不了那些活下来的脏补丁。上个月我试图给 getBizSummaryV3WithCacheAndFallback 加个熔断,结果测出下游依赖的一个老服务连 OpenFeign 的 connectTimeout 都没设,默认是 -1,也就是无限等。我当场放弃。现在那块日志里还飘着一行 warn:“[FallbackExecutor] catch all exception, using empty dto — please fix it.” 写这行 log 的人,去年跳槽去了杭州,微信回我一句“兄弟你真卷”,再没下文。 我刚才试了下 curl -v http://local/summary?uid=123456&debug=true,看到返回 Header 里有个 X-Cache-From: precomputed_bucket_42,说明它真走预热表了。但 debug=true 的参数,其实是前端老张昨天加的,说是为了埋点分析慢请求来源——可他忘了把 debug 参数加进缓存 key 计算逻辑里,所以所有带 debug 的请求,全 miss。我现在就坐在那儿,对着 terminal 犹豫要不要 grep 一下项目里还有多少类似 “if (debug)” 的裸判断……算了,先看看今晚要不要值班。咖啡凉透了,杯子底下印了个深褐色圆圈,像某种不太吉祥的隐喻。 接下来我想查查那个 Apollo 开关的 commit 历史,看是谁 merge 的——不过得等钉钉静音解除,现在弹窗太多,我怕错过谁喊“赶紧看下生产库 CPU 又爆了”。也可能根本不用查,毕竟……谁还记得清楚呢。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

