你以为水平扩展就是加机器?以为长轮询比短轮询更省资源?这些"常识"可能正在拖垮你的系统。
这篇笔记来自一位工程师的真实学习整理,没有理论堆砌,全是面试和实战中踩过的坑。看完你会发现:很多性能问题的根源,不是代码写得烂,是架构选型时就选错了方向。
![]()
轮询策略:短轮询是性能杀手,但长轮询也不是万能解
客户端要实时拿到服务器更新,最土的办法是短轮询:每隔几秒发一次请求问"有新消息吗"。实现简单,问题在于空转——90%的请求换来的都是"没有更新",带宽和CPU全浪费在无效往返上。
长轮询看起来聪明:客户端发请求后,服务器挂着不立刻响应,等有数据了再返回。省了点无效请求,但代价是服务器要维持大量挂起的连接。一个线程挂一个请求,几千并发就能吃光线程池。
真正低延迟的场景,SSE(服务器推送事件)和WebSocket才是正解。SSE单向推送适合股票行情、新闻feed;WebSocket双向通道适合聊天、协作编辑。但别急着上WebSocket——它维护长连接的成本,在弱网环境下可能比轮询更崩。
扩展方向:垂直扩展被嫌弃,但水平扩展有隐形成本
加CPU加内存叫垂直扩展,加机器叫水平扩展。业内默认水平扩展更"优雅",因为单机总有天花板。但很多人忽略了:水平扩展引入的复杂度,可能吃掉你省下的硬件钱。
分布式意味着数据一致性要重新设计。用户A的请求打到机器1,用户B的请求打到机器2,会话状态怎么同步?数据库分片后,一个查询要跨多个节点聚合,延迟可能反而上升。Netflix能玩水平扩展,是因为有专门的团队做分布式调度——小团队硬上,等于给自己挖坑。
垂直扩展在特定场景反而更香。内部工具、低频后台任务、强一致性要求的财务系统,单机MySQL配个好SSD,可能比分布式数据库少睡很多觉。
负载均衡:不只是"把流量分到多台机器"
很多人理解负载均衡就是轮询:请求1给A,请求2给B,雨露均沾。但轮询对计算密集型任务很蠢——A机器正在跑重任务,新请求过来照样塞给它。
最少连接数策略更聪明:看谁当前处理的请求少,新请求给谁。加权策略适合异构集群:新机器配置高,权重设大点,老机器慢慢退居二线。会话保持(Sticky Session)解决状态问题:同一个用户的请求固定打到同一台机器,但代价是某台机器挂了,它的用户全丢会话。
健康检查是隐形刚需。负载均衡器得持续探测后端,发现某台机器响应慢了、报错多了,自动踢出集群。没有健康检查的负载均衡,等于把鸡蛋放在多个篮子里,但篮子之间用绳子绑着——一塌全塌。
缓存淘汰:LRU不是唯一答案,业务特征决定策略
缓存满了删谁?LRU(最近最少使用)是默认答案,但假设你的缓存是热点新闻,最新发布的文章反而应该优先保留,不管它现在被读了多少次。这时候LFU(最不经常使用)或者简单的时间过期(TTL)更合适。
更隐蔽的问题是缓存穿透:查询一个不存在的数据,缓存miss,打到数据库,数据库也查不到。攻击者用随机ID狂刷,数据库直接崩。布隆过滤器或者缓存空值,是解决这类问题的标准套路。
缓存雪崩是另一个噩梦:大量key同时过期,请求雪崩式打到数据库。给过期时间加随机偏移,或者热点数据永不过期+后台异步刷新,才能避免整点事故。
代理与反向代理:方向搞反,安全模型全错
正向代理站在客户端前面,帮用户访问外部资源——翻墙工具、公司内网代理都是这类。反向代理站在服务器前面,用户以为自己连的是目标网站,实际连的是代理,再由代理决定哪台后端服务器处理。
这个"反向"不是白叫的。它隐藏了后端拓扑,攻击者摸不清你有多少台服务器、什么IP。SSL终结也在这一层做:用户到反向代理走HTTPS,代理到后端走HTTP,减少后端加解密开销。但这也意味着反向代理成了单点,它挂了全站瘫痪,高可用方案必须跟上。
API网关是反向代理的进化版。不只是路由,还管认证、限流、协议转换。微服务架构下,100个服务不可能各自做鉴权,统一收口在网关,后端只专注业务逻辑。但网关本身别写复杂逻辑,否则它又成了新瓶颈。
WebSocket:双向通信的代价,很多人没算清
HTTP是请求-响应模式,问一句答一句,答完关门。WebSocket一次握手后连接保持,双方随时推送。聊天室、在线游戏、协同文档,这些场景没有WebSocket很难做。
但WebSocket的坑在于状态管理。HTTP是无状态的,请求之间互不认识,水平扩展随便加机器。WebSocket连接是有状态的,用户A连在服务器1,服务器2根本不知道这回事。消息要广播给房间所有人?得引入Redis Pub/Sub或者专门的消息队列做跨节点同步。
心跳机制也不能省。TCP连接中间经过NAT、防火墙,长时间没数据会被静默断开。客户端和服务端得定期互发ping/pong,维持连接存活。心跳间隔太短,耗电耗流量;太长,连接断了用户还没感知。
幂等性:为什么刷新页面不会重复下单
幂等性这个词很学术,意思是同样的操作执行N次,结果和执行1次一样。HTTP方法里,GET天然幂等——你刷新100遍百度首页,不会创建100个搜索任务。POST默认不幂等,同样参数发两遍,可能创建两条订单。
实际系统中,幂等性靠唯一请求ID保证。客户端生成全局唯一ID,服务端用这个ID去重:处理过了直接返回之前的结果,没处理过才执行业务逻辑。支付场景尤其关键,网络抖动导致用户点了两次"确认支付",没有幂等控制就是双重扣款。
但幂等性有有效期。请求ID存多久?存太短,用户隔一小时重试,当成新请求处理;存太长,存储成本爆炸。通常和业务场景绑定:支付相关存7天,普通操作存1小时,过期后幂等性不再保证。
选型没有银弹,只有 trade-off 的清醒认知
这篇笔记的价值,不在于告诉你"该用什么",而在于暴露每个选项的隐藏成本。长轮询省带宽但吃连接数,水平扩展省硬件但增复杂度,WebSocket实时但难运维——系统设计的本质,是在约束条件下做取舍。
很多面试题问"如何设计一个秒杀系统",标准答案背得滚瓜烂熟:Redis预扣库存、消息队列异步下单、限流熔断兜底。但真到线上,你的团队能维护几级缓存的一致性?降级开关有没有演练过?全链路压测的数据准不准?
架构图上的方框和箭头是免费的,运行时的故障和告警是昂贵的。这篇笔记列出的8个概念,每个背后都是生产事故的学费。下次做技术选型时,不妨多问一句:这个方案省掉的麻烦,会在哪里加倍还回来?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.