分布式与架构反模式与 Microsoft Cloud Antipatterns

共 20 题
📑 题目列表 20 题
#
★★★

1. Dead End 在引入难以替换的技术栈的后果。

请说明 Dead End(死胡同)反模式在引入难以替换的技术栈时的后果?

  • Dead End 反模式定义
  • 技术栈锁定
  • 后果

Dead End(死胡同)反模式指:在一个不可替换的技术栈上投入大量开发,导致后期无法在合理成本内迁移到更好的方案。典型场景:公司采用了某个生态虽好但封闭/专用/维护不善的技术栈,投入大量代码后想替换时发现成本极高(所有代码、工具、人员都绑定该技术栈),形成"死胡同"。后果:替换成本巨大的技术栈被锁定,无法适应需求变化;新特性无法接入、性能受限没有出路;人才与生态萎缩;创新与选型被拖累。规避方法:评估技术栈的可替换性、避免过度依赖封闭/专属技术、为关键组件预留适配层(抽象接口)、控制技术债、定期评估技术栈健康度。识别信号:某个技术栈投入巨大、无法替换、维护乏力、生态停滞。

Dead End 的核心是"技术栈不可替换"导致的高昂迁移成本。规避在于可替换性评估与抽象预留,避免把架构押在死胡同技术栈上。

#
★★★

2. Monolithic Persistence 在关系数据库承担队列、文档、图、时序的滥用。

请说明 Monolithic Persistence(单体持久化)反模式在关系数据库承担队列、文档、图、时序等职责时的滥用?

  • Monolithic Persistence 反模式
  • 关系数据库滥用
  • 问题与改进

Monolithic Persistence 反模式指:用一个数据库(通常是关系数据库)承担所有数据存储职责,包括队列、文档、图、时序、缓存、搜索索引等本应使用专门存储的场景。关系数据库被用来既存业务数据,又存队列消息、文档、图、时序数据、缓存等,导致:数据库承担大量不适合的负载(时序高吞吐、图遍历、文档 JSON、队列)、性能差、冲突多、schema 僵化、难以扩展。改进:polyglot persistence(多语言持久化)——按数据形态选择合适存储:队列用消息队列(Kafka/RabbitMQ)、文档用文档库(MongoDB)、图用图库(Neo4j)、时序用时序库(InfluxDB)、缓存用 Redis、搜索用 ES、关系数据用关系库。避免"一个库装所有"。

Monolithic Persistence 是"一个数据库装所有数据形态"的反模式,违背"合适的存储做合适的事"。改进是多语言持久化,按数据特征选存储,避免关系库承载队列/时序/图等不适合的负载。

#
★★

3. Cargo Cult 在不理解原理下照搬实践的工程问题。

请说明 Cargo Cult(货船崇拜)反模式在不理解原理下照搬实践的工程问题?

  • Cargo Cult 定义
  • 照搬实践的问题
  • 后果

Cargo Cult(货船崇拜)源自"仪式崇拜"——照搬表面形式但不懂原理。工程中的 Cargo Cult 指:团队不理解某实践/技术/框架的原理,只是听说"别人这么做"就照搬,形式正确但实质缺失。例如:照搬别人的微服务拆分、照搬某框架配置、照搬某项目结构,但不知为何如此,导致"用错了地方"或"功能不全"。问题:照搬的实践可能不适合当前场景(规模、技术栈、团队);不懂原理无法正确调整与排错;形式主义掩盖真实问题;引入不必要复杂度。解决:理解实践背后的原理与适用条件,按需裁剪,避免盲目照搬;以"为什么"驱动,而非"别人怎么做"。

Cargo Cult 是"照搬形式不懂原理",导致实践不适用、无法因地制宜。规避核心是理解原理与适用场景,避免形式主义。

#
★★

4. Chatty I/O 在远程调用过细粒度的网络往返。

