小镇上的“老王餐馆”火了。原来只有一个灶台,老王一个人洗菜、切菜、炒菜、收银、上菜全包——这就是典型的“单体应用”:所有逻辑挤在一个大锅里,改一道菜的口味得把整口锅都翻一遍。客人一多,灶台糊了、订单堆了、出菜慢了。老王痛定思痛,决定把后厨改造成六个独立档口:凉菜档、热炒档、蒸菜档、烧烤档、甜品档、出菜档。每个档口有自己的灶台、冰箱和厨师,档口之间只通过“传菜口”和“订单小票”协作。 这个后厨改造的故事,就是微服务架构里最核心的一堂课——服务拆分。系统不会凭空变成微服务,它需要一整套原则告诉你:该切几刀、从哪里下刀、怎么避免切坏。本文会用老王的后厨贯穿始终,带你理解领域驱动设计、拆分粒度、数据策略、反模式、团队组织与演进路线,让你真正看懂微服务架构的基石。
掌握服务拆分原则,你才能从“会写接口”进阶为“能设计系统”——这是架构师、AI平台技术负责人必须拥有的核心能力,也是微服务落地成败的第一道分水岭。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
订单服务 服务拆分策略对比:DDD按业务边界拆分内聚度高、按技术层拆分导致跨服务修改、纳米服务粒度过细通信复杂度爆炸。
拆分核心原则
老王的第一个想法是“把厨房切成块”。但切块的标准是什么?隔壁老李建议他按“这边放调料、那边放锅具”来分(按技术层切),老王觉得不对劲——一个人的活让两条流水线干,传菜反而更乱。他最后决定按“品类”分:凉菜、热炒、蒸菜、烧烤各成一个档口。这个决策就是服务拆分的第一原则:按业务域划分边界,而不是按技术组件划分。
在微服务里,一个服务对应一个独立业务能力,比如“订单服务”管下单,“库存服务”管库存。每个服务对业务域内的事情“全权负责”,对外只暴露必要的接口,内部怎么做是这个档口自己的事。只有这样,服务才能独立部署、独立伸缩、独立演进——老王想让烧烤档多架两个炉子(弹性扩容),完全不用惊动甜品档。
如何量化一个服务边界好不好?核心指标是内聚度:服务内的功能是否都围绕同一个业务域。
老王把“切菜”和“炒菜”都留在同一个档口里,因为二者同属“这道菜”的业务域;若是切菜归一个部门、炒菜归另一个部门,那么切完的菜端到炒锅前就要跨部门沟通——这正是微服务拆分要避免的架构悲剧。
- 内聚度函数$\text{Cohesion}(S)$ 表示对服务 $S$ 的内聚程度打分,衡量这个服务内部功能是否聚焦于同一个业务主题。
- 同域功能数$|F_{\text{domain}}|$ 统计服务内属于同一业务域的功能条目数,也就是“这个档口里干本行活的次数”。
- 服务总功能数$|F_{\text{all}}|$ 表示服务内全部功能条目总数,是规模的度量。
- 高内聚判据比值越接近 $1$,说明服务越“专一”,越不容易被无关修改牵动。
领域驱动设计
后厨改造的第一天,老王没有急着砌墙,而是把店里最资深的老师傅们请来,让他们把“菜是怎么从生到熟走完全程”画成了一张张流程图。这张图里,每道菜只属于一个档口,每个档口有自己的术语和规则。老师傅们画的这张“菜谱地图”,就是软件工程里的领域驱动设计(DDD)。
DDD 中最关键的概念是限界上下文(Bounded Context):它划定了一个业务概念的有效范围。比如“订单”在销售上下文里指“待支付订单”,在仓库上下文里指“待发货订单”,二者语义不同,就该分属不同的限界上下文,各自建模,互不干扰。专业术语“限界上下文”可以理解为“每个档口的操作规范和菜品定义”——凉菜档的“黄瓜”是食材,烧烤档的“黄瓜”是烤串,不用统一。
DDD 还把所有业务按重要性分为三类:核心域(核心竞争力所在,如餐厅的秘制酱料)、支撑域(辅助核心域,如采购备货)、通用域(买现成的就行,如财务记账)。这个分类决定了拆分策略的投资优先级,也决定了一个功能该放在内部自研还是外部接入。
老王把“秘制酱料”当成核心域,绝不分出去给别的档口做;把“洗碗”这类通用域直接外包。这就是 DDD 给拆分的第一个指引:先分清轻重,再决定怎么切。
- 业务竞争力评分$\text{竞争力}(D)$ 表示领域 $D$ 对业务的独特贡献程度,像“秘制酱料”对餐厅就是极高分。
- 核心域判定$\text{竞争力}(D) \geq \theta_{\text{core}}$ 时划分为核心域,对应自研且高投入。
- 支撑域判定分数中等则属于支撑域,可以自研或外包,但不必投入顶级资源。
- 通用域兜底分数低的直接采购现成方案,避免在非核心上浪费拆分精力。
拆分粒度控制
老王在朋友圈晒出六个档口的设计图,一位干连锁餐饮的老板评价:“档口太少不够灵活,档口太多管理就崩。”这就是拆分粒度问题。如果只拆成两个档口(“荤菜档”和“素菜档”),那还是个大单体,换个招牌菜要两头改;如果拆成六十个档口,一道凉拌黄瓜要经过洗、切、拌、盘四五个档口,光传菜就累死传菜员。
微服务中每个服务不应是“字典级”的小功能,而应是一个可独立交付的业务单元。判断粒度是否合适,要看功能内聚和团队匹配:一个服务至少应该让一个小团队(2~9 人)能完整负责,同时内部功能的改动能独立发布,不需要跟别的服务协调。服务数量也不是越多越好——服务越多,跨服务的通信和运维成本增长得越快。
老王的六个档口刚刚好:每道菜只需经过 1~2 个档口,团队各自守得住。档口的数量要和团队规模、菜品复杂程度匹配,而不是“越多越专业”。
- 维护成本项$\alpha \cdot n$ 表示 $n$ 个服务带来的部署、监控、日志等固定运维开销,随服务数线性增长。
- 通信连接数$\dfrac{n(n-1)}{2}$ 是 $n$ 个服务两两之间可能建立的调用关系总数。
- 单对沟通成本$\beta$ 表示每一对服务之间因接口变更、联调、故障排查产生的平均成本。
- 成本爆炸点当 $n$ 很大时,$n^2$ 项主导总成本,拆得越碎,协作成本增长越快。
数据拆分策略
改造后厨时,老王给每个档口配了独立的冰箱和调料柜。起初烧烤档的师傅想直接去热炒档的冰箱拿肉,被老王拦住了:“你去拿肉,那边少了一块还不知道,结账全乱。”独立的数据归属,是服务拆分里最容易踩坑的一环。
在微服务架构中,每个服务必须拥有自己的数据库/数据存储,其他服务只能通过接口读写,不能直连他人的库。这保证了服务之间的真正解耦:库存服务半夜升级数据库,不会影响到订单服务。代价则是:原本一个事务内完成的“下单扣库存”,现在变成了跨服务的分布式操作,必须引入最终一致性。
典型做法是用事件或 Saga 模式:订单服务先创建订单并发布“订单已创建”事件,库存服务的消费者收到事件后扣减库存;若失败则通过补偿操作回滚。最终一致性保证所有副本在某个有限时间后收敛到一致状态,而不是要求瞬时的强一致。
老王给每个档口独立配冰箱,表面上“浪费”了空间,实际上让各档口互不拖累。数据独立的代价是“对账”变复杂,但换来的是整个厨房可以并行开火、互不阻塞——这在分布式系统里是值得的取舍。
- 服务数据快照$S_i^{(t)}$ 表示第 $i$ 个服务在时刻 $t$ 的数据状态。
- 另一服务数据快照$S_j^{(t)}$ 表示第 $j$ 个服务在相同时刻的数据状态。
- 收敛极限$\lim_{t \to \infty}$ 表示让时间足够长,所有副本趋于一致。
- 全服务收敛$\forall i,j \in \text{Services}$ 表示这个收敛性质对任意两个服务成立。
通信契约设计
六个档口都独立了,但一道烤鱼需要烧烤档烤好再传给热炒档调味。两个档口之间怎么交接?老王统一印了一批“传菜小票”,上面固定写好:菜品编号、口味要求、出菜时间、温度要求。任何档口只认这张小票,改小票格式必须先通知所有档口。这张小票,就是微服务里的通信契约。
服务间的 API 契约要先于实现定义好,并且要设计版本兼容机制。一个服务的接口升级,不能一次性推翻所有调用方;必须保证旧版本调用方还能正常工作,常用手段包括:新增可选字段、保留旧字段、语义化版本号管理。同时要根据场景选同步还是异步:查库存要立即返回结果,适合同步调用;订单创建后的通知链路,适合异步消息,提高削峰能力。
更关键的是用契约测试(如消费者驱动契约测试)来自动验证:服务提供方的新版本必须满足所有消费方之前的调用期望。好比传菜小票改了字体,不能让老档口不认账——契约测试就是在发新小票之前,先拿所有老档口的人来模拟验一遍。
老王的“传菜小票”就是服务的契约:规格定死了,档口之间才能各自演进。谁想改小票,必须保证老档口按旧规格也能正常出菜——这就是微服务世界里的“旧版本兼容”。
- 旧调用方集合$\mathcal{C}_{\text{old}}$ 表示所有已经依赖旧 API 的调用方(消费者)。
- 新版本行为$\mathcal{A}_{\text{new}}(c)$ 表示新版本 API 对调用 $c$ 的响应。
- 旧版本行为$\mathcal{A}_{\text{old}}(c)$ 表示旧版本 API 对同一调用的响应。
- 全量兼容约束$\forall c$ 要求每个旧调用方在新版本下都获得与旧版本一致的响应,才算兼容。
反模式识别
改造三个月后,老王发现两个档口出了问题。有“聪明”的顾问建议他把洗菜单独分一个档口、切菜再单独立一个档口——菜要经过三次传菜口才能下锅,后厨挤满了传菜员;还有的档口干脆共用一个超大冰箱,甜品想拿个奶油要等热炒的师傅翻完肉。这些就是微服务的反模式。
最典型的反模式是分布式单体:代码层面拆成了很多服务,但业务逻辑还是像单体一样四处远程调用——完成一笔订单要点 10 次跨服务调用,比原来单体还慢。其次是共享数据库:服务独立了但库还共用一张大表,改个字段要通知所有服务一起改,等于没拆。还有无边界过度拆分:为了拆而拆,导致一个简单的 CRUD 也要经过五六个服务,运维成本和故障概率急剧上升。
可以用“分布式单体指数”来量化健康度:每个服务处理一个完整业务请求时,远程调用次数与本地调用次数的比值越高,说明系统的“伪微服务化”越严重。
后厨如果到处是传菜员在喊“借过一下”,那必然出菜慢。微服务也一样:服务之间远程调用过多,说明边界根本没有划对——拆的不是服务,是寂寞。
- 远程调用计数$N_{\text{remote}}$ 表示一次完整业务请求中跨服务远程调用的次数。
- 本地调用计数$N_{\text{local}}$ 表示服务内部本地方法调用次数。
- 比值计算$\dfrac{N_{\text{remote}}}{N_{\text{local}}}$ 体现业务逻辑中有多大部分依赖其他服务。
- 阈值告警$\text{DSI} > \theta$ 时说明系统已落入分布式单体陷阱,需要重新审视边界。
团队组织适配
老王发现一个有趣的现象:后厨隔出六个档口后,师傅们的分工方式也随之固定——每个档口由一个“档口主管”带着 2~3 个师傅全权负责,从备料到出菜一条龙。而档口隔墙怎么砌,也完全跟着师傅们的座位走。这个现象在软件架构里叫康威定律:系统结构会镜像组织的沟通结构。
康威定律是微服务拆分最重要的“社会学”原理:如果团队还按“前端组、后端组、测试组”来组织,那你的微服务很自然就会被拆成“前端服务、后端服务、测试服务”——这是灾难。正确的做法是先调整组织,再设计架构,让每个服务由一支跨职能的自治团队(后端、前端、运维都齐)长期负责。这就是“双披萨团队”:一个团队小到两个披萨就能喂饱,这样沟通成本低、响应快。
同时,一个服务从需求、开发、测试到上线运维必须由同一团队闭环,这就需要DevOps 能力的支撑:自动化 CI/CD、监控告警、日志追踪。档口师傅自己掌握灶台的使用和维护,出现故障自己能快速修复,而不是等“维修部”来。组织结构和架构互相成就,缺一不可。
老王如果不改变师傅们的座次,墙怎么砌都会别扭;团队如果不重组为自治小队,微服务的“服务”再小也运转不灵。架构调整永远要和组织调整同步进行。
- 系统结构$\mathcal{S}_{\text{system}}$ 表示微服务系统的模块划分与依赖关系。
- 组织结构$\mathcal{C}_{\text{org}}$ 表示团队的职责划分与沟通通道。
- 同构关系$\cong$ 表示两者在结构上互为镜像。
- 反推应用想得到理想的系统结构,就要先改革组织沟通结构。
演进路线规划
最后,老王没有推倒老厨房重新装修(那样要停业三个月),而是采用了一个聪明的方法:保留老厨房继续营业,在旁边新搭一个“新档口”来承接新菜单的需求;等新档口稳定了,再把老厨房的菜品一道一道迁移过去,每迁一道就封一道旧菜单。这就是微服务改造的经典模式——绞杀者模式:新系统在旧系统旁边慢慢生长,像藤蔓绞杀宿主树一样逐步替代它。
演进路线还要遵守拆分优先级:优先拆分变更最频繁的模块(改动最多、发布最痛苦的部分),优先拆分弹性需求差异大的模块(大促时只有订单暴涨,支付和库存不需要跟着暴涨)。每完成一次拆分,都要经过灰度迁移:新服务先接一小部分流量,观察监控指标正常后再逐步放量,并且始终保留回滚预案——新服务有问题,一键切回老服务,保证业务不中断。
用覆盖率来度量迁移进度:已迁移到新服务的功能数占总功能数的比例,这个指标应当单调递增,任何一步回退都要有明确的记录和原因。
老王的“边营业边改造”让餐馆每一天都在赚钱,也让新档口每一次上线都有老档口兜底。微服务演进不是一夜重写,而是一场有计划、可回退、灰度可控的长期工程。
- 已迁移功能数$N_{\text{migrated}}$ 表示已经迁移到微服务架构的功能数量。
- 总功能数$N_{\text{total}}$ 表示系统全部功能数量。
- 覆盖率计算$\dfrac{N_{\text{migrated}}}{N_{\text{total}}}$ 得到迁移进度百分比。
- 单调递增约束$N_{\text{migrated}} \nearrow$ 表示迁移进度应当持续推进,回退必须是被记录的风险决策。
AI 应用场景
AI 推理平台的服务边界划分
阶段:AI系统架构设计
解决的问题:一个 AI 推理平台把所有模型推理逻辑塞在一个单体服务里,图像、文本、语音三类模型的负载特征完全不同。图像推理高峰期 GPU 打满,而文本推理平时很闲,单体服务只能一起扩容,浪费大量 GPU 资源——这正是“老王只有一个灶台”的 AI 版。
具体案例:某 AI 平台用 DDD 的限界上下文思路,把推理服务按模型业务域拆分为“图像推理服务”、“文本推理服务”、“语音推理服务”,每个服务独立部署、独立伸缩。图像服务在业务高峰期弹性扩到 20 个副本,文本服务保持 3 个副本即可,GPU 利用率提升了 40%。
电商订单域拆分与数据策略落地
阶段:架构演进与数据架构设计
解决的问题:电商系统的订单、库存、支付原本在同一个数据库里,大促时一个慢查询就能拖垮整条链路。传统方案靠加机器硬扛,治标不治本——本质上是后厨只有一个共享冰箱,谁都在翻。
具体案例:架构团队用 DDD 划出订单/库存/支付三个限界上下文,各自独立数据库;下单链路采用 Saga 模式:先创建订单,发事件扣库存,再发起支付,失败则补偿回滚。最终一致性代替了分布式事务,大促期间订单服务独立扩容,库存抖动不再影响下单。
银行核心系统的绞杀式迁移
阶段:存量系统重构
解决的问题:银行核心系统运行了十几年,绝不能停机重写。传统的“一步到位改造”风险极高,一旦失败就是全行瘫痪——相当于把营业中的餐馆直接砸了重装。
具体案例:项目组采用绞杀者模式,在旧核心旁边新建“客户信息微服务”和“账户微服务”,先接 5% 的查询流量灰度验证,指标平稳后逐步扩大到 100%,每步都有自动化回滚开关。历时一年完成 80% 功能迁移,期间零事故。
Python 演示
class ServiceSplitEvaluator: """服务拆分评估器:检查内聚度、粒度与分布式单体风险""" def __init__(self, services, domain_map): self.services = services self.domain_map = domain_map self._count = 0 def cohesion(self, funcs): if not funcs: return 0.0 domains = [self.domain_map.get(f, "unknown") for f in funcs] main_domain = max(set(domains), key=domains.count) same = sum(1 for d in domains if d == main_domain) self._count += 1 return same / len(domains) def average_cohesion(self): total = sum(self.cohesion(v) for v in self.services.values()) return total / len(self.services) def monolith_index(self, remote, local): return remote / (remote + local) def report(self, remote_calls=None, local_calls=None): print("== 服务拆分评估报告 ==") for svc, funcs in self.services.items(): coh = self.cohesion(funcs) flag = "OK" if coh >= 0.7 else "边界可疑" print(f"[{svc}] 内聚度 {coh:.2f} -> {flag}") avg = self.average_cohesion() print(f"平均内聚度: {avg:.2f}") if avg < 0.7: print("提醒: 存在跨业务域聚集,建议用 DDD 重划限界上下文") elif len(self.services) > 20: print("提醒: 服务数过多,关注拆分粒度是否过细") else: print("总体: 拆分边界健康") if remote_calls is not None and local_calls is not None: dsi = self.monolith_index(remote_calls, local_calls) print(f"分布式单体指数: {dsi:.2f} (阈值0.6)") if dsi > 0.6: print("警告: 跨服务远程调用占比过高,疑似分布式单体") else: print("远程调用占比在可控范围") if __name__ == "__main__": services = { "画像推理服务": ["加载用户画像", "生成推荐结果"], "特征服务": ["实时计算特征", "同步离线特征"], "模型管理服务": ["注册新模型", "发布模型版本"], } domain_map = { "加载用户画像": "画像", "生成推荐结果": "推荐", "实时计算特征": "特征", "同步离线特征": "特征", "注册新模型": "模型", "发布模型版本": "模型", } evaluator = ServiceSplitEvaluator(services, domain_map) evaluator.report(remote_calls=12, local_calls=30)
def cohesion(self, funcs):计算一个服务的内聚度:服务内功能属于同一业务域的比例。main_domain = max(set(domains), key=domains.count)找出出现次数最多的业务域,作为该服务的主域。same / len(domains)主域功能数除以总功能数,比值越接近 1 越好。def monolith_index(self, remote, local):计算远程调用占比,识别分布式单体风险。if avg < 0.7:平均内聚度低于 0.7 时提示重新划分边界。elif len(self.services) > 20:服务数超过 20 提示粒度可能过细。dsi > 0.6远程调用占比超过 0.6 触发反模式警告。
常见误区
误区总以为微服务就是“拆”,服务越小越多就越高级。有人把一个用户管理拆成“注册服务”“登录服务”“资料服务”三个,觉得这才叫微服务。档口多到 60 个,一道菜过 5 个档口,后厨反而瘫痪。
正解拆分粒度要服从业务内聚和团队规模。一个服务应该是一个完整业务能力的承载体,至少能由一个小团队独立维护。通信成本随服务数呈 $O(n^2)$ 增长,拆得越碎,协调成本越高,最终吞噬拆分带来的收益。
为何常见:人们容易把“微”字理解成“小”,却忘了它的本意是“服务粒度恰好匹配业务边界”——就像档口恰好匹配菜品结构,而不是越碎越好。
误区拆服务会带来分布式事务的麻烦,于是很多人把服务拆了但数据库还是那一张总表。理由是“查询方便,反正都是自己的系统”。老王让烧烤档和甜品档共用一个冰箱,结果互相翻乱。
正解共享数据库是典型的拆分反模式。所有服务读写同一张表,意味着任何一处 schema 变更都要所有服务同步修改,服务之间的耦合比单体时代还紧。正确做法是每个服务独立库,通过事件最终一致性解决跨服务数据需求。
为何常见:因为避免分布式事务的“短期舒适”太诱人,很多人不愿面对数据一致性设计的长远成本,结果把服务拆了等于没拆。
误区很多人觉得 DDD 太“重”,先按感觉把服务拆出来,等运行一段时间再调整边界。结果拆出十几个服务后,发现调用链乱成一团,改边界要动十几个服务,比不拆还痛苦。
正解边界是微服务的地基,地基歪了房子必然歪。DDD 的限界上下文和聚合分析看起来花费时间,但它能帮你在拆之前就画出清晰的边界。前期花一天画领域图,胜过后期花一个月重构服务边界。
为何常见:工程师天然喜欢“动手”多于“设计”。但微服务拆分恰恰是“设计先行”的工程,跳过设计就像不画图纸就砌墙。
误区服务一拆,原来的本地方法调用变成了 RPC。有人觉得“分布式系统嘛,网络延迟肯定大,这是正常的”,于是接受一个下单请求要串行调用 10 次远程服务的现状。
正解高延迟如果源于物理网络,那是客观限制;但如果是因为边界没划好、业务逻辑被切得过碎,那就是分布式单体陷阱。正确做法是减少跨服务调用次数,通过聚合、缓存、异步化和重新划分边界来优化链路,而不是被动忍受。
为何常见:把“分布式系统有延迟”当成万能挡箭牌,掩盖了服务边界设计失误——就像后厨师傅抱怨“传菜太远”,却不反思为什么要洗切炒分三个档口。
误区架构师画完微服务架构图,认为任务就完成了。但后端组、前端组、运维组的组织结构纹丝不动,微服务的每个“服务”要协调三个部门才能上线,比单体时代还慢。
正解康威定律决定了系统结构会镜像组织沟通结构。不改组织就谈微服务,架构只会被组织结构重新“掰回”单体。必须组建跨职能自治团队,让每个服务由一个“双披萨团队”全栈负责,才能真正落地。
为何常见:组织调整属于管理动作,工程师习惯性回避“人的问题”,只盯“技术问题”——但微服务最大的阻力往往不在代码里,而在组织架构里。
面试题
Q1. 微服务拆分最核心的边界依据是什么?
- A.代码文件的目录结构
- B.业务能力与限界上下文← 正确答案
- C.数据库的物理表数量
- D.团队人数的多寡
答案:B。微服务应围绕业务域(限界上下文)划分边界,就像老王按“菜系”而不是按“调料位置”分档口。代码目录、表数量都是技术细节,不应该是划分依据;团队人数会影响粒度但也不是边界依据。
Q2. “限界上下文”这一概念来自哪种设计方法?
- A.领域驱动设计← 正确答案
- B.敏捷开发管理
- C.持续集成实践
- D.测试驱动开发
答案:A。限界上下文是领域驱动设计(DDD)的核心概念,用来划定业务概念的有效边界。它就像“每个档口的菜品定义和操作规范”,其他三种方法论都与这个概念无关。
Q3. 以下哪个现象最可能说明系统落入了“分布式单体”陷阱?
- A.服务总数超过一百个
- B.完成一笔业务要十余次跨服务调用← 正确答案
- C.使用了消息队列通信
- D.每个服务有独立数据库
答案:B。分布式单体指“拆了服务但逻辑还是单体”,典型特征是一个业务事务需要大量远程调用。服务多不等于陷阱,消息队列和独立数据库反而是健康信号。
Q4. 共享数据库对微服务最大的影响是什么?
- A.服务器磁盘占用增加
- B.Schema 变更需所有服务协同← 正确答案
- C.数据库备份时间变长
- D.单表数据总量变大
答案:B。共享数据库让所有服务读写同一批表,任何表结构变化都要所有相关服务同步修改,服务之间形成比单体时代更紧的耦合。磁盘、备份、数据量都是次要的工程问题。
Q5. 康威定律的核心含义是什么?
- A.组织沟通结构决定系统架构形态← 正确答案
- B.技术栈选型决定了架构走向
- C.用户使用习惯塑造了服务边界
- D.网络带宽限制了系统规模
答案:A。康威定律指出系统结构镜像组织的沟通结构。想让系统变成微服务,先要让团队变成自治小分队,不然架构会被组织“拉回”单体。技术选型、用户习惯、带宽都不是定律内容。
Q6. 随着服务数量持续增加,拆分的总体收益曲线通常是怎样的?
- A.持续线性上升
- B.先升后降存在峰值← 正确答案
- C.单调持续下降
- D.与数量无关
答案:B。拆分初期独立部署和伸缩带来收益,但服务多了之后通信成本按 $O(n^2)$ 增长,收益被吞噬,曲线先升后降。这也是为什么粒度控制如此重要——要找到曲线峰值的“最优区间”。
Q7. 绞杀者模式的核心思想是什么?
- A.一次性重写整个系统再替换
- B.新系统渐进生长逐步替代旧系统← 正确答案
- C.把旧系统的代码全部删掉重写
- D.对旧系统只维护不扩展
答案:B。绞杀者模式让新服务在旧系统旁边生长,逐步把功能从旧系统迁移出来,每迁一块就封掉旧的一块。它避免了“重写式”改造的高风险,老王边营业边改造就是这个道理。
Q8. 在 DDD 中,“防腐层”的主要职责是什么?
- A.防止外部系统的模型污染本地领域模型← 正确答案
- B.阻止所有外部网络请求进入服务
- C.对服务间传输的数据进行加密
- D.防止数据库在高并发下发生死锁
答案:A。防腐层(ACL)是上下游限界上下文之间的翻译层,负责把外部系统的概念转换成本地模型,避免外部语义污染内部核心领域。它不管网络拦截、数据加密和数据库锁,只做“语义隔离”。
Q9. 以下哪些特征适合将一个模块拆分为独立服务?
- A.存在独立弹性伸缩的需求← 正确答案
- B.团队规模足够自治← 正确答案
- C.代码行数已经超过一万
- D.与其他模块强耦合且不可分割
答案:AB。独立伸缩和团队自治是拆分的两个经典理由。代码行数多不是拆分依据;与其他模块强耦合时强行拆分反而制造分布式单体,应先理清边界再拆。
Q10. 以下哪些属于微服务拆分的反模式?
- A.分布式单体仍然大量远程调用← 正确答案
- B.多个服务共享同一个数据库← 正确答案
- C.无边界地过度拆分服务← 正确答案
- D.使用异步消息实现最终一致性
答案:ABC。分布式单体、共享数据库、无边界过度拆分都是典型反模式。异步消息和最终一致性是解决跨服务数据的健康手段,不属于反模式。