Files
lone-services/README.md
T
2026-08-05 17:37:32 +08:00

345 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 如何加一个新服务
以加 `order` 为例(对标现有 `product`)。
### 0. 安装 goctl
```bash
go install github.com/zeromicro/go-zero/tools/goctl@latest
goctl --version
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
```
### 1. 创建 RPC 服务(goctl
在仓库根目录执行:
```bash
goctl rpc new order
cd order
```
### 2. 将 proto 移到 `proto/` 目录
`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `proto/`
```bash
mkdir proto
mv order.proto proto/
```
### 4. 配置 Zero 兼容 Nacos
编辑 `order/internal/config/config.go`
```go
package config
import "github.com/zeromicro/go-zero/zrpc"
type Config struct {
zrpc.RpcServerConf
Nacos NacosConf
}
type NacosConf struct {
Hosts []string
NamespaceId string `json:",optional"`
Group string `json:",optional"`
RegisterIP string `json:",optional"`
}
```
### 5. 配置服务名与监听端口
`order/etc/order.yaml`
```yaml
Name: order-service # 注册到 Nacos 的 serviceNameBFF Upstream.Target 必须与此一致
ListenOn: 0.0.0.0:10200
Nacos:
Hosts:
- rnacos:8848
NamespaceId: test
Group: LONE_SERVICES
RegisterIP: order # Docker Compose 里的服务名 / 主机名
Mysql:
Host: mysql
Port: 3306
User: root
Password: "123123"
Database: dms-order
Charset: utf8mb4
Prefix:
```
### 3. 构建 mod
编辑 `order/go.mod`
```go
go 1.24.3
require (
github.com/zeromicro/go-zero v1.10.2
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
)
```
```bash
go mod tidy
```
编辑 `order/go.mod` 增加本地包 pkg.local
```go
require (
github.com/zeromicro/go-zero v1.10.2
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
pkg.local v0.0.0
)
replace pkg.local => ../pkg
```
### 6. 服务注册
编辑 `order/order.go`
```go
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
if err := discovery.Init(discovery.Config{
Hosts: c.Nacos.Hosts,
NamespaceId: c.Nacos.NamespaceId,
Group: c.Nacos.Group,
}); err != nil {
log.Fatalf("nacos init: %v", err)
}
registerIP := c.Nacos.RegisterIP
port, err := listenPort(c.ListenOn)
if err != nil {
log.Fatalf("parse ListenOn: %v", err)
}
if err := discovery.Register(discovery.Instance{
ServiceName: c.Name,
IP: registerIP,
Port: port,
Group: c.Nacos.Group,
}); err != nil {
log.Fatalf("nacos register: %v", err)
}
defer func() {
if err := discovery.Deregister(); err != nil {
log.Printf("nacos deregister: %v", err)
}
}()
ctx := svc.NewServiceContext(c)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
order.RegisterOrderServer(grpcServer, server.NewOrderServer(ctx))
if c.Mode == service.DevMode || c.Mode == service.TestMode {
reflection.Register(grpcServer)
}
})
defer s.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
s.Start()
}
func listenPort(listenOn string) (uint64, error) {
_, portStr, err := net.SplitHostPort(listenOn)
if err != nil {
return 0, err
}
return strconv.ParseUint(portStr, 10, 64)
}
```
编辑 `order/order.go`:增加本地包
```go
import (
"pkg.local/discovery"
)
```
再次执行
```bash
go mod tidy
```
### 8. 接入 Docker Compose
`deploy/docker-compose.override.yml` 增加服务:
```yaml
order:
image: golang:1.24.3
volumes:
- ..:/src
- go-mod-cache:/go/pkg/mod
working_dir: /src/order
command: go run . -f etc/order.yaml
ports:
- "10200:10200"
environment:
NACOS_SERVER_ADDR: rnacos:8848
depends_on:
- rnacos
```
### 9. 生成 ProtoSet 给 BFF
```bash
protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/order.pb order.proto
```
### 10. 在 BFF 配 Upstream + Mapping
编辑 `bff/etc/bff.yaml`,增加一段(go-zero gateway **每个 RPC 都要写 Mapping**):
```yaml
- Name: order
Grpc:
Target: order-service # 必须等于 order.yaml 的 Name
Timeout: 5000
ProtoSets:
- etc/order.pb
Mappings:
- Method: post
Path: /admin/v3/order/ping
RpcPath: order.Order/Ping
```
### 11. 加接口需要
只改业务逻辑(`internal/logic/`)不必跑 goctl。
`proto/order.proto`(新增/改名 RPC、改字段等)后,按文末「三条命令何时用」处理;
若 HTTP 路径有变,再改第 10 步的 Mapping。
---
### 命令 ①:生成服务端 pb / grpc
```bash
protoc -I. -I../pkg/third_party --go_out=. --go-grpc_out=. proto/order.proto
```
**什么时候跑:**
- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条**
- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新)
### 命令 ②:生成 BFF ProtoSet
```bash
protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/product.pb --include_imports proto/order.proto
```
**什么时候跑:**
- 增删改 **字段**BFF gateway 编解码需要)
- 增删 **RPC**
### 命令 ③:goctl 生成/更新脚手架
```bash
goctl rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=.
```
**什么时候跑:**
- **新增 RPC**:需要生成 `internal/logic`、更新 `server` / `productclient`
- 注意:可能覆盖已改过的 `product.go` 等,生成后对比合并;也可用手写 logic/server 代替
## Proto 常用校验规则(protovalidate
文档:https://protovalidate.com/schemas/standard-rules/
依赖:`import "buf/validate/validate.proto";`,服务启动挂 `pkg.local/validate` 拦截器。
### 必填字符串
```protobuf
string name = 1 [(buf.validate.field).string = {min_len: 1, max_len: 256}];
```
`min_len: 1` 表示不能为空串。
### 可选字符串(仅限长度)
```protobuf
string subhead = 2 [(buf.validate.field).string = {max_len: 255}];
```
空串可通过;有内容时限制最大长度。
### 必填数值(含 0 合法)
```protobuf
double price = 6 [(buf.validate.field).double = {gte: 0}];
int32 period_validity = 16 [(buf.validate.field).int32 = {gte: 0}];
```
### 非必填数值(0 表示未传,跳过校验)
```protobuf
double store_price = 7 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
double: {gte: 0}
}];
```
有值时仍要求 `>= 0`;未传/为 0 不校验。
### 枚举 / 固定取值(0 表示未传)
```protobuf
uint32 type = 19 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
uint32: {in: [1, 2, 3]}
}];
uint32 sales_model = 4 [(buf.validate.field) = {
ignore: IGNORE_IF_ZERO_VALUE,
uint32: {in: [1, 2]}
}];
```
### ID 必须大于 0
```protobuf
int64 id = 1 [(buf.validate.field).int64 = {gt: 0}];
```
### 无规则字段
```protobuf
uint32 number = 20; // 不做 protovalidate
```
### 删除字段编号(避免复用)
```protobuf
// reserved 2;
```
业务条件校验(如「普通商品必须带齐价格」)仍写在 `internal/logic`,不要全塞进 proto。