搭建百万级并发的微服务系统如何设计一. 拆分分而治之1服务拆分与治理。把庞大的单体按照业务领域拆分成用户、订单、支付、库存独立的服务。利用注册中心nacos完成服务注册与调用。服务启动时后端服务自动把自己的IP端口注册到Nacos,调用方通过nacos获取健康服务列表配合Ribbon或者LoadBalancer做负载均衡。这是客户端负载均衡。【注一。 服务自动注册到Nacos(服务提供者)1. 注册流程后端微服务启动时Nacos Client(spring-cloud-starter-alibaba-nacos-discovery)自动执行1. 读取本机IP、服务启动端口、服务名、权重、健康检测配置2. 向Nacos Server发送注册请求把服务名- [IP:Port实例列表】存入nacos;3. 服务持续发送心跳包默认5秒上报健康状态4. Nacos超过15秒收不到心跳标记实例为不健康剔除可用列表。Nacos:存取全量服务实例维护实例健康状态----Nacos本身不负责分发流量不做负载均衡。2. 调用方拉取服务实例服务发现调用服务启动时同样引入Nacos Discovery流程1. 调用方本地Nacos Client向Nacos Server订阅目标服务2. Nacos主动推送该服务实例列表给调用方本地缓存;3.后续实例上下线健康状态变更Nacos实时推送增量更新4. 调用方本地内存常驻一份可用实例清单不用每次调用都查Nacos.3. 客户端实现负载均衡完整时序图极简梳理服务提供者启动 → 注册 IP 端口 心跳到 Nacos调用方启动 → 订阅目标服务本地缓存健康实例业务发起http://服务名调用LoadBalancer/Ribbon 拦截请求读取本地实例列表本地执行均衡算法选出单个实例 IP:Port直连目标后端服务完成调用调用失败则本地剔除故障实例、触发重试Nacos 同步更新健康状态客户端负载均衡 vs 服务端负载均衡 完整对比先一句话区分核心客户端 LB选实例的逻辑在调用方客户端本地调用方直连目标服务无中间转发。服务端 LB有一台独立中间代理服务器做分流所有请求必须先经过代理由代理选后端实例。一、核心原理对比1. 客户端负载均衡Nacos Ribbon/LoadBalancer、Dubbo 内置负载均衡角色划分 调用服务 客户端被调服务 服务端 流程消费者启动时从 Nacos 拉取全部健康实例缓存到自己内存每次发起远程调用前消费者本地代码执行均衡算法选出一个 IP:Port消费者直接 TCP/HTTP 直连选中的后端服务不经过任何中间机器。2. 服务端负载均衡Nginx、SLB、SpringCloud Gateway、Kong流程调用方只知道代理网关地址完全不知道后端真实服务 IP请求统一发给中间代理代理服务器执行负载均衡算法挑选后端实例代理再把请求转发给目标服务响应原路返回代理再给调用方。二、详细维度对比表表格对比维度客户端负载均衡服务端负载均衡均衡逻辑位置调用方服务内部Ribbon/LoadBalancer 代码独立中间代理服务器请求链路调用方 → 直连后端服务两层调用方 → 网关 / 代理 → 后端三层转发是否感知后端实例调用方持有全部实例列表知道真实 IP 端口调用方只认代理地址看不到后端实例网络性能少一次转发延迟更低无代理瓶颈多一层转发增加耗时代理存在性能损耗单点风险无统一中间节点不存在 LB 单点故障代理本身是单点必须集群部署高可用扩容成本新增服务消费者每个服务都要维护实例缓存只扩容代理集群即可调用方无需改动统一管控能力均衡规则、限流、鉴权分散在各个调用服务统一管控难所有流量收口统一鉴权、限流、灰度、日志、监控适用场景微服务内部互相调用服务间 RPC/HTTP 调用前端访问后端、第三方外部调用、统一流量出入口代表组件Spring Cloud LoadBalancer、Ribbon、Dubbo 负载均衡Nginx、阿里云 SLB、Spring Cloud Gateway、Traefik实例更新机制调用方订阅注册中心本地缓存实时更新代理定时探活后端服务列表三、举两个实际例子看懂例 1客户端 LB订单调用库存订单服务调用方本地缓存库存 3 台实例地址每次调用自己轮询选一台直接发请求给库存不经过任何网关。 优点内网直连速度快缺点想统一限流要每个服务单独配置。例 2服务端 LB用户浏览器访问商城用户只访问shturl.cc/sFy不知道后台有几十台商城服务Nginx 接收请求自己分配到某一台商城机器再转发。 优点外部流量统一收口安全管控方便缺点多一层转发Nginx 需要集群防挂。四、优缺点总结客户端负载均衡 优点无中间转发性能更好内网微服务调用首选无代理单点瓶颈横向扩展无压力简单轻量不需要额外部署网关组件。客户端负载均衡 缺点所有调用服务都要集成注册中心、均衡组件代码侵入流量分散无法全局统一管控路由、限流、黑白名单均衡策略变更所有调用服务都要重新发布。服务端负载均衡 优点流量统一入口集中做鉴权、限流、监控、灰度发布调用方无感知后端集群对外只暴露一个域名切换后端服务、调整均衡策略无需改动业务服务代码。服务端负载均衡 缺点多一层转发增加网络延迟代理服务器存在性能上限高并发下需要集群扩容网关本身需要单独维护、扩容、做高可用。五、企业标准架构搭配两者同时使用线上微服务一般组合使用各司其职外部流量 → 服务端 LBGateway/Nginx统一接收前端、第三方请求做路由、鉴权、限流微服务内部互相调用 → 客户端 LBLoadBalancerNacos订单、库存、支付内网互调直连保证性能。】Nacos的动态配置管理动态调整线程池参数或者日志级别不用重启服务Nacos配置一改全量下发全部服务实例都收到推送; 每个客户端拉取完整配置内容2. 数据拆分。垂直分库做到专库专用可以解决服务太多数据库连接太多的问题减少数据库的压力。如果垂直分库完的表还是很大比如说订单表很多数据就需要水平分表使用工具是ShardingSphere“我们利用Sharding-JDBC,配置好分片键比如user_id或者order_id”通过一次性hash算法把一张大表拆成1024个小表均匀的分布在不同的物理磁盘上这样就把几种的IO压力打散了。【注分库分表的分布式事务原来的Transactional不管用了为什么单库单表的Transactional是本地事务JDBC事务只作用于单个数据库连接一旦分库分表一次业务操作会操作多个不同库的连接原生Transactional只能保证单个库成功/失败跨库无法原子回滚因此失效。一、先搞懂Transactional 的底层原理本地事务Spring 的Transactional依赖 JDBC 原生事务事务绑定一个数据库 Connection执行逻辑方法开启事务从数据源拿一个 Connection关闭自动提交autoCommitfalse所有增删改都共用这同一个 Connection正常执行统一commit异常统一rollback约束同一个事务内只能操作同一个数据库。举个简单场景java运行Transactional public void createOrder(){ orderMapper.insert(); // 库A.order_0 stockMapper.deduct();// 库B.stock_0 }order 走库 A 连接stock 走库 B 连接是两个独立 ConnectionSpring 事务只会管理第一个 Connection库 A如果插入订单成功库 A commit扣库存抛异常库 B 报错库 B 自己回滚但库 A 已经提交数据不一致出现脏数据。二、分库分表为什么会产生多个数据库连接分库分表中间件Sharding-JDBC、MyCat两种形态Sharding-JDBC客户端分片应用本地持有多个数据源ds0、ds1、ds2…不同分片库对应不同DataSource每个库拿到独立 ConnectionMyCat代理分片应用只连 MyCat但 MyCat 后端连接多个真实 MySQL 库底层依然是多连接。一条业务 SQL 逻辑上拆分成多条、下发到不同分片库 → 占用多个独立数据库会话。 而原生Transactional只能控制单个会话跨库无力。三、分情况拆解 Transactional 的失效表现1. 同库不同分表仅分表不分库所有分片表都在同一个 MySQL 库共用一个 Connection ✅Transactional依然有效能正常回滚。2. 跨多个数据库分库 分表操作 ds0、ds1 两个库两个连接 ❌ 原生Transactional完全无法保证原子性会出现部分库提交、部分回滚。四、原生本地事务的本质缺陷事务边界局限单数据源只能绑定一个 Connection没有跨库协调者多库之间无统一调度A 库提交后B 库失败无法撤回 A 库已提交数据MySQL InnoDB 不支持跨实例分布式回滚不同 MySQL 库是独立实例彼此感知不到对方事务状态。五、解决方案分布式事务替代单纯 Transactional分库场景必须使用分布式事务方案主流 4 种1. XA 强一致性2PCSeata AT 模式原理二阶段提交统一协调所有分片库使用Seata Sharding-JDBC注解换成GlobalTransactional特点强一致性能一般适合并发不高场景。2. TCC侵入业务性能高自己实现 Try/Confirm/Cancel无锁高并发场景。3. SAGA 柔性事务长事务、流程编排补偿事务适合跨服务 分库长流程。4. 本地消息表 / 可靠消息最终一致性最常用通过 MQ 做异步补偿性能最好仅保证最终一致。六、对比Transactional 和 GlobalTransactionalTransactional管理单个数据库本地事务适用单库能力ACID 强一致跨库失效。GlobalTransactionalSeata管理多个分片库、多微服务全局事务适用分库分表、微服务跨服务能力全局原子性全部成功或全部回滚。七、极简例子直观感受问题库 1order_db新增订单库 2stock_db扣库存加普通 Transactional插入订单成功库 1 自动提交扣库存代码抛空指针库 2 执行回滚结果订单存在库存没扣数据不一致。如果换成 SeataGlobalTransactional所有分片操作先 undolog 记录快照不真实提交全部执行无异常 → 统一提交所有库任意节点报错 → 根据 undolog 反向回滚所有分片数据。一句话总结Transactional是单数据库连接的本地事务分库场景会产生多个独立数据库连接它只能控制其中一个库无法协调跨库统一提交 / 回滚因此跨分库时失效必须引入分布式事务框架如 Seata实现全局事务。】