你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

进化型设计

进化型设计是持续创新的关键

无论是修复 bug、添加新功能、引入新技术,还是使现有系统更具伸缩性和弹性,所有成功的应用程序都在随着时间而不断变化。 如果应用程序的所有部分都紧密耦合,则很难将更改引入系统。 应用程序中一个部分的更改可能会破坏另一部分,或者改变整个代码库。

这个问题并不局限于单片应用程序。 应用程序可分解为服务,但仍会表现出那种紧密耦合性,使系统变得刚性和脆弱。 但当服务设计为可以改进时,团队可以创新并不断提供新功能。

微服务正在成为实现进化设计的一种热门方式,因为它们可以解决此处列出的许多值得注意的问题。

建议

强制执行高度内聚和松散耦合。 如果服务提供逻辑上具有共同所属的功能,则该服务具有内聚性。 如果可以在更改一个服务的同时不会更改另一个服务,则服务具有松散耦合性。 高度内聚通常意味着更改一个函数时还需更改其他相关函数,其中的所有相关函数都驻留在一个服务中。 如果发现更新某个服务时需要对其他服务进行协调更新,则可能表示该服务不具有内聚性。 域驱动设计 (DDD) 的目标之一就是标识这些边界。

封装域知识。 客户端使用服务时,强制执行域的业务规则的责任不应落在客户端上。 相反,服务应封装属于其责任范围内的所有域知识。 否则,每个客户端都必须强制执行业务规则,最终域知识会分散在应用程序的不同部分。

使用异步消息传递。 异步消息传递是一种将消息创建者与使用者分离的方法。 创建者不依赖于使用者回复消息或采取任何特定操作。 有了 pub/sub 体系结构,创建者甚至可能不知道谁在使用消息。 新服务可以轻松地使用消息,而不需要对创建者进行任何修改。

不要将域知识构建到网关中。 在微服务体系结构中,网关对于请求路由、协议转换、负载均衡或身份验证等操作非常有用。 但网关应该仅限于这种基础结构功能。 它不应实施任何域知识,以避免成为严重的依赖项。

公开开放接口。 避免在服务之间创建自定义转换层。 相反,服务应该公开具有明确定义的 API 协定的 API。 API 应拥有版本控制,以便在保持向后兼容性的同时改进 API。 这样就可以更新服务,而无需对依赖它的所有上游服务进行协调更新。 面向公众的服务应通过 HTTP 公开一个 RESTful API。 因性能原因,后端服务可能会使用 RPC 样式的消息传递协议。

针对服务协定进行设计和测试。 在服务公开了明确定义的 API 后,可以针对这些 API 进行开发和测试。 这样可以开发和测试单个服务,而无需启动所有的依赖服务。 (当然,仍然可以针对实际服务执行集成和负载测试。)

使用适应度函数。 适应度函数可测量结果,以查看是离最佳解决方案更近还是更远。 适应度函数有助于在随着时间推移发生更改时保护体系结构特征。 适应度函数是指任何提供体系结构特征客观完整性评估的机制。 评估可能包括各种机制,例如指标、单元测试、混沌工程等。 例如,架构师可能会将页面加载时间标识为重要特征。 随后,工作负荷应使用适应度函数来测试页面加载时间,并在持续集成过程中运行测试。

分清基础结构与域逻辑。 不要将域逻辑与基础结构相关的功能(如消息传递或暂留)混在一起。 否则,更改域逻辑时需要对基础结构层进行更新,反之亦然。

将跨领域问题转移到单独服务上。 例如,如果多个服务需要对请求进行身份验证,可将此功能移到各自的服务中。 然后便可改进身份验证服务(例如,通过添加新的身份验证流),而无需涉及使用它的任何服务。

独立部署服务。 DevOps 团队可以独立地为应用程序中的其他服务部署单个服务时,更新就会更快,更安全。 Bug 修复和新功能便能按更常规的节奏推出。 同时设计应用程序和发布过程以支持独立更新。