按业务域而非技术层划分服务边界,如电商系统中user-service应封装authenticate_and_enrich_user_context等用例级操作,避免细粒度函数暴露与跨域模型共享,坚持数据自治、协议分离与最终一致性。

按业务域而非技术层划分服务边界
很多团队一上来就按“controller/service/dao”分层,结果每个服务里还是塞满所有层逻辑,最后变成“分布式单体”。真正有效的解耦起点是业务域——比如电商系统中,user-service 不该暴露 get_user_by_id 和 update_user_profile 两个细粒度函数,而应封装成 authenticate_and_enrich_user_context 这类语义明确、面向用例的操作。
- 避免把“用户查询”和“用户通知”硬塞进同一个服务:前者属核心身份上下文,后者属事件响应链路,天然该拆到
user-service和notification-service - 领域模型(如
User)必须随服务一起发布,禁止跨服务直接 import 其他服务的pydantic模型或 ORM 类 - 如果两个功能总是一起修改、一起部署、共享同一份数据库迁移脚本,那它们大概率不该分属不同服务
基础设施层必须收口,不能每个服务都自己连 Redis/MQ
放任每个服务自行初始化 redis.Redis() 或 pika.BlockingConnection() 会导致连接数爆炸、配置散落、健康检查失效。正确做法是把连接池、序列化、重试策略全部封装进统一的 client 包,由服务通过依赖注入获取实例。
- 用
dependency_injector或fastapi.Depends注入RedisClient,而不是在路由函数里手动 new 一个连接 -
settings.py中只保留全局配置项(如REDIS_URL),不写任何服务私有参数(如USER_SERVICE_CACHE_TTL) - 消息队列消费者必须使用死信队列 + 延迟重试,且重试次数上限设为 3,避免无限循环消费导致数据错乱
API 网关与内部通信协议要严格区分
对外暴露的 /api/v1/users/{id} 是 REST,但 order-service 调用 inventory-service 查库存时,绝不能也走 HTTP+JSON。同步调用必须用 gRPC,异步事件必须走 Kafka,否则延迟不可控、错误语义模糊、调试成本翻倍。
- gRPC 接口定义(
.proto)必须由被调用方维护并发布为 Python 包,调用方只 install,不 copy-paste - REST 接口返回状态码必须真实反映业务含义:
404表示资源不存在,409表示业务冲突(如库存不足),不能全用500吞掉细节 - Kafka topic 名称需带服务前缀和语义后缀,如
user-service.user_registered.v1,禁止出现events或messages这类无意义通配名
数据一致性必须接受最终一致,别碰分布式事务
试图用 two-phase commit 或 Saga 框架强行保证跨服务 ACID,只会让系统变慢、变脆、难以观测。微服务的数据自治原则不是口号——每个服务只读自己的库,写操作必须通过事件广播,其他服务监听后异步更新本地投影。
- 订单创建成功后,发
order_created事件,库存服务消费后扣减,失败则重试;不要让订单服务直接调用库存服务的扣减接口 - 跨服务查询(如“查订单+用户+商品信息”)必须由 API 网关聚合,禁止前端发三个请求再拼装
- 任何需要强一致的场景(如支付扣款),都该收缩到单一服务内完成,而不是拆出去还幻想“事务可靠”
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