请说明 Chatty I/O(啰嗦 I/O)反模式在远程调用过细粒度网络往返上的问题?

  • Chatty I/O 定义
  • 细粒度远程调用
  • 问题与改进

Chatty I/O(啰嗦 I/O)反模式指:客户端/服务用大量细粒度的远程调用获取数据,每个调用只返回少量数据,导致大量网络往返(round trips),网络开销与延迟被放大。表现:客户端逐字段/逐条调用(如先取用户再取用户地址再取用户订单),或一个聚合需要十几次远程调用。问题:网络往返引入延迟与开销(每个 RTT 都有成本)、吞吐下降、前端等待时间长、增加故障点。改进:批量/聚合调用(Aggregator/BFF 把多个调用合并为一个)、GraphQL 按需取数、接口返回更完整的数据(粗粒度)、减少往返、用缓存。核心是"减少远程往返次数与粒度"。

Chatty I/O 是"细粒度远程调用过多往返",放大了网络延迟与开销。改进靠聚合、批量化、粗粒度接口(BFF/Aggregator/GraphQL)减少往返。

#
★★

5. Extraneous Fetching 在 SELECT * 或一次性读取不必要数据的工程影响。

请说明 Extraneous Fetching(多余获取)反模式在 SELECT * 或一次性读取不必要数据时的工程影响?

  • Extraneous Fetching 定义
  • SELECT * 问题
  • 工程影响

Extraneous Fetching(多余获取)反模式指:查询一次性读取了多余/不必要的数据(如 SELECT * 读取所有列,或拉取整表、整条记录但只用一个字段),导致数据库与网络传输大量无用数据。工程影响:IO 与带宽浪费(传输大字段、大对象)、内存占用增加、数据库负载上升(全列扫描、全表读取)、缓存命中率下降、响应变慢。改进:只 SELECT 需要的列(投影)、分页/按需取数、避免 SELECT *、减少不必要的关联与全表查询、对大字段(BLOB/JSON)延迟加载。核心是"只取所需,避免读取不必要数据"。

Extraneous Fetching 是"读取了用不到的数据",浪费 IO、带宽、内存与数据库负载。改进是投影(只取所需列)、分页、避免 SELECT * 与大字段全量读取。

#
★★

6. Improper Instantiation of Instances 在 new 操作在频繁路径上的 GC 压力。

请说明 Improper Instantiation of Instances(不当实例化)反模式在 new 操作频繁路径上的 GC 压力?

  • Improper Instantiation 反模式
  • new 操作与 GC 压力
  • 改进

Improper Instantiation of Instances 反模式指:在频繁执行的热路径(high-frequency path)上反复 new 创建对象,导致大量对象被创建与回收,增加 GC 压力(Young GC 频繁、分配开销、停顿),降低性能。表现:在循环/每个请求/每个消息处理中 new 大型对象、临时对象、连接、线程,对象生命周期短但数量巨大。工程影响:GC 频繁(分配/回收)、停顿、CPU 开销、吞吐下降。改进:对象池/复用(复用连接、线程池、缓冲)、避免在热路径创建大对象、使用不可变与栈复用、减少临时对象、合理设置 GC 与对象生命周期。核心是"避免在热路径高频实例化不必要对象"。

热路径上的 new 会产生大量短命对象,加剧 GC。改进是对象复用(池化)、减少临时对象、避免在循环/热路径创建大对象,降低 GC 压力。

#
★★

7. Lava Flow 在遗留系统死代码无法删除的反模式。

请说明 Lava Flow(熔岩流)反模式在遗留系统死代码无法删除的场景?

  • Lava Flow 定义
  • 死代码累积
  • 问题与处理

Lava Flow(熔岩流)反模式指:遗留系统中积累了大量无法删除、无人理解、不敢删除的代码(死亡代码、死分支、废弃模块、历史遗留 hack),就像冷却的熔岩流堆积在系统里。成因:项目快速迭代、人员流动、遗留代码无人维护、删除风险高(担心破坏其他功能)。问题:代码体积膨胀、可维护性差、新人不理解、bug 隐藏在死代码中、重构成本高。处理:识别死亡代码(通过覆盖率、调用分析、运行日志)、渐进式清理、用版本控制保障删除安全、重构与文档化、避免"害怕删除"的文化。识别信号:大量未使用的类/方法/分支、无人知的配置、注释掉的代码。

