从单体到微服务:怎么拆、怎么生成、服务之间怎么发现与调用、网关怎么收口。一张架构图先建立全局观。
典型形态:一个对外 API 网关 + 多个对内 RPC 服务,全部通过 etcd 自动注册发现。客户端只认网关,网关再调度内部 RPC。
实线 = 调用链路;绿色虚线 = 服务启动时向 etcd 注册、调用方从 etcd 拉取节点。
拆分的依据不是「技术层」,而是「业务域」。一个域一个 RPC 服务,对外再包一层 API 网关。
go-zero 的精髓:先写契约(.api / .proto / SQL),再让工具产出全部样板。
写好 user.api 后:goctl api go -api user.api -dir user-api
写好 user.proto 后:goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=. -m
goctl model mysql ddl -src user.sql -dir ./internal/model -c 产出带缓存的 CRUD。
网关的 config 里加 UserRpc zrpc.RpcClientConf,svc 里建 client,logic 里直接调用。
func (l *LoginLogic) Login(req *types.LoginReq) (*types.LoginResp, error) { // 通过注入的 svcCtx 拿到 RPC 客户端 resp, err := l.svcCtx.UserRpc.Login(l.ctx, &user.LoginRequest{ Username: req.Username, Password: req.Password, }) if err != nil { return nil, err } return &types.LoginResp{Token: resp.Token}, nil }
RPC 服务启动时自动注册到 etcd,调用方自动发现并负载均衡。你只需要在 yaml 里写 etcd 地址。
Name: user.rpc # 服务名,调用方靠它找你 ListenOn: 0.0.0.0:8080 Etcd: Hosts: - 127.0.0.1:2379 Key: user.rpc # 注册到 etcd 的 key
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc # 按 key 找到 user-rpc 的所有节点
网关是内外边界,把横切关注点集中处理,下游 RPC 保持纯粹。
每个服务独立打镜像、独立部署,互不影响发布节奏。
goctl docker -go user-api.go
产出多阶段构建的 Dockerfile,体积小、启动快。
goctl kube deploy \ -name user-api \ -namespace default \ -image user-api:v1 \ -port 8888 \ -o user-api.yaml
直接产出 Deployment + Service,改改镜像就能上集群。