话说,半夜三点,告警电话跟催命符一样响起,是不是你我最熟悉的噩梦?那一刻,什么狗屁的 QPS、DAU,都变成了心电图上的尖刺。所以,我这些年琢磨终端架构,翻来覆去就想搞明白一件事:怎么才能让这摊子事儿自己跑得稳一点,让我能踏踏实实地睡个整觉。
一开始,我们都特天真,觉得一个牛逼的单体网关能搞定一切。所有流量都从那儿过,统一鉴权、统一路由,多干净利落。直到有一天,市场部搞了个大促,某个"上新推荐"接口的流量一上来,整个 App 都跟着抖三抖。我当时就想骂人,凭什么啊?就因为 iOS 那边加了个新功能,搞得安卓、小程序的用户也跟着一起卡?
这就是我为什么现在对网关分层 + BFF 这套东西有点着魔。说白了,就是别把鸡蛋都放一个篮子里。公共的大门(API Gateway)还在,但每个端(iOS, Android, Web)都给自己配个专属小门(BFF - Backend for Frontend)。这样,iOS 的热门接口要扩容,就单独给它加机器,搞个十台八台的,完全不影响隔壁安卓兄弟。各家升级各家的,发版也不用再拉个大会,互相知会"我今天要动公共厕所了,你们都别上啊",解耦,真香。
但光拆门还不够。最怕的就是那种瞬间涌进来的流量,比如秒杀。你服务器再能扛,数据库也扛不住这么多人同时写一行数据啊。硬抗?那就是大家一起完蛋。
所以,异步削峰 这招,简直是保命符。你别直接来我家砸门,先去门口排队机(MQ)那儿取个号。我们家(后端服务)里头有几个服务员(消费者),就按自己的速度叫号。这样一来,数据库的压力瞬间就平滑了,跟细水长流似的。而且,感觉人手不够了?简单,再多喊几个服务员(增加消费组的 Pod 数量)来帮忙叫号就行,横向扩容,就这么简单粗暴。
当然,我有时候也犯嘀咕,这 MQ 可不是银弹。消息万一丢了呢?顺序错了怎么办?重复消费了怎么办?每次引入一个新组件,就好像请了个大神,厉害是真厉害,脾气也是真大,你得小心伺候着。
说到扩容,我以前最烦的就是手动加机器。等我发现流量上来了,再去申请机器、部署服务,黄花菜都凉了。现在有了 K8s,感觉自己像个开了自动驾驶的司机。我把所有服务都搞成无状态的,用户的登录信息之类的,全扔 Redis 里去。服务本身就是个工具人,随时可以被替换。然后用 Nacos 这种服务发现组件,让它们自己报到、自己组队。
最爽的是 K8s 的
HPA(Horizontal Pod Autoscaler)。
我给它定个规矩:CPU 超过 70% 了,或者 QPS 超过 500 了,你就自己去加人手(Pod)。流量下去了,再把多余的人手给裁了,省钱。整个过程,我甚至都不用知道。这种"无人值守"的弹性,才是我心里真正的高可用,因为它把最不靠谱的人为因素给剔除了。
但是,就算你单个机房玩得再溜,万一哪天挖掘机一铲子下去,整个机房的光缆都断了呢?
这就是为什么老板们总念叨异地多活。听着就烧钱,对吧?在北京搞个机房,在上海再搞一个。用户数据、会话状态,全都实时同步过去。北京的用户,可能流量实际打到上海去了,他自己都不知道。万一北京机房真的挂了,DNS 或者更牛逼的流量调度系统,能在几秒钟内就把所有流量切到上海去。RTO(恢复时间)趋近于零。
听着是挺美的,但这里面的数据同步,就是个天坑。怎么保证两边数据一致?网络延迟怎么办?这背后花的钱、投入的人力,可能比你整个业务团队都多。有时候我也会怀疑,我们真的有必要做到这个程度吗?是不是有点过度设计了?
后来我发现,其实"高可用"这事儿,不光是堆机器、搞容灾。很多时候,系统挂了,是因为安全出了问题。
我越来越信奉零信任。以前我们觉得,流量进了内网就安全了。现在我不这么想了。我总觉得,裸奔的服务就像在黑暗森林里打着手电筒,指不定哪个角落里就藏着个"鬼"。所以,从终端 App,到网关,再到后端每个微服务,整条链路都得上 mTLS 加密。每个服务之间互相访问,都得先亮出身份证(证书),验明正身。用户的令牌(JWT)也得是短时间的,丢了也不怕,反正很快就过期了。别因为一个服务被渗透,导致整个内网被人横着走,最后全线崩溃。
安全即高可用,这话真不是说着玩的。
你看,这些东西,东一榔头西一棒子的,什么网关、队列、K8s、多活、安全......听着都挺唬人。但把它们串起来,你会发现,这就是一个闭环。从流量入口的扩展,到后端的弹性,再到机房级的容灾,最后用安全和自动化监控把所有环节都保护起来。
这就是我们这些工程师,为了能安稳睡一觉,给自己构建的层层防线。
说到底,架构这东西,有完美的吗?我觉得没有。今天你觉得固若金汤的设计,明天可能就被一个新的业务场景、一个新的技术给颠覆了。我们真的能预测下一次雪崩什么时候来吗?谁知道呢。
算了,不想了,先去泡杯咖啡。起码今天,系统还没挂。这就挺好。