Lava Flow 是"死代码堆积、无人敢删"的反模式,源于迭代与人员流动。治理靠识别(覆盖率/调用分析)、安全删除(版本控制)、重构与文档。

#
★★

8. Retry Storm 在失败时所有客户端同时重试的反模式。

请说明 Retry Storm(重试风暴)反模式在失败时所有客户端同时重试的场景?

  • Retry Storm 定义
  • 同时重试
  • 后果与避免

Retry Storm(重试风暴)反模式指:当服务/依赖发生故障时,所有客户端在同一时刻对同一请求进行重试,形成对下游的请求风暴,放大故障、压垮系统。成因:客户端都配置了相同的重试策略(同样间隔、同样次数),故障发生后所有客户端同时重试,下游被海量重试请求淹没,故障扩大。后果:把所有重试请求叠加到故障的下游,造成雪崩、级联故障、资源耗尽。避免:重试使用指数退避 + 抖动(jitter)错开重试时刻;限制最大重试次数;配合熔断(失败率高时停止重试);限流;在分布式/多客户端场景用随机化重试分散压力。核心是"随机化重试时刻,避免所有客户端同时重试"。

Retry Storm 是"所有客户端同时重试"放大故障,源于相同的重试策略。避免靠指数退避 + 抖动错开、限制重试次数、熔断兜底。

#
★★

9. Spaghetti Code 在 goto、回调地狱、Promise 嵌套的代码可读性。

请说明 Spaghetti Code(意大利面代码)反模式在 goto、回调地狱、Promise 嵌套时的代码可读性问题?

  • Spaghetti Code 定义
  • 回调地狱/Promise 嵌套
  • 可读性

Spaghetti Code(意大利面代码)反模式指:代码控制流混乱、结构杂乱,像一盘意大利面一样纠缠不清,难以阅读、维护与修改。表现:goto 滥用(旧语言)、回调地狱(callback hell,多层嵌套回调)、Promise 嵌套过深、全局变量滥用、无清晰分层、散落的业务逻辑。问题:可读性差(难以理解控制流)、可维护性差(改动影响面大)、bug 多、测试难。改进:用清晰的控制流(async/await、结构化、事件驱动)、分层/模块化、单一职责、避免深嵌套、用状态机/编排替代混乱的分支、提高内聚降低耦合。核心是"结构化、可读的控制流与清晰分层"。

Spaghetti Code 是"控制流混乱、无结构",由 goto、回调地狱、深层嵌套等造成。改进是结构化控制流(async/await)、分层、模块化、低耦合高内聚。

#
★★

10. Vendor Lock-In 在过度依赖云厂商专有服务的迁移代价。

请说明 Vendor Lock-In(供应商锁定)反模式在过度依赖云厂商专有服务时的迁移代价?

  • Vendor Lock-In 定义
  • 云厂商专有服务
  • 迁移代价

Vendor Lock-In(供应商锁定)反模式指:过度依赖某个云厂商/供应商的专有服务与特性,导致迁移到其他厂商时代价巨大。表现:用云厂商专有服务(专有数据库、专有消息队列、专有对象存储、专有 AI 服务)替代通用/开源方案,代码、配置、数据、运维都与厂商绑定;厂商 API、数据格式、运维能力不可移植。迁移代价:重写代码与接口(适配厂商 API)、数据搬迁(格式/迁移链路)、运维技能与工具重构、成本与风险。避免:采用开源/标准技术(Kubernetes、Kafka、PostgreSQL、标准 REST)、为关键服务抽象适配层(防厂商绑定)、评估可移植性、考虑多云/混合、控制专有服务使用范围。核心是"避免被单一厂商专有服务锁定,预留可移植性"。

