简介: 本指南旨涵盖前端、CDN、Nginx 负载均衡、服务集群、Redis 缓存、消息队列、数据库设计、熔断限流降级以及系统优化等模块的核心要点。我们将介绍各模块常见的设计方案与优化策略,并结合电商秒杀、SaaS CRM 系统、支付系统等高并发场景讨论实践技巧,指出设计时需要特别注意的问题和常见陷阱,并引用美团、淘宝、京东、滴滴等大厂的真实案例加以说明。这份指南结构清晰、模块化编排,方便快速查阅,注重实战性和场景应对能力。
前端架构与优化
现代系统的前端架构需要既能提供良好的用户体验,又能支撑高并发访问。前后端分离是常见架构,即前端负责页面展示和交互,后端提供数据接口。这种模式下可以灵活扩展前端集群,并通过CDN缓存静态资源(如HTML、CSS、JS、图片)减轻服务器压力。前端性能优化主要围绕减少请求体积和数量、加快加载和渲染展开:
静态资源优化:
将尽量多的静态内容下发给CDN或浏览器缓存。通过将静态资源从动态内容中拆分,可以更好地优化网站性能和扩展性;静态资源可被缓存并通过CDN分发,加快加载速度并减轻服务器负载。例如,将JS/CSS文件打包压缩、启用浏览器缓存控制(强缓存/协商缓存)等,使重复访问时能直接读取缓存而非每次请求服务器。
这里我想到了http1.1引入的cache-control功能。
什么是 HTTP/1.1 的
Cache-Control
?
Cache-Control
是 HTTP/1.1 引入的一个非常重要的缓存控制头部字段,
用来告诉浏览器、CDN、代理服务器等中间层,是否可以缓存这个资源,以及怎么缓存。简单说:
Cache-Control
是用来管理缓存策略的指挥棒!为什么需要
Cache-Control
?如果没有它,缓存行为非常混乱:
什么内容能缓存?
缓存多久?
什么情况下要重新请求服务器?
如何保证缓存是最新的?
所以,HTTP/1.1 通过
Cache-Control
标准化了缓存规则,提高了 性能 和 一致性体验!常用的
Cache-Control
指令总结
指令 作用 no-cache
不直接使用缓存,每次都向服务器确认是否有更新(不是不缓存!) no-store
完全不缓存,请求和响应都不存本地 public
可以被任何中间缓存服务器(比如 CDN)缓存 private
只允许用户本地缓存,中间层不缓存 max-age=秒数
在多少秒内可以直接用缓存,无需请求服务器 s-maxage=秒数
专门给代理服务器(CDN)设定的 max-age,优先级高于 max-age must-revalidate
过期后必须向服务器重新验证,不能使用过期缓存 proxy-revalidate
代理服务器也必须重新验证 假设你希望一个图片缓存 1 天(86400秒),过期后重新请求
Cache-Control: public, max-age=86400, must-revalidate
含义:
浏览器、CDN可以缓存
86400秒内直接用缓存,不发请求
过期后必须重新验证
减少请求数量
合并请求和资源文件(如将多个CSS、JS打包,雪碧图合并小图标),启用HTTP/2多路复用减少连接开销。对初次加载不必要的资源采用懒加载或按需加载,降低首屏渲染压力。
优化渲染路径
尽量避免阻塞渲染的操作。将脚本放在页面底部或使用
defer
/async
异步加载,采用服务端渲染 (SSR) 提前生成部分HTML以缩短首屏时间,在需要SEO的场景(如电商商品页)尤其有用。对于单页应用 (SPA),合理使用路由懒加载和虚拟DOM减少重绘重排。
前端安全与稳定
使用HTTPS保障传输安全,合理设置Content Security Policy等防范XSS等攻击。对重要交互加入前端校验和限流(如按钮防抖),避免因为用户重复点击导致后端收到洪峰请求。
场景实践
在电商秒杀场景下,前端通常采用静态化的活动页面并提前加载必要资源,按钮会在倒计时结束后才激活,以减少无效请求;同时引入验证码或滑块验证防止恶意刷请求。
在SaaS CRM系统中,由于功能复杂页面众多,常采用SPA架构配合组件懒加载,保证后台管理界面在功能丰富的同时保持良好响应。
对于支付系统的前端,重点在于安全和可靠性:页面需防止重复提交订单(前端按钮“一次点击”原则),并在请求支付后给予明确的进度提示(如转圈动画)避免用户频繁刷新。
SPA架构配合组件懒加载
SPA(Single Page Application,单页应用)
指的是整个网站只有一张 HTML 页面,不同的内容是通过 前端路由 动态切换出来的,而不是重新请求服务器加载新页面。简单说:只加载一次页面,之后都靠 JS 控制视图切换。比如:Vue、React、Angular 的项目,基本上都是 SPA。
SPA 的一个大问题:首屏加载慢
因为 SPA 要一次性加载大量的 JS、CSS,首屏很容易:
白屏时间长
页面迟迟不出东西
用户体验差
所以就有了一个非常重要的优化手段:组件懒加载(Lazy Loading)
什么是组件懒加载?
组件懒加载指的是:只在需要时,才按需加载某个页面或组件的 JS 资源,而不是一开始就全部打包到一起。
比如用户一开始在首页,后台管理页的代码就先不加载。等到用户点到后台时,再去请求那块 JS 文件。就像打游戏一样,先加载新手村地图,等你去冰雪之城再加载冰雪之城地图。
旨在:
缩短首屏白屏时间
减少初始下载资源
提高网站性能和体验
常见坑点
-
缓存失效策略: 静态资源版本更新时如果未正确处理缓存,用户可能加载旧版本导致功能异常。通常通过文件名哈希或版本号确保更新时客户端能获取新资源,或配置CDN在发布时清理缓存。
-
大数据量渲染: 单页应用一次性渲染海量DOM节点会导致浏览器卡顿甚至崩溃。这在CRM系统显示大型报表时容易出现。解决方案包括分页加载、虚拟列表技术等。
-
内存泄漏: 前端长时间运行(尤其后台系统长期开着)若事件监听或组件未正确卸载,可能导致内存泄漏,时间久了页面变慢甚至崩溃。开发时需注意清理定时器、事件绑定等。
-
浏览器兼容性: 不同浏览器对新特性的支持差异可能导致功能异常。需使用Polyfill或降级处理,以免在某些用户环境出现问题。
实践案例
多家互联网公司采用了前后端分离+CDN加速的架构优化前端性能。例如,
淘宝将商品详情页预渲染为静态页并通过CDN发布,用户打开页面时基本不需要向源站请求动态内容,确保了双11大促时即使瞬时流量暴增页面也能秒开。
美团针对移动端网页的网络波动,开发了优化弱网下资源加载的方案,提高了App在弱网环境下的加载速度。
这一切都体现出前端架构在系统设计中的重要性:合理的前端优化能极大缓解后端压力,提高系统整体的可用性和流畅度。
CDN(内容分发网络)
CDN 的作用
CDN(Content Delivery Network)通过在全球各地部署边缘节点服务器,将网站的静态内容分发缓存到离用户更近的节点上,以实现就近访问。用户请求内容时,会由离其最近的CDN节点提供响应,从而加速静态资源访问,显著降低源站服务器的负载和带宽压力。简单来说,CDN就好比网站的“物流仓库体系”,把资源提前储存在各地的“仓库”,用户访问时从附近仓库取货,免去长途传输延迟。这对于大流量的网站非常关键——例如热点新闻、视频网站、商城的图片和脚本,都几乎必然使用CDN加速。
工作原理
CDN通过DNS调度等技术将用户请求指向最佳节点。当用户首次请求某资源时,如果CDN节点上没有缓存,会向源站拉取并缓存该资源;后续请求直接命中缓存。CDN系统在靠近用户的位置存储网站静态资源(图片、视频、CSS、JS 文件等),当用户请求这些资源时,无需直接访问源站。同时CDN通常具备智能路由和负载均衡能力,能根据用户网络状况选择最快的节点响应。如果某个节点发生故障或响应变慢,CDN调度系统可自动切换节点,提高整体可用性。
优化策略
缓存策略: 为不同类型的内容设置合适的缓存过期时间(TTL)。对于很少变化的资源(如版本固定的JS/CSS文件或产品图片),TTL可以设置较长,实现长期缓存;对于可能频繁更新的内容(如新闻页HTML),TTL可以较短甚至不缓存,并利用CDN的协商缓存(If-Modified-Since/ETag)机制确保必要时及时更新。合理利用 Cache-Control 和 Expires 头,让浏览器和CDN共同缓存内容,提高缓存命中率。
回源降载: 避免CDN缓存失效时大量请求瞬间回源造成源站压力陡增(即回源雪崩)。可采用分片过期:让缓存过期时间错开,或通过CDN提供的预取/预热接口,在内容即将过期前主动刷新缓存。在电商秒杀场景中,大促页面往往提前缓存好,并确保缓存有效期覆盖活动高峰期,以避免活动过程中回源查询。
CDN容灾: 准备备用方案以防 CDN 服务商故障。如果主要 CDN 大面积故障,用户可能无法访问资源。可以为关键业务配置多个 CDN 服务商的冗余,当探测到某主 CDN 节点不可用时,自动切换到备用 CDN。美团外卖团队就曾在客户端实现CDN可用性探测与自动容灾切换方案,有效降低了业务对 CDN 异常的敏感性
场景实践
在电商秒杀中,CDN 扮演关键角色——静态页、商品图片、CSS/JS等全部通过CDN分发,用户在抢购过程中几乎所有静态资源都本地化命中,只有下单等操作会访问源站,大大提升了并发承载能力。
SaaS CRM系统面对各地企业用户,也会利用 CDN 将前端静态资源和常用数据分发到各区域,让不同城市的用户访问速度一致。
对于支付系统,虽然支付流程主要是动态交互,但其静态资源(支付页面HTML、样式脚本)同样通过CDN加速,此外CDN的全球节点还能加速海外用户的支付页面加载,提高支付成功率。
常见坑点
-
缓存不一致: 更新资源时,如果不同节点缓存未同步刷新,可能出现有的用户拿到新版本有的拿到旧版本。解决办法是内容版本化:更新时更改文件名(如附加版本号或hash),让CDN缓存的新旧内容共存,避免旧缓存干扰;或者同时调用CDN提供的API批量刷新关键内容。切忌在不确定缓存配置时直接修改文件却不刷新CDN,否则会产生难以复现的线上问题。
-
回源带宽压力: 当某些资源一段时间未被访问而从边缘节点逐出缓存后,突然又有大量用户访问,CDN会将请求回源。若源站带宽不足,会造成性能瓶颈。需要监控CDN回源流量,确保源站有足够冗余,必要时升级源站带宽或增加源站节点,并设置CDN的缓冲站点缓存层级缓解回源压力。
-
成本控制: CDN 按流量计费,高峰流量可能带来高费用。需权衡加速收益和成本。比如对于内部员工使用的CRM系统,可以对非公开网络场景选择性关闭CDN或使用自建节点。在预算有限时,重点保障关键页面和大流量资源走CDN,加速效果与成本做到平衡。
实践案例
各大厂都高度依赖 CDN 提升访问性能。
淘宝/天猫的双11会场页面及商品详情资源全部提前部署在多家 CDN 上,以承受峰值流量;
哔哩哔哩视频网站通过 CDN 提供全国高速的视频内容分发,即使弹幕密集的视频也能流畅加载。
在美团外卖业务中,工程师们甚至设计了端侧 CDN 容灾方案,当检测到某CDN节点响应异常时,客户端自动切换到另一个CDN域名,以保障用户加载图片和菜单的体验。
可以说,CDN 已是高并发系统的标配,加速和稳定效果显著。
什么是端侧 CDN 容灾?
端侧 CDN 容灾,就是指在客户端(浏览器、APP),检测并处理 CDN 节点异常,确保资源可以正常访问,避免因为 CDN 故障导致白屏、功能不可用。
简单说: 服务器挂了不要紧,端上自己能兜底补救!
为什么需要端侧容灾?
CDN 节点虽然多,但也可能局部故障、网络劣化
如果不做容灾,用户端请求超时或者失败,体验非常糟糕
服务端无法完全感知每一个用户的网络状态,必须端上自救
端侧 CDN 容灾核心思路
核心动作 说明 监控请求 判断资源是否加载成功,比如图片、脚本 快速降级 检测失败后,快速切换备用地址 多源备份 预设多个 CDN 备份源(多域名、多存储) 限速与重试 避免疯狂重试,合理限流控制 常见端侧容灾方案
1. 多 CDN 域名 fallback
配置 主域名 + 备域名(多个CDN供应商,比如又拍、阿里云、腾讯云)
加载资源失败后,自动切换到下一个域名重新请求
2. 加载前预检测(测速探测)
在加载大资源之前,发一个小文件探测(比如 1x1像素图片,或者小的 JSON 文件)
测速,如果超时或者失败,就提前切备用源
3. 本地缓存兜底(Service Worker)
利用 Service Worker 缓存重要资源
即使 CDN 挂了,也能从本地缓存里读出来
端侧 CDN 容灾注意事项
问题 解决建议 不要无限重试 控制最大重试次数,避免雪崩效应 合理选择备源 主备源部署在不同运营商/机房 优先检测主源 小文件探测提前预判,用户无感知 降级策略 比如低清图代替高清图、小功能降级展示
Nginx 负载均衡
在后端架构中,引入负载均衡(Load Balancing)是支撑高并发的重要手段。Nginx 是流行的七层负载均衡服务器,常被用作网关来将客户端请求分发到后端多个服务实例上。通过负载均衡,可以横向扩展服务:当单台应用服务器无法承载流量时,增加多台服务器并由Nginx分配请求,实现集群共同承担压力。此外,Nginx还可以作为反向代理,缓存后端响应、进行请求合并,从多个层面提升系统性能。
负载均衡策略: Nginx 支持多种负载均衡算法,可根据配置选择请求分配方式:
-
轮询 (Round Robin): 默认策略,每个请求按顺序依次分配给后端服务器,实现简单的平均分摊。
-
加权轮询 (Weighted RR): 按配置的权重比率分配请求,权重高的服务器承担更多请求。适用于后端服务器性能不均等的情况,可让高配服务器多承担一些流量。
-
最少连接 (Least Connections): 将新请求分配给当前活动连接数最少的后端,避免某些请求处理慢的节点堆积请求。这在请求处理时间差异较大时提升整体响应速度。
-
源地址哈希 (IP Hash): 根据客户端 IP 进行哈希,固定将同一 IP 的请求分配到同一台后端服务器。这样可实现会话粘滞,确保用户的连续请求落在相同节点上(比如维持登录会话),适用于无状态会话存储困难的情况。
-
其它策略: 使用第三方模块还可实现URL哈希(按请求URL分配),Fair算法(根据后端平均响应时间动态调整)等策略。选择策略时要结合业务特点,常用的是轮询、加权和IP哈希。
部署架构
在大型分布式系统中,负载均衡常常多级组合:前有四层负载均衡(如LVS、HAProxy)承担海量连接的分发,后有Nginx这类七层负载均衡做应用层路由和缓存压缩等工作。例如某些大厂的架构是用户请求先通过DNS解析到最近机房,然后进入LVS集群做IP层转发,再到各机房内部由Nginx将请求按URL转发到对应服务集群。Nginx本身也可集群部署:为了防止单点故障,通常会部署多台Nginx,同步配置,并通过Keepalived等做VIP漂移以实现高可用。当一台Nginx故障时,流量自动切换到另一台,保证负载均衡服务不中断。
优化策略
调优Nginx负载均衡需要考虑高并发连接和后端健康管理:
-
连接复用与限速: 调高
worker_connections
等参数以允许更多并发连接,开启keep-alive保持客户端连接复用,从而减少TCP建立开销。Nginx还能通过限速模块对单IP或总并发做限制,防止恶意请求耗尽后端资源。 -
健康检查与熔断: 配置Nginx对后端节点进行健康检查(如探测心跳URL)。当检测到某个节点连续失败达到阈值时,可暂时将其摘除(熔断)停止转发,等待其恢复正常再自动加入。这避免了持续把流量发送给已故障或超载的节点而影响用户请求。
-
SSL卸载和静态缓存: 在HTTPS场景下,将SSL握手和加解密工作由Nginx完成(即SSL卸载),减轻后端服务器CPU负担。同时Nginx可启用
proxy_cache
等功能缓存后端响应(例如静态JSON数据),后续请求直接由Nginx返回缓存结果,加速响应并降低后端压力。
场景实践
电商秒杀时,Nginx需要承载巨量并发请求的分发。为防止Nginx自身成为瓶颈,通常会部署多实例Nginx并做LVS前置,同时调高Nginx的worker进程数和连接数上限,确保能处理瞬时涌入的成千上万连接。对秒杀接口进行限流(这可在Nginx用lua脚本实现简单令牌桶)是常见操作,防止恶意刷请求打垮后端。
支付系统一般要求请求有序处理且安全,因此常使用IP哈希或在上层网关做会话黏着,确保支付过程中的多步请求落在同一后端,避免跨节点造成状态同步问题。此外,支付网关还会配置严格的健康检查,任何一台后端响应变慢都会被临时摘除,以保障支付请求低延迟。
SaaS CRM系统因为服务众多、接口繁杂,API网关(往往基于Nginx)会根据URL将流量路由到不同业务集群,例如将/crm/customer
打头的请求送往客户服务集群、/crm/sales
送往销售管理服务。网关还可实现统一认证和鉴权,拦截未授权请求,提升整体安全性和一致性。
常见坑点
-
单点故障: 仅部署单台负载均衡会成为单点,一旦故障整个服务不可用。需要多实例冗余和健康检查,以及配套的自动切换机制(如VRRP协议的Keepalived)保证高可用。
-
会话粘滞影响扩展: 如果依赖IP哈希等实现黏住会话,那么当需要临时增加节点承担流量时,哈希可能导致部分老用户仍指向原节点,新节点得不到流量分担。解决办法是在服务端实现无状态会话(比如将session存Redis集中管理),尽量避免对负载均衡层黏住会话的依赖。
-
不当的超时设置: Nginx对后端有连接和读取超时设置。如果设置过长,后端卡顿时请求会长时间挂起占用连接;设置过短又可能误判正常慢请求为超时而过早终止。需根据后端服务特点调整。尤其在支付等场景,某些第三方接口可能需要较长等待,这时网关超时要适当放宽或做特殊处理,否则用户支付到一半被切断体验很差。
-
日志与监控不足: 负载均衡节点往往是故障排查的关键点。如果没有详细的访问日志(包括客户端IP、请求路径、后端分配结果等)和监控(如各后端QPS、健康情况),出问题时很难迅速判断是负载均衡配置问题还是后端服务问题。要确保Nginx的日志级别和监控指标全面覆盖。
实践案例
许多大规模系统采用多层负载均衡架构。
例如淘宝在双11期间通过 DNS 将用户引导至各地机房,再由 LVS 集群实现数百万级别并发连接的四层分流,最后由机房内成百台 Nginx 服务器做七层转发和缓存压缩。
美团内部也构建了统一的接入层网关 Oceanus,作为七层负载均衡网关每天处理着千亿级调用,背后支撑着几千个服务节点、近万个注册服务。
在滴滴出行的架构中,乘客端和司机端请求首先进入全局流量调度中心,再由各业务线的Nginx网关路由到具体微服务集群,实现了出行、高并发场景下的高效请求分发。可以看到,负载均衡设计是大型系统稳定运行的基石。
服务集群与微服务架构
当系统规模扩大、功能模块增多时,服务集群化和微服务架构是一种行之有效的设计思路。它将单体应用拆分为多个可独立部署和扩展的服务,分别负责不同的业务功能(如用户管理、商品、订单、支付等),通过远程调用协同完成整个业务流程。这样做的好处是每个服务可以按需横向扩展,并由专门团队独立开发部署,提升开发效率和系统弹性。
核心组件
-
服务注册与发现: 由于服务实例动态扩容缩容,需要一个注册中心跟踪所有服务地址。服务启动时将自身地址注册上去,调用方通过注册中心发现可用实例列表。常见实现有 ZooKeeper/Etcd、Eureka、Consul 以及阿里的 Nacos 等。
-
API 网关: 微服务数量众多时,一个统一入口的 API 网关能提供路由转发、协议转换、安全校验等功能。它接受客户端请求并根据URI或其它路由规则将请求转发给内部服务,还能做统一的认证、限流和日志记录。提到,美团在微服务拆分导致API规模激增的情况下,开发了统一的API网关服务 Shepherd 来管理所有接口流量。网关也可屏蔽内部架构变化,对前端提供稳定的REST/RPC接口。
-
配置与治理中心: 随着服务实例的剧增,集中管理配置(如数据库连接串、开关参数)很必要。配置中心(如Apollo、Spring Cloud Config)可以统一下发配置并实时通知。服务治理平台则管理服务的各种规则,如限流熔断策略、升级发布控制等。美团内部的 OCTO 服务治理平台就是这方面实践的例子,包含服务通信框架、命名服务、服务数据中心等组件,为内部全部服务提供统一的治理方案。
-
通信与调度: 服务间通信可采用HTTP/REST,也可用RPC框架。阿里开源的 Dubbo、Facebook 的 Thrift 等都是RPC框架,可以提供高性能的服务调用。美团等大厂也研发自有RPC框架并结合Service Mesh理念,比如美团的 OCTO 2.0 基于 Service Mesh 来增强服务治理能力。另外,像美团 Oceanus 网关不仅负载均衡,还提供HTTP层面的服务治理,每日承载海量服务调用
扩展与部署
服务集群一般通过容器化+编排来管理。使用 Docker 将服务封装,然后用 Kubernetes 等容器编排系统在集群中调度部署,实现弹性伸缩和故障自愈。
场景实践
在电商领域(如淘宝、京东),后台通常拆分为商品服务、购物车服务、订单服务、支付服务等,各自独立部署扩展。秒杀活动期间,可能还会有专门的抢购服务模块,用来处理秒杀逻辑并与库存服务交互,在高峰时可以单独水平扩容这个服务而不影响其他部分。
SaaS CRM系统由于需要服务多个企业客户,往往采用多租户微服务架构:公共的基础服务(用户认证、权限)共享,但每个租户的数据操作由独立服务或逻辑处理,确保数据隔离。比如,CRM会将“销售线索服务”、“客户管理服务”、“报表服务”等解耦,各模块通过消息或API集成,使不同租户的请求在后端可以分散到不同服务实例处理,从而同时支撑多个客户使用。
支付系统对可靠性要求极高,通常将账务、风控、通知等功能也拆成独立服务。例如支付完成后,账务服务负责记账,通知服务负责发送用户通知,彼此解耦并异步处理,即使通知失败也不影响核心支付流程完成。
什么是多租户(Multi-Tenant)?
多租户指的是同一个系统实例同时为多个独立客户(租户)服务,数据隔离,资源共享。
简单说就是:一套微服务,多个客户一起用,但互相数据隔离。
比如:
企业微信:你在用,我也在用,账号不同,但后台一套系统。
美团商家后台:每个商家登录的是自己的数据,但其实是统一平台。
多租户微服务架构
在微服务体系中,支持多租户并保证租户数据隔离、安全,同时服务复用、资源最大化。
多租户微服务关键设计点
设计领域 要点 数据隔离 不同租户数据不能混淆(数据库层面设计) 认证授权 确保用户访问的是自己租户的数据(Token携带租户ID) 配置隔离 每个租户可以有自己定制的配置(如主题、功能开关) 性能隔离 单个大租户不能拖垮整个系统(限流、配额管理) 服务治理 多租户要统一管理、监控、扩缩容 多租户架构常见模式
模式 特点 单实例单数据库 一套代码,一个数据库,所有租户的数据共存在表里,通过 tenant_id
区分(最省资源,常见)单实例多数据库 每个租户单独一套数据库,系统连接不同数据库(隔离更强,适合大客户) 多实例多数据库 每个租户一套完整系统部署,隔离极强,但运维复杂,成本高(适合超大型客户) 关键技术设计细节
1. 租户上下文(Tenant Context)
用户请求到来时,必须知道是哪个租户(tenant_id)
通常通过 JWT Token、HTTP Header、请求参数携带
在微服务内部每一层透传
2. 数据隔离方案
数据库表加租户字段 (
tenant_id
)应用层自动注入查询条件(Mybatis Interceptor、Hibernate Filter)
复杂场景甚至做逻辑分库分表(分租户)
3. 接入网关 (API Gateway) 租户鉴权
微服务前统一通过 API Gateway 拦截、鉴权
根据 Token、Header,打上租户标签,后端透明使用
比如:
用户访问 → API Gateway提取token → 验证租户 → 请求转发
4. 配置中心多租户支持
Apollo、Nacos等配置中心,支持租户维度的配置隔离
不同租户可以加载不同的 feature 开关、参数、主题
5. 资源隔离与弹性伸缩
各租户有独立的配额(请求QPS、磁盘配额等)
热点大租户支持自动扩容(HPA / K8S多副本)
防止大客户"劫持"公共资源
+-------------+| API Gateway |+------+-------+|+-----------+-----------+| |+--------v-------+ +-------v--------+| Authentication | | Configuration |+--------+-------+ +-------+--------+| |
+----------v------+ +-------v---------+
| User Service | | Product Service |
+----------+------+ +-------+---------+| |+-------v------------------------v------+| Shared Database (tenant_id) |+---------------------------------------+
常见坑点
-
分布式事务: 原本单体内的本地事务,拆到多个服务后就变成分布式事务,很难保证强一致性。如果不加设计,可能出现部分服务更新成功而部分失败的不一致情况。解决方法包括采用最终一致性(通过消息队列异步校正)或引入分布式事务协调器(如 Saga 模式)等。但要慎重,过度追求强一致会使系统复杂度飙升。
-
网络延迟与可靠性: 服务间远程调用相比进程内调用有网络延迟,链路长了总延迟可能增大。同时网络调用也有失败可能,需做好重试和超时控制。服务网状依赖下,任何一个服务变慢都会级联影响整体。美团的实践表明,当微服务数量和复杂度提升后,网状依赖中任何轻微的延迟都可能传导放大。因此需要引入熔断和限流机制(在后续章节详述)来避免雪崩效应。
-
运维复杂度: 服务实例成百上千后,日志追踪和监控告警变得困难。需要实施全链路追踪(如使用SkyWalking、Zipkin等)以跟踪一次请求经过哪些服务、耗时多少;也需要完善的监控体系监视各服务的QPS、错误率、平均延迟等。否则出了问题难以及时定位是哪一个子服务导致。
-
资源浪费与调优: 拆分微服务后,每个服务都有独立的资源配额,但是流量在实际中可能不均衡。如果各服务按照峰值各自申请资源,可能总的计算资源利用率不高。需要通过容器编排的平台根据负载动态调整,或者结合云厂商弹性伸缩来优化资源使用。此外,微服务粒度也要拿捏合适,过细会导致调用量剧增(典型的微服务不再微的问题),需要根据业务关联度适当合并成中粒度服务。
实践案例
几乎所有一线互联网公司都实施了微服务架构。
美团内部服务治理框架 OCTO 支撑了上万微服务的注册发现和通信,配套的 Oceanus 七层网关每天处理千亿级服务请求。美团还开发了Shepherd API网关来统一管理外部接口流量,使客户端只需调用网关而无需关心后端服务细节。
滴滴出行则在2017年全站进行了服务化改造,将原先的巨石应用拆分为300多个微服务,显著提高了开发部署效率,同时也经历了一次由于微服务依赖未治理好而在春节高峰发生的连锁故障,事后滴滴加强了熔断降级策略,建立了健全的服务监控体系。
小米公司在其电商和云服务中也采用微服务架构,并结合 Kubernetes 实现了一键扩容缩容,其开源的微服务框架(如 Dubbo 的改进版)也服务于社区。可以说,服务集群化和微服务已成为大型系统的标配架构,在提高系统可伸缩性的同时,需要成熟的治理手段来保证稳定性。