「缓存淘汰策略到底在淘汰什么?负载均衡真的只是随机分配吗?」——这些面试必问的系统设计题,答案往往停留在八股文层面。一位开发者在学习笔记里扒开了这些概念的底层逻辑,有些发现甚至和主流认知相反。
一、轮询与推送:长轮询不是"更长的轮询"
![]()
客户端获取服务器更新的方式,本质只有两种:轮询(Poll)和推送(Push)。但三种具体实现的技术选型,藏着容易被忽略的工程陷阱。
短轮询(Short Polling)最直观:客户端定时发请求问服务器"有消息吗",没有就立即返回空响应。优点是实现简单,缺点是空跑严重——服务器压力随客户端数量线性增长,实时性还受限于轮询间隔。
长轮询(Long Polling)常被误解为"把轮询间隔拉长",实际上完全不是一回事。客户端发起请求后,服务器会挂起这个HTTP连接,直到有新数据才返回响应。连接结束后客户端立即发起新请求,保持"随时待命"状态。
这带来一个反直觉的成本:长轮询的服务器资源占用比短轮询更高。每个挂起的连接都需要维持TCP会话,高并发场景下容易触及服务器的连接数上限。很多开发者直到压测时才意识到,"更优方案"反而成了瓶颈。
真正的推送方案是SSE(服务器推送事件)和WebSocket。SSE基于HTTP,适合服务器单向推送场景;WebSocket建立后是全双工通道,双方随时发数据。但WebSocket的维护复杂度常被低估——心跳检测、断线重连、代理穿透,每个都是生产环境的坑。
二、扩展的两种哲学:纵向是赌命,横向是手术
垂直扩展(Vertical Scaling)和水平扩展(Horizontal Scaling)的选择,本质是风险偏好的体现。
纵向扩展就是给单台服务器加配置:更多CPU、更大内存、更快磁盘。这像给老车换引擎——见效快,但天花板明显。单机性能总有物理极限,且升级过程往往需要停机,形成"维护窗口"的业务损失。
更隐蔽的风险是单点故障。一台价值50万的高端服务器宕机,和五台10万的服务器挂掉一台,业务连续性完全不同。后者可以用负载均衡快速切流,前者直接服务中断。
水平扩展则是分布式架构的起点:加机器,分流量。但这需要系统层面配合——无状态化设计、数据分片策略、分布式事务处理。很多"无法水平扩展"的遗留系统,问题不在技术而在历史包袱:session粘滞、本地缓存依赖、数据库自增ID。
一个判断标准:如果扩展需要改动应用代码,说明架构债务已经累积。理想状态下,扩缩容应该只是运维层面的机器增减。
三、负载均衡:随机是最差的策略
负载均衡器(Load Balancer)被简单理解为"流量分配器",但分配策略的选择直接影响系统稳定性。
轮询(Round Robin)最公平,却无视服务器的实际负载。一台机器因为GC停顿响应变慢,轮询仍会源源不断塞请求过去。加权轮询稍微改进,但权重调整往往滞后于真实状态。
最少连接数(Least Connections)策略更聪明:把新请求发给当前活跃连接最少的后端。这适合长连接场景,比如WebSocket服务。但短连接密集时,连接数的统计噪声会让策略失效。
最实用的往往是健康检查+动态剔除的组合。负载均衡器持续探测后端状态,发现异常立即移出池子。很多故障不是瞬间崩溃,而是响应时间逐渐劣化——没有健康检查,这些"慢节点"会持续拖累整体性能。
反向代理(Reverse Proxy)和正向代理(Forward Proxy)常被混淆。正向代理站在客户端一侧,帮用户访问目标网站(比如翻墙);反向代理站在服务器一侧,对外暴露统一入口,对内分发到具体服务。Nginx、HAProxy、AWS ALB都是反向代理的实现。
四、缓存淘汰:LRU不是银弹
缓存满了怎么办?淘汰策略(Cache Eviction Policy)决定哪些数据该被扔掉。但"最近最少使用"(LRU)的流行,掩盖了其他策略的适用场景。
LRU的核心假设是:过去被访问的数据未来更可能被访问。这在用户行为稳定的场景成立,但面对周期性批量任务时会失效。比如每晚运行的报表生成,会把大量冷数据一次性灌入缓存,挤掉真正的高频热点。
LFU(最不经常使用)计数访问频次,能识别长期热点,但无法适应兴趣漂移。一个突然爆火的新闻事件,在LFU策略下要积累足够计数才能常驻缓存,错失流量高峰。
TTL(生存时间)策略最简单:给数据设置过期时间。适合时效性强的场景,比如验证码、限时活动。但需要预估合理的过期时长,太短增加回源压力,太长导致数据陈旧。
生产环境往往是混合策略:LRU处理常规流量,TTL兜底异常场景,再辅以手动标记的"永不过期"关键数据。缓存设计最难的不是技术选型,而是对业务访问模式的准确建模。
五、API网关与幂等性:分布式系统的安全带
API网关作为统一入口,职责常被过度膨胀。认证、限流、路由、协议转换、日志采集——功能堆砌后,网关本身成为新的单点瓶颈。一个设计原则是:网关只处理横切关注点,业务逻辑下沉到微服务。
幂等性(Idempotency)是分布式系统的核心概念,却少有工程团队真正落实。定义很明确:同一操作执行多次,结果与执行一次相同。但实现层面,网络超时、消息重试、用户重复点击,都会打破这个假设。
HTTP方法的幂等性设计值得细品。GET天然幂等,因为不修改状态;POST创建资源,多次调用会生成多个记录;PUT更新为指定值,多次执行结果一致;DELETE删除资源,第一次成功后续都是"资源不存在"——也算幂等。
实际业务中,POST的幂等性最难保证。常见方案是客户端生成唯一请求ID,服务端用数据库唯一索引或分布式锁去重。但请求ID的生成、传递、存储都有成本,很多团队直到出现重复订单才补课。
一个犀利观察:幂等性实现往往和"性能优化"冲突。去重检查需要额外存储和查询,高并发场景下可能成为瓶颈。这解释了为什么金融支付系统愿意投入大量工程资源做幂等,而内容社区往往选择性忽略——业务对一致性的容忍度,决定了技术投入的上限。
六、WebSocket:全双工的代价
WebSocket解决了HTTP半双工的痛点,但"随时双向通信"的能力不是免费的。
建立连接需要一次HTTP升级握手,这消耗1个RTT。连接维持期间,TCP keepalive和WebSocket心跳包持续占用带宽。更重要的是,WebSocket连接有状态——服务器需要维护连接映射表,水平扩展时必须解决会话同步问题。
很多团队用Redis存储用户ID到服务器实例的映射,实现"消息路由"。但这引入新的依赖:Redis宕机怎么办?网络分区时消息往哪发?这些复杂度在选型演示时往往被跳过。
一个替代方案是SSE(Server-Sent Events),基于HTTP流实现服务器推送。无法客户端主动推送,但实现简单、自动支持HTTP/2多路复用、代理兼容性更好。如果业务场景是服务器主导的信息流(股价、通知、日志),SSE可能是更务实的选择。
七、TCP:可靠性的幻觉
原文对TCP的定义极简:"两台设备在网络上的对话方式"。但这句轻描淡写背后,藏着系统设计的关键认知。
TCP的可靠性是端到端的承诺,不是应用层的保证。数据成功抵达操作系统内核,不代表业务程序已处理;连接正常建立,不代表对方服务已就绪。很多"神秘丢数据"的bug,根源在于混淆了传输层和应用层的边界。
WebSocket基于TCP,继承了这些特性,也继承了这些问题。应用层需要自己实现消息确认、顺序保证、断线重连——这些正是MQTT、STOMP等协议存在的意义。直接裸用WebSocket的团队,往往在生产环境踩完所有坑后才意识到需要协议封装。
八、学习笔记的启示:概念清晰比架构图重要
这份学习笔记的价值,不在于覆盖了多少高级主题,而在于对每个基础概念的精准定义。系统设计面试常陷入一个误区:追求分布式事务、一致性算法等"高级"话题,却说不清负载均衡的具体策略。
真正的工程能力,体现在对基础概念的边界认知:知道长轮询的资源代价、明白LRU的失效场景、理解幂等性的实现成本。这些细节不会出现在
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
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.