微服务设计原则

微服务设计以服务识别出的服务目录为基础,针对服务粒度、依赖组合关系做合理调整(更新服务目录和服务关联),并对服务接口(输入/输出异常)、服务应用分组以及部署方式,采用契约先行的方式并更好地支持可伸缩高可用(如无状态原则),为目标做进一步的设计,同时在性能、管控、安全等非功能性需求方面对接下来的服务实现阶段提出明确的要求(服务定义)。

在服务设计阶段,针对服务模型(服务目录+服务关联+服务定义)的设计是自上而下、由粗到细的,微服务设计有以下一些参考原则。

服务化松耦合原则
  • 实现的松耦合:即服务消费端不需要依赖服务契约的某个特定实现,这样服务提供端的内部变更就不会影响消费端,而且消费端未来还可以自由切换到该契约的其他提供端。
  • 时间的松耦合:典型的是异步消息队列系统,因为有中介者(broker),所以生产者和消费者不必在同一时间都保持可用性及相同的吞吐量,而且生产者也不需要立即得到回复。
  • 位置的松耦合:典型的是服务注册中心,消费端完全不需要直接知道提供端的具体位 置,而通过服务注册中心来查找服务提供端的地址来访问。服务提供端应用扩容时,也由服务注册中心实时通知消费端新的服务地址。
  • 版本的松耦合:消费端不需要依赖服务契约的某个特定版本来工作,这就要求服务的契约在升级时尽可能地提供向下兼容性。
服务依赖原则
  • 业务层:对依赖的聚焦迫使我们将流程合理化并进行精简。业务流程需要能够追溯到组织机构的愿景、组织的任务和为执行组织机构战略所需的广泛功能(产品管理、工程、市场、销售等)。
  • 应用层:需要更加静态地对操作进行分组,那些属于一类的操作应该归到一起,并且在不同的系统间仅保留低限度的联系。
  • 数据层:任何系统的“内部”数据模型又被称为“领域数据模型”,它们将永远不会对其他系统可见。与之相对应,系统的“外部”数据模型被称为“接口数据模型”,它们永远对外暴露并与其他系统分享。要区分好内外部数据模型。
  • 技术层:服务之间的交互依赖面向接口以及契约,而非具体的实现。为了降低系统之间的耦合性,应尽可能减少直接依赖(如同步服务调用),更多地采用间接依赖(如异步消息)。
服务设计原则
  • 优化远程调用:分析服务调用场景,选择较优的调用模式。多路复用TCP长连接,多服务复用TCP长连接,以减少TCP建立连接的时间消耗并减少服务器的端口占用。
  • 消除冗余数据:尽量避免留有当前业务用例不需要的冗余字段,从而减小序列化和传输的开销。
  • 粗粒度契约:在保证一定复用性的前提下,尽可能提供完整业务含义的服务粒度。
  • 通用契约:为了支持不同语言和平台的客户端,服务契约中不能出现某些语言独有的高级特性,参数和返回值也必须是被广泛支持的较简单的数据类型。
  • 隔离变化:隔离内外系统,把内部系统变化对外部的冲击减少到较小的程度。
  • 契约先行:详细规定双方合作的内容、合作的形式等,对双方形成强有力的约束和保障。
  • 稳定和兼容的契约:由于用户范围的广泛性,在公开发布之后就要保证相当的稳定性,不能随便被重构,即使升级也要考虑尽可能地向下兼容。
服务命名原则

建议使用服务使用者专业领域内有意义的名称,优先选用业务概念,而不是技术概念。应使用名词对服务进行命名,使用动词对操作进行命名。

服务粒度原则

综合考虑复用性以及功能完整性,尽量保持一个团队内部对于服务粒度的一致理解。服务应该是内聚而完整的。

  • 内聚:创建功能内聚的接口,一组操作由于其功能相关而聚合到一起。从服务使用者角度看待服务粒度的划分更加有效。
  • 完整性:服务应该为可复用的,因此需要考虑将来的使用者的可能需求。如果不知道使用者需求,则很难提供正确的功能,因此就有可能存在将开发和测试工作浪费在提供将不会使用的操作上的风险。
服务无状态原则

无状态的服务可以轻易地被替代,如果一个服务出现异常,系统可以随时拉起一个新的服务来接管原有服务的工作;而有状态的服务伸缩起来非常复杂,可以通过将服务的状态外置到数据库、分布式缓存中,从而使服务变成无状态的。

持续演进原则

应逐步划分、持续演进,避免服务数量的爆发性增长。这就类似于应用的灰度发布效果,先将几个不太重要的功能拆分到一个服务做实验,万一有问题也可以缩小故障影响范围。另外,除了业务服务数量的增加,还需要准备持续交付的工具、微服务框架等。随着分布式微服务的改造,系统的全链路追踪监控也要及时跟上,以便出问题时进行快速定位排查。

服务管理原则
  • 业务管理垂直化:以垂直业务划分开发、测试、运维团队,明确跨团队服务消费需求并定义服务契约,方便背对背模式。
  • 数据归属单一化:主数据规则(可写)存储归属于单一业务域,跨域数据规则读写必须通过所属域的服务,不能直接访问对方的数据库。
  • 系统组织层次化:划分服务的系统逻辑层次,大量复用的服务尽可能下沉,对服务依赖做逻辑层次上的限制。
服务契约原则
  • 合适粒度原则:平衡可维护性与易用性。可提供普遍适用的粗粒度业务逻辑片段,根据需求增加精细化的服务接口。
  • 强描述性原则:服务名(名词)及方法(动词)意义明确,表意精准,服务模式明确(同步、异步)。
  • 内聚完整原则:从服务消费者的角度出发,考查服务提供业务能力的完整性,即功能组合的自洽。
  • 语义接口原则:接口信息使用语义化封装,内外隔离,接口信息对象独立于服务内部的实现信息对象定义。
  • 接口普遍适用原则:接口信息基本属性使用跨语言的基本类型(字符串、日期、数值等)。
  • 扩展兼容原则:在保证易用性的前提下,尽可能考虑未来扩展,避免未来频繁更改接口。