微服务拆分核心依据是业务能力与数据所有权,而非页面或名词;需确保服务能独立闭环、独占写入权,避免逻辑拆分但物理共库。

单体转微服务不是“重写一遍”,而是有节奏地拆、有依据地分、有兜底地切。Go 语言做这件事,核心不在于语法,而在于结构设计、通信边界和部署粒度的把控。
怎么划清服务边界(别一上来就写代码)
拆分失败,80% 出在领域划分模糊。不能按“前端页面”切,得按“业务能力”和“数据所有权”切:
- 用户注册、登录、资料修改 →
user-service(独占用户表,所有读写走它) - 发帖、评论、点赞 →
content-service(不碰用户密码,只通过userID关联) - 好友关系、关注列表 →
relation-service(独立的关系图谱存储,不和用户主表混)
关键判断标准:一个服务是否能独立完成某类业务闭环?是否拥有自己专属的数据写入权?如果答案是否定的,说明边界还没切准。
go-zero 的 goctl 怎么用才不踩坑
goctl 是加速器,不是自动焊机。生成代码前必须手动完成两件事:
- 先写好
user.api文件,其中service块里每个接口的@handler名称要唯一且语义清晰(比如LoginHandler而不是Handler1) - 配置文件
etc/user-api.yaml中的etcd地址必须真实可连,否则服务启动后注册失败,但日志只报register failed,不提示具体原因 - 生成命令要用
goctl api go -api user.api -dir .,注意-dir后面是当前目录(.),不是./user—— 否则生成路径错乱,main.go找不到 handler 包
服务间调用选 REST 还是 gRPC
新团队、小规模、调试优先,用 REST(http.Client + JSON);高吞吐、低延迟、跨语言协作,上 gRPC。但要注意:
- go-zero 默认生成的是 HTTP API 层,内部服务间调用建议走 gRPC,避免 JSON 序列化/反序列化开销
- 若用 gRPC,必须统一
.proto文件版本,且所有服务共用同一份pb生成代码 —— 否则字段名或类型稍有差异,就会出现unknown field "xxx"错误 - 不要在
user-service里直接http.Get("http://content-service:8083/post"),而应封装为 client 接口,方便后续替换为 gRPC 或 mock 测试
数据库怎么拆才不会丢数据
单体共用一个 MySQL,拆微服务时最容易犯的错是“逻辑拆分、物理不拆”。正确做法:
- 每个服务配独立数据库实例(哪怕初期用同一台 MySQL,也必须不同
schema),禁止跨库 JOIN - 用户服务删掉原单体中的
posts表,内容服务删掉users表 —— 拆完立刻执行SHOW TABLES核对 - 历史数据迁移用脚本而非手动导出导入:
mysqldump --no-create-info --where="user_id IN (SELECT id FROM user_service.users)" community_db.posts > posts_for_user.sql
最常被忽略的一点:外键约束必须在拆分前全部移除。微服务之间靠最终一致性保障,不是靠数据库级约束。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











