二、微服务设计原则:单一职责、服务自治、接口契约、去中心化治理
好,咱们进入第二个核心话题。微服务设计原则。
说实话,我见过太多团队,一上来就拆服务。拆得那叫一个欢快。结果呢?拆完发现,服务之间互相调用像蜘蛛网,改一个功能要改八个服务。嗯,这就是没理解设计原则的后果。
今天聊的这四个原则——单一职责、服务自治、接口契约、去中心化治理——是我个人认为最基础的。你把这四个吃透了,微服务架构至少不会跑偏。
2.1 单一职责原则:一个服务只做一件事
这个原则最早来自面向对象设计。但在微服务里,它更狠——一个服务,只负责一个业务能力。
什么叫一个业务能力?举个例子。用户管理是一个能力。订单处理是另一个能力。支付是第三个。你不能把用户管理和订单处理塞到同一个服务里。为什么?因为它们的变更频率、扩展需求、故障影响面都不一样。
我在项目中遇到过一个典型的反面教材。有个团队把「商品管理」和「库存管理」放在同一个服务里。结果呢?商品详情页要加个字段,部署的时候把库存服务也重启了。线上订单瞬间断了几分钟。你说冤不冤?
判断标准:如果你能用一个简洁的句子描述这个服务「做什么」,而且这个句子里没有「和」字,那基本就对了。
比如:
- 「订单服务负责创建和管理订单」—— 对
- 「订单服务负责订单、支付和物流」—— 错,拆!
2.2 服务自治:你的地盘你做主
服务自治,说白了就是每个服务能独立开发、独立测试、独立部署、独立运行。不依赖别的服务也能活。
你想想看,如果服务A要启动,必须先启动服务B和服务C,那这叫微服务吗?这叫分布式单体。
我建议每个服务都要有自己的数据库。别共享数据库!这是血泪教训。共享数据库意味着你改个表结构,要通知所有团队。你上线一个功能,要协调所有人的时间。那跟单体架构有什么区别?
避坑指南:我曾经见过一个团队,两个服务共享同一个MySQL库。服务A改了用户表的字段类型,服务B没同步更新ORM映射,结果线上查询全部报错。那晚的故障复盘会,开了整整四个小时。
服务自治还体现在数据同步上。服务之间的数据一致性,别用强事务。用最终一致性,用事件驱动。我个人的习惯是:能用异步消息解决的,绝不用同步RPC。
2.3 接口契约:先说好,再动手
微服务之间怎么通信?靠接口。接口就是合同。合同没写好,后面全是扯皮。
接口契约的核心是:定义清楚输入、输出、错误码、版本号。而且这个契约要独立于实现。你用Java,我用Go,没关系。只要契约一致,就能通信。
我个人比较推荐用OpenAPI(Swagger)或者gRPC的Protocol Buffers来定义契约。为什么?因为它们是语言无关的,而且可以自动生成客户端和服务端代码。
举个例子,一个简单的用户服务接口:
// 用Protobuf定义接口契约
service UserService {
rpc GetUser (GetUserRequest) returns (GetUserResponse);
}
message GetUserRequest {
string user_id = 1;
}
message GetUserResponse {
string user_id = 1;
string name = 2;
string email = 3;
int32 status = 4; // 0: 正常, 1: 禁用
}
你看,字段类型、字段含义、状态码枚举,全写清楚了。谁都不用猜。
小技巧:接口契约一定要做版本管理。我习惯在URL或者请求头里带版本号,比如 /v1/users/{id}。这样即使接口升级,旧版本还能继续用,给客户端留足迁移时间。
2.4 去中心化治理:别搞中央集权
去中心化治理,听起来有点政治色彩。其实技术上说,就是每个团队可以自己选技术栈、自己定开发流程、自己管自己的服务。
为什么需要去中心化?因为微服务架构下,服务多了,你不可能用一个统一的框架、统一的数据库、统一的部署方式去管所有服务。那会把人逼疯。
我记得有一次去一个客户现场,他们规定所有微服务必须用Spring Cloud,必须用Eureka做注册中心,必须用同一个配置中心。结果有个团队想用Go写一个高性能的网关服务,被架构委员会驳回了。理由是「不符合统一技术规范」。你说这合理吗?
去中心化治理,不是没有治理。而是治理的粒度下放到服务级别。比如:
- 技术选型:团队自己定,只要满足SLA
- 数据库选型:根据业务场景选,不强制统一
- 部署方式:可以用K8s,也可以用Serverless
- 监控告警:自己配自己的,但日志格式要统一(方便全局排查)
核心思想:去中心化不是无政府状态。而是「中央定标准,地方做决策」。标准要少而精,决策要快而准。
2.5 四个原则的关系
这四个原则不是孤立的。它们互相支撑:
| 原则 | 解决的问题 | 跟其他原则的关系 |
|---|---|---|
| 单一职责 | 服务边界模糊,变更互相影响 | 边界清晰了,自治才可能实现 |
| 服务自治 | 服务之间强依赖,无法独立交付 | 自治了,接口契约才有意义 |
| 接口契约 | 服务间通信混乱,兼容性差 | 契约稳定了,去中心化治理才敢放权 |
| 去中心化治理 | 中央决策慢,扼杀创新 | 治理放权了,单一职责才能真正落地 |
说白了,这四个原则是一个闭环。你缺了任何一个,其他三个都会出问题。
2.6 实践中的常见误区
最后聊几个我见过的坑,你注意避一下:
- 过度拆分:一个服务只有两个接口,也要拆成一个微服务。没必要。微服务也是服务,不是函数。
- 接口契约频繁变更:今天加个字段,明天改个类型。客户端团队天天追着你问。我建议接口变更走评审流程,至少提前一个迭代通知。
- 自治变成孤岛:每个服务自己玩自己的,日志格式不统一,监控指标不统一,出问题的时候全局排查像大海捞针。自治不等于各自为政。
- 去中心化变成没人管:没有统一的API网关,没有统一的安全策略,没有统一的配置管理。最后线上出了安全漏洞,都不知道哪个服务的问题。
我的建议:刚开始做微服务,别追求完美。先按单一职责拆,再逐步推进自治和契约。去中心化治理可以晚一点,等团队成熟了再放权。步子迈大了,容易扯着。
好,这一章就到这儿。下一章我们聊服务拆分的方法论——到底怎么拆,才能拆得漂亮。