Vendor Lock-In 是"过度依赖厂商专有服务导致迁移代价高"。规避靠标准/开源技术、抽象层、可移植性评估,避免把架构押在厂商锁定上。

#

11. Improper Cache Sizing 在缓存过小(频繁失效)与过大(浪费资源)的工程取舍。

请说明 Improper Cache Sizing(不当缓存容量)反模式在缓存过小(频繁失效)与过大(浪费资源)下的工程取舍?

  • Improper Cache Sizing 定义
  • 过小与过大
  • 取舍

Improper Cache Sizing(不当缓存容量)反模式指:缓存容量设置不当,过大或过小都带来问题。缓存过小:缓存命中率低,大量数据被频繁淘汰(频繁失效),导致频繁回源数据库,DB 压力大、命中率低、性能未充分发挥。缓存过大:占用过多内存/资源,浪费资源、成本高,甚至因内存不足影响其他功能。工程取舍:缓存容量要在"命中率"与"资源成本"间平衡——根据访问分布(热点数据占比)、数据量、可接受的回源率、资源预算来确定容量;用监控(命中率、淘汰率、内存)调整;对热点数据重点缓存、冷数据不缓存。核心是"按访问分布与资源预算平衡缓存容量,避免过小频繁失效或过大浪费"。

缓存容量是"命中率 vs 资源成本"的权衡。过小命中率低、频繁回源,过大浪费资源。需按热点分布、数据量与预算监控调优。

#

12. Synchronous I/O 在同步阻塞 I/O 在高并发请求下的线程池耗尽。

请说明 Synchronous I/O 反模式在同步阻塞 I/O 在高并发请求下导致线程池耗尽的问题?

  • Synchronous I/O 反模式
  • 阻塞 I/O
  • 线程池耗尽

Synchronous I/O(同步阻塞 I/O)反模式指:用同步阻塞的方式处理 I/O(数据库、HTTP、磁盘、网络),在高并发下每个请求占用一个线程并阻塞等待 I/O,导致线程池被大量阻塞线程耗尽。问题:线程数有限,高并发下大量线程阻塞在 I/O 等待,线程池耗尽,新请求无法处理,吞吐下降、延迟增高、服务不可用。改进:异步 I/O(异步/非阻塞,如 Netty、CompletableFuture、异步 JDBC)、线程池合理配置、连接池复用、减少阻塞点、用异步/响应式模型处理高并发 I/O。核心是"避免每个请求阻塞占用线程,用异步非阻塞提升并发"。

同步阻塞 I/O 在高并发下让线程阻塞等待,导致线程池耗尽。改进是异步/非阻塞 I/O、连接池与线程池合理配置,减少线程阻塞。

#

13. Accumulated 技术债在交付压力下的不可逆债务。

请说明 Accumulated(累积)技术债在交付压力下形成的不可逆债务?

  • 技术债累积
  • 交付压力
  • 后果

Accumulated 技术债反模式指:在持续交付压力下,团队不断用临时方案、快捷实现、跳过重构与测试来赶进度,技术债(坏味道、重复代码、无测试、错误设计)不断累积,形成"不可逆的债务"。问题:代码质量恶化、维护成本上升、交付速度越来越慢、隐患累积、最终债务"利息"(修复成本、bug、重构)超过本金,几乎不可逆。技术债并非都不可取(有意的技术债可接受),但不可控累积的债务会拖垮系统。管理:识别并登记技术债、为债务设上限、定期偿还(重构/补测试)、用质量门禁(测试、覆盖率、评审)控制新增债务、在交付压力下坚持必要质量。核心是"控制技术债累积,避免不可逆债务"。

Accumulated 技术债是"交付压力下债务累积不可逆"。管理靠识别登记、设定上限、定期偿还、质量门禁,避免债务失控。

#

14. Big Ball of Mud 在无结构、随意生长系统的识别。

请说明 Big Ball of Mud(大泥球)反模式在无结构、随意生长系统中的识别?

  • Big Ball of Mud 定义
  • 无结构系统特征
  • 识别

Big Ball of Mud(大泥球)反模式指:系统没有清晰的结构,随意生长、无边界、无分层,像一团泥球一样纠缠在一起。识别信号:无清晰分层/模块、依赖混乱(循环依赖、任意引用)、代码无边界、数据与逻辑纠缠、难以理解与维护、随意添加功能、技术栈混杂。成因:缺乏架构设计、快速迭代、人员流动、无约束生长。问题:可维护性极差、修改影响面大、bug 多、测试难、无法演进。改进:重构为清晰分层(分层/模块化/微服务)、界定边界、控制依赖、引入架构治理、逐步重构(Strangler Fig)。核心是"识别无结构、无边界、随意生长的系统,并渐进重构"。

Big Ball of Mud 是"无结构、无边界、随意生长"的系统。识别靠依赖混乱、无分层、无边界等信号;改进靠分层、模块化、边界与重构。

#

15. Busy Frontend 在前端加载所有数据、阻塞渲染的反模式。

请说明 Busy Frontend(忙碌前端)反模式在前端加载所有数据、阻塞渲染的问题?

  • Busy Frontend 定义
  • 前端加载所有数据
  • 阻塞渲染

Busy Frontend(忙碌前端)反模式指:前端承担了过多的数据加载与处理逻辑,一次性加载所有数据(全量数据、大响应),并在渲染前做大量同步处理,导致页面阻塞、响应慢、体验差。表现:前端加载所有数据再本地过滤/排序、渲染前同步等待大量数据、前端做复杂业务逻辑、大体积 JS 阻塞渲染。问题:首屏慢、渲染阻塞、流量大、前端逻辑复杂难维护、后端能力未充分利用。改进:后端聚合/投影(BFF/后端返回所需数据)、分页/按需加载、懒加载、异步加载、前端只做展示与轻交互、把业务逻辑放后端。核心是"减少前端全量加载与阻塞渲染,后端承担数据加工"。

Busy Frontend 是"前端加载所有数据并阻塞渲染"。改进靠后端聚合裁剪、分页/懒加载、异步加载,把数据处理放后端。

#

16. Distributed Monolith 在表面微服务但内部强耦合的反模式。

请说明 Distributed Monolith(分布式单体)反模式在表面微服务但内部强耦合的场景?

  • Distributed Monolith 定义
  • 表面微服务内部耦合
  • 问题

Distributed Monolith(分布式单体)反模式指:表面上按微服务拆分了多个服务,但内部依然强耦合(共享数据库、同步强依赖、共享逻辑、直接调用),实际仍是"单体"的分布式版本,只是把单体拆成了多个强耦合的部署单元。特征:多个服务共享数据库(Shared Database)、服务间通过同步调用强耦合、共享领域模型/代码、部署仍要一起发布、一个服务变更影响其他服务。问题:既没有微服务的独立开发/部署/扩展优势,又增加了分布式系统复杂度(网络、分布式事务、调试),是"双输"。改进:真正的服务边界(每个服务独立数据)、遵循微服务原则(独立部署、独立扩展、去共享)、控制服务间耦合、用事件/异步解耦。核心是"避免表面拆分、实则强耦合的分布式单体"。

Distributed Monolith 是"表面微服务、内部强耦合",既无微服务优势又增分布式复杂度。改进是真正独立数据与部署边界、降低耦合。

#

17. Mega Service 在过度聚合的微服务(反向微服务)。

请说明 Mega Service(巨型服务)反模式在过度聚合的微服务(反向微服务)场景?

  • Mega Service 定义
  • 过度聚合
  • 问题

Mega Service(巨型服务)反模式指:把过多职责/功能聚合到一个糟糕的微服务里,形成"反向微服务"——名义上是微服务,实际容量巨大、职责过多、难以独立演进与扩展。表现:一个服务承载多个业务域、横切功能混杂、代码量巨大、依赖众多、职责单一原则被破坏。问题:超出微服务"小而独立"的初衷,难以独立开发/部署/扩展,成为新的单体点,故障面大,团队协作困难。改进:按业务域/子域重新拆分(领域驱动设计)、遵循单一职责、控制服务职责边界、监测服务规模。核心是"避免服务过度聚合、职责过多"。

Mega Service 是"过度聚合的微服务",职责多、规模大,违背微服务独立演进原则。改进是按业务域拆分、单一职责。

#

18. NIH(Not Invented Here)在拒绝使用成熟库的工程问题。

请说明 NIH(Not Invented Here,非我发明)反模式在拒绝使用成熟库时的工程问题?

  • NIH 定义
  • 拒绝成熟库
  • 问题

NIH(Not Invented Here,非我发明)反模式指:团队基于"自己造轮子"的偏好,拒绝使用成熟、可靠的第三方库/框架,坚持自己实现,导致重复造轮子。表现:拒绝成熟的库/框架(日志、缓存、序列化、消息、算法),自己实现一遍,往往质量差、维护成本高、功能不全。问题:重复造轮子浪费资源、自研实现质量与可靠性不如成熟库、维护成本高、隐藏 bug 与安全风险、增加技术债。改进:优先评估/采用成熟库(只要满足需求、成熟、可维护)、避免盲目自研、对差异化需求再自研、控制"非我发明"倾向。核心是"用成熟库,避免重复造轮子"。

NIH 是"拒绝成熟库、自己造轮子",浪费资源、质量差、维护成本高。改进是优先采用成熟可靠的库,避免盲目自研。

#

19. No Caching 在重复读相同数据的性能浪费。

请说明 No Caching(无缓存)反模式在重复读相同数据时的性能浪费?

  • No Caching 定义
  • 重复读相同数据
  • 性能浪费

No Caching(无缓存)反模式指:系统完全没有使用缓存,每次请求都重复读取相同的数据(读数据库/远程),导致大量重复计算与 IO,性能浪费。表现:热点数据(配置、用户、商品、字典)每次请求都查库,数据库压力大、响应慢、浪费计算。问题:重复读相同数据造成 DB 负载、延迟、吞吐下降。改进:对热点/只读/变化不频繁的数据加缓存(本地缓存 + 分布式缓存,如 Redis),设计缓存策略(TTL、失效、预热),配合缓存穿透/击穿/雪崩防护。核心是"对重复读的数据加缓存,避免重复 IO"。

No Caching 是"不缓存重复读的数据",造成 DB 压力与延迟。改进是引入合理缓存(本地 + 分布式)与失效策略,减少重复 IO。

#

20. No-Fault Tolerance 在无重试、熔断、降级的单点故障设计。

请说明 No-Fault Tolerance(无容错)反模式在无重试、熔断、降级的单点故障设计中的问题?

  • No-Fault Tolerance 定义
  • 无重试/熔断/降级
  • 单点故障

No-Fault Tolerance(无容错)反模式指:系统没有容错机制(无重试、无熔断、无降级、无超时、无隔离),任何依赖故障都会直接导致整个系统失败,且无单点冗余,形成单点故障。表现:依赖失败直接报错、无超时(无限阻塞)、无重试、无熔断、无降级兜底、无冗余副本。问题:一个组件故障即导致系统不可用、故障扩大、无恢复能力、稳定性差。改进:引入容错机制——超时、重试(退避+抖动)、熔断、降级/兜底、限流、隔离(bulkhead)、冗余/多副本、健康检查与自愈。核心是"为系统设计容错与冗余,避免单点故障导致整体不可用"。

No-Fault Tolerance 是"无容错、无冗余",单点故障导致整体失败。改进是超时、重试、熔断、降级、隔离、冗余多副本等容错机制。