go-zero rpc 分布式 微服务

安装go必要环境

  1. 下载go
bash 复制代码
https://go.dev/dl/

# inter版本
https://go.dev/dl/go1.25.5.windows-amd64.msi
  1. 配置GOROOT
  2. 配置代理

安装goctl工具

bash 复制代码
 go install github.com/zeromicro/go-zero/tools/goctl@latest

goctl --version

出现下面的信息说明go-zero安装成功

创建第一个项目

初始化api项目

bash 复制代码
goctl api new user

查看生成的项目

下载依赖

切换到user目录,下载依赖

复制代码
 cd user
 go mod tidy

结果

复制代码
 cd user
PS E:\work\golang\demo\user> go mod tidy
go: finding module for package github.com/zeromicro/go-zero/core/logx
go: finding module for package github.com/zeromicro/go-zero/rest
go: finding module for package github.com/zeromicro/go-zero/core/conf
go: finding module for package github.com/zeromicro/go-zero/rest/httpx
go: found github.com/zeromicro/go-zero/core/conf in github.com/zeromicro/go-zero v1.9.4
go: found github.com/zeromicro/go-zero/rest in github.com/zeromicro/go-zero v1.9.4
go: found github.com/zeromicro/go-zero/rest/httpx in github.com/zeromicro/go-zero v1.9.4
go: found github.com/zeromicro/go-zero/core/logx in github.com/zeromicro/go-zero v1.9.4
go: downloading github.com/stretchr/testify v1.11.1
go: downloading github.com/google/uuid v1.6.0
go: downloading k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
go: downloading github.com/golang-jwt/jwt/v4 v4.5.2
go: downloading gopkg.in/h2non/gock.v1 v1.1.2
go: downloading github.com/google/go-cmp v0.6.0
go: downloading google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094
go: downloading github.com/kylelemons/godebug v1.1.0
go: downloading github.com/prometheus/procfs v0.15.1
go: downloading go.uber.org/goleak v1.3.0
go: downloading github.com/stretchr/objx v0.5.2
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542
go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
go: downloading github.com/kr/pretty v0.3.1
go: downloading github.com/prashantv/gostub v1.1.0
go: downloading github.com/rogpeppe/go-internal v1.10.0
go: downloading github.com/kr/text v0.2.0

运行user模块

运行启动user模块

复制代码
go run user.go   
Starting server at 0.0.0.0:8888...

生成文件详细解释

  1. 配置文件
    user/etc/user-api.yaml
yml 复制代码
Name: user-api # 服务名
Host: 0.0.0.0 # 主机
Port: 8888 #端口
  1. 定义协议

user/user.api

yml 复制代码
syntax = "v1" # 版本

# 请求 `type`  对于生成的Request  在`user/internal/types/types.go` 的 	`Request`
type Request {
	Name string `path:"name,options=you|me"`
}

# 响应  `type` 对于生成的Response 在`user/internal/types/types.go` 的 	`Response`
type Response {
	Message string `json:"message"`
}

# 方法, UserHandler在`user/internal/handler/userhandler.go`里
service user-api {
	@handler UserHandler
	get /from/:name (Request) returns (Response)
}
  1. 类型type
    user/internal/types/types.go
go 复制代码
package types

type Request struct {
	Name string `path:"name,options=you|me"`
}

type Response struct {
	Message string `json:"message"`
}
  1. svc 上下文
go 复制代码
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2

package svc

import (
	"demo/user/internal/config"
)

type ServiceContext struct {
	Config config.Config
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
	}
}
  1. 逻辑logic
go 复制代码
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2

package logic

import (
	"context"
	"demo/user/internal/svc"
	"demo/user/internal/types"
	"github.com/zeromicro/go-zero/core/logx"
)

type UserLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLogic {
	return &UserLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserLogic) User(req *types.Request) (resp *types.Response, err error) {
	// todo: add your logic here and delete this line
	return &types.Response{
		Message: "===========Hello World==========",
	}, nil
}
  1. 路由
go 复制代码
// Code generated by goctl. DO NOT EDIT.
// goctl 1.9.2

package handler

import (
	"net/http"

	"demo/user/internal/svc"

	"github.com/zeromicro/go-zero/rest"
)

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
	server.AddRoutes(
		[]rest.Route{
			{
				Method:  http.MethodGet,
				Path:    "/from/:name",
				Handler: UserHandler(serverCtx),
			},
		},
	)
}

浏览器查看

bash 复制代码
http://127.0.0.1:8888/from/you
bash 复制代码
http://127.0.0.1:8888/from/wo

知识总结

热加载

下载air

方便开发,

复制代码
go install github.com/air-verse/air@latest
 
air -v

运行

不再运行 go run user

复制代码
air 

Thunder Client 测试

vscode 安装插件

go-zero项目解析










GRPC demo代码生成

grpc服务是和http服务分开的,不可以混为一谈

例如:同为user模块,既可以提供http服务,也可以提供rpc服务

如果提供http服务,命令行如下:

go 复制代码
cd /user
go run user.go

如果提供rpc服务,相应的配置,proto文件等需要生成。这里只讲启动

go 复制代码
cd /user/rpc
go run user.go

以car项目为例

bash 复制代码
goctl rpc new car
  1. 创建过程
bash 复制代码
goctl rpc new car
go: downloading google.golang.org/protobuf v1.36.11
go: downloading google.golang.org/grpc v1.78.0
go: downloading google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0
go: downloading google.golang.org/protobuf v1.36.10
Done.
  1. 切换到car目录下拉去依赖,
bash 复制代码
go mod tidy
  1. 运行

会报错

复制代码
go run car

编辑该文件

internal/logic/pinglogic.go

复制代码

商城微服务 shop

0.规划

服务 http端口
user-api 8881
user-rpc 8882
order-api 8883
order-rpc 8884
product-api 8885
product-rpc 8886
cart-api 8887
cart-rpc 8888
product-api 8887
product-rpc 8888
gateway-api 8889
gateway-rpc 8890

1.创建项目

复制代码
mkdir -p shop/api
cd shop

2.初始化init mod

复制代码
go mod init finejade/shop-mall

3. 定义 API 文件

网关服务 api/gateway.api

go 复制代码
// api/gateway.api
info (
	title:   "Shop Mall Gateway API"
	desc:    "API Gateway for the distributed shop mall system."
	author:  "Your Name"
	email:   "your.email@example.com"
	version: "1.0.0"
)

// 1. 定义所有路由所需的具体请求和响应结构体
//    这些结构体必须与各自微服务 .api 文件中的定义保持一致!
type (
	// --- 用户服务 (user.api) ---
	UserRegisterReq {
		Username string `json:"username"`
		Password string `json:"password"`
		Email    string `json:"email"`
	}
	UserRegisterResp {
		Id int64 `json:"id"`
	}
	UserLoginReq {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	UserLoginResp {
		Token string `json:"token"`
	}
	GetUserInfoReq {
		// 实际项目中,用户ID通常从JWT Token解析,这里仅为演示
		UserId int64 `json:"userId"`
	}
	UserInfo {
		Id       int64  `json:"id"`
		Username string `json:"username"`
		Email    string `json:"email"`
	}
	GetUserInfoResp {
		User UserInfo `json:"user"`
	}
	// --- 商品服务 (product.api) ---
	GetProductListReq {
		Page     int `form:"page,default=1"`
		PageSize int `form:"pageSize,default=10"`
	}
	ProductItem {
		Id       int64   `json:"id"`
		Name     string  `json:"name"`
		Price    float64 `json:"price"`
		ImageUrl string  `json:"imageUrl"`
	}
	GetProductListResp {
		List  []ProductItem `json:"list"`
		Total int64         `json:"total"`
	}
	GetProductDetailReq {
		Id int64 `path:"id"`
	}
	GetProductDetailResp {
		Product ProductItem `json:"product"`
	}
	// --- 购物车服务 (cart.api) ---
	AddToCartReq {
		UserId    int64 `json:"userId"`
		ProductId int64 `json:"productId"`
		Quantity  int   `json:"quantity"`
	}
	GetCartListReq {
		UserId int64 `json:"userId"`
	}
	CartItem {
		ProductId   int64   `json:"productId"`
		ProductName string  `json:"productName"`
		Price       float64 `json:"price"`
		Quantity    int     `json:"quantity"`
	}
	GetCartListResp {
		Items []CartItem `json:"items"`
	}
	UpdateCartItemReq {
		UserId    int64 `json:"userId"`
		ProductId int64 `json:"productId"`
		Quantity  int   `json:"quantity"`
	}
	DeleteCartItemReq {
		UserId    int64 `json:"userId"`
		ProductId int64 `json:"productId"`
	}
	// --- 订单服务 (order.api) ---
	CreateOrderReq {
		UserId  int64  `json:"userId"`
		Address string `json:"address"`
	}
	CreateOrderResp {
		OrderId int64 `json:"orderId"`
	}
	GetOrderListReq {
		UserId int64 `json:"userId"`
	}
	OrderInfo {
		Id         int64   `json:"id"`
		TotalPrice float64 `json:"totalPrice"`
		Status     string  `json:"status"`
		CreateTime string  `json:"createTime"`
	}
	GetOrderListResp {
		Orders []OrderInfo `json:"orders"`
	}
	GetOrderDetailReq {
		Id int64 `path:"id"`
	}
	GetOrderDetailResp {
		Order OrderInfo `json:"order"`
	}
	// --- 支付服务 (payment.api) ---
	CreatePaymentReq {
		OrderId int64  `json:"orderId"`
		Method  string `json:"method"`
	}
	CreatePaymentResp {
		PaymentUrl string `json:"paymentUrl"`
	}
	PaymentNotifyReq {
		OutTradeNo  string `json:"out_trade_no"`
		TradeStatus string `json:"trade_status"`
	}
	PaymentNotifyResp {
		Code string `json:"code"`
		Msg  string `json:"msg"`
	}
	// 2. 定义网关统一的、最终的对外响应格式
	GatewayResponse {
		Code int         `json:"code"` // 业务状态码, 0 代表成功
		Msg  string      `json:"msg"` // 提示信息
		Data interface{} `json:"data"` // 响应数据,这里可以是任意类型
	}
)

// 3. 在 service 块中,为每个路由指定其具体的请求和响应类型
service gateway-api {
	// --- 用户服务路由 ---
	@doc "用户注册"
	@handler userRegisterHandler
	post /api/user/register (UserRegisterReq) returns (GatewayResponse)

	@doc "用户登录"
	@handler userLoginHandler
	post /api/user/login (UserLoginReq) returns (GatewayResponse)

	@doc "获取用户信息"
	@handler getUserInfoHandler
	get /api/user/info (GetUserInfoReq) returns (GatewayResponse)

	// --- 商品服务路由 ---
	@doc "获取商品列表"
	@handler getProductListHandler
	get /api/product/list (GetProductListReq) returns (GatewayResponse)

	@doc "获取商品详情"
	@handler getProductDetailHandler
	get /api/product/:id (GetProductDetailReq) returns (GatewayResponse)

	// --- 购物车服务路由 ---
	@doc "添加商品到购物车"
	@handler addToCartHandler
	post /api/cart/add (AddToCartReq) returns (GatewayResponse)

	@doc "获取购物车列表"
	@handler getCartListHandler
	get /api/cart/list (GetCartListReq) returns (GatewayResponse)

	@doc "更新购物车商品数量"
	@handler updateCartItemHandler
	post /api/cart/update (UpdateCartItemReq) returns (GatewayResponse)

	@doc "删除购物车商品"
	@handler deleteCartItemHandler
	post /api/cart/delete (DeleteCartItemReq) returns (GatewayResponse)

	// --- 订单服务路由 ---
	@doc "创建订单"
	@handler createOrderHandler
	post /api/order/create (CreateOrderReq) returns (GatewayResponse)

	@doc "获取订单列表"
	@handler getOrderListHandler
	get /api/order/list (GetOrderListReq) returns (GatewayResponse)

	@doc "获取订单详情"
	@handler getOrderDetailHandler
	get /api/order/:id (GetOrderDetailReq) returns (GatewayResponse)

	// --- 支付服务路由 ---
	@doc "创建支付"
	@handler createPaymentHandler
	post /api/payment/create (CreatePaymentReq) returns (GatewayResponse)

	@doc "支付回调通知"
	@handler paymentNotifyHandler
	post /api/payment/notify (PaymentNotifyReq) returns (PaymentNotifyResp)
}


}

用户服务 api/user.api

go 复制代码
info(
    title: "User Service API"
    desc: "Provides user registration, login, and profile management."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    RegisterReq {
        Username string `json:"username"`
        Password string `json:"password"`
        Email    string `json:"email"`
    }

    LoginReq {
        Username string `json:"username"`
        Password string `json:"password"`
    }

    GetUserInfoReq {
        // 实际项目中,用户ID通常从JWT Token中解析,这里仅作示例
        UserId int64 `json:"userId"`
    }

    // --- 响应结构体 ---
    RegisterResp {
        Id int64 `json:"id"`
    }

    LoginResp {
        Token string `json:"token"`
    }

    UserInfo {
        Id       int64  `json:"id"`
        Username string `json:"username"`
        Email    string `json:"email"`
        Nickname string `json:"nickname"`
        Avatar   string `json:"avatar"`
    }
    
    GetUserInfoResp {
        User UserInfo `json:"user"`
    }

    // 统一响应
    UserResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }
)

service user-api {
    @handler registerHandler
    post /user/register (RegisterReq) returns (UserResponse)

    @handler loginHandler
    post /user/login (LoginReq) returns (UserResponse)

    @handler getUserInfoHandler
    get /user/info (GetUserInfoReq) returns (UserResponse)
}

商品服务 (api/product.api)

go 复制代码
info(
    title: "Product Service API"
    desc: "Provides product listing and detail information."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    GetProductListReq {
        Page     int `form:"page,default=1"`
        PageSize int `form:"pageSize,default=10"`
    }

    GetProductDetailReq {
        Id int64 `path:"id"`
    }

    // --- 响应结构体 ---
    ProductItem {
        Id          int64   `json:"id"`
        Name        string  `json:"name"`
        Price       float64 `json:"price"`
        Description string  `json:"description"`
        Stock       int     `json:"stock"`
        ImageUrl    string  `json:"imageUrl"`
    }

    GetProductListResp {
        List  []ProductItem `json:"list"`
        Total int64         `json:"total"`
    }

    GetProductDetailResp {
        Product ProductItem `json:"product"`
    }

    // 统一响应
    ProductResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }
)

service product-api {
    @handler getProductListHandler
    get /product/list (GetProductListReq) returns (ProductResponse)

    @handler getProductDetailHandler
    get /product/:id (GetProductDetailReq) returns (ProductResponse)
}

购物车服务 (cart.api)

go 复制代码
info(
    title: "Cart Service API"
    desc: "Manages user shopping cart items."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    AddToCartReq {
        UserId    int64 `json:"userId"`
        ProductId int64 `json:"productId"`
        Quantity  int   `json:"quantity"`
    }

    GetCartListReq {
        UserId int64 `json:"userId"`
    }

    UpdateCartItemReq {
        UserId    int64 `json:"userId"`
        ProductId int64 `json:"productId"`
        Quantity  int   `json:"quantity"`
    }

    DeleteCartItemReq {
        UserId    int64 `json:"userId"`
        ProductId int64 `json:"productId"`
    }

    // --- 响应结构体 ---
    CartItem {
        ProductId   int64   `json:"productId"`
        ProductName string  `json:"productName"`
        Price       float64 `json:"price"`
        Quantity    int     `json:"quantity"`
        ImageUrl    string  `json:"imageUrl"`
    }

    GetCartListResp {
        Items []CartItem `json:"items"`
    }
    
    // 统一响应
    CartResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }
)

service cart-api {
    @handler addToCartHandler
    post /cart/add (AddToCartReq) returns (CartResponse)

    @handler getCartListHandler
    get /cart/list (GetCartListReq) returns (CartResponse)

    @handler updateCartItemHandler
    post /cart/update (UpdateCartItemReq) returns (CartResponse)

    @handler deleteCartItemHandler
    post /cart/delete (DeleteCartItemReq) returns (CartResponse)
}

订单服务 (order.api)

go 复制代码
info(
    title: "Order Service API"
    desc: "Manages the entire order lifecycle, from creation to fulfillment."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    CreateOrderReq {
        UserId  int64 `json:"userId"`
        // 实际项目中,地址信息会更复杂,这里简化
        Address string `json:"address"`
    }

    GetOrderListReq {
        UserId int64 `json:"userId"`
    }

    GetOrderDetailReq {
        OrderId int64 `path:"id"`
    }

    // --- 响应结构体 ---
    OrderItem {
        ProductId   int64   `json:"productId"`
        ProductName string  `json:"productName"`
        Price       float64 `json:"price"`
        Quantity    int     `json:"quantity"`
    }

    OrderInfo {
        Id         int64       `json:"id"`
        UserId     int64       `json:"userId"`
        TotalPrice float64     `json:"totalPrice"`
        Status     string      `json:"status"` // e.g., "pending_payment", "paid", "shipped"
        Items      []OrderItem `json:"items"`
        CreateTime string      `json:"createTime"`
    }

    CreateOrderResp {
        OrderId int64 `json:"orderId"`
    }

    GetOrderListResp {
        Orders []OrderInfo `json:"orders"`
    }

    GetOrderDetailResp {
        Order OrderInfo `json:"order"`
    }

    // 统一响应
    OrderResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }
)

service order-api {
    @handler createOrderHandler
    post /order/create (CreateOrderReq) returns (OrderResponse)

    @handler getOrderListHandler
    get /order/list (GetOrderListReq) returns (OrderResponse)

    @handler getOrderDetailHandler
    get /order/:id (GetOrderDetailReq) returns (OrderResponse)
}

支付服务 (payment.api)

go 复制代码
info(
    title: "Payment Service API"
    desc: "Handles payment processing and payment notifications."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    CreatePaymentReq {
        OrderId int64 `json:"orderId"`
        // 支付方式, e.g., "alipay", "wechat"
        Method  string `json:"method"`
    }

    // 支付回调的请求体通常由第三方支付平台定义,这里简化
    PaymentNotifyReq {
        OutTradeNo  string `json:"out_trade_no"`
        TradeStatus string `json:"trade_status"`
        // ... 其他回调参数
    }

    // --- 响应结构体 ---
    CreatePaymentResp {
        // 支付链接或参数,前端需要用它来唤起支付
        PaymentUrl string `json:"paymentUrl"`
    }
    
    // 支付回调的响应体也需要符合第三方平台的要求,通常是 "success"
    PaymentNotifyResp {
        Code string `json:"code"`
        Msg  string `json:"msg"`
    }

    // 统一响应
    PaymentResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }
)

service payment-api {
    @handler createPaymentHandler
    post /payment/create (CreatePaymentReq) returns (PaymentResponse)

    // 注意:支付回调接口通常是 POST,并且可能需要特殊的签名验证
    @handler paymentNotifyHandler
    post /payment/notify (PaymentNotifyReq) returns (PaymentNotifyResp)
}

库存 api/stock.api

go 复制代码
info(
    title: "Stock Service API"
    desc: "Provides stock deduction and management for products."
    author: "Your Name"
    email: "your.email@example.com"
    version: "1.0.0"
)

type (
    // --- 请求结构体 ---
    DeductStockReq {
        ProductId int64  `json:"productId"`
        Quantity  int    `json:"quantity"`
        OrderId   string `json:"orderId"`
    }

    RollbackStockReq {
        ProductId int64  `json:"productId"`
        Quantity  int    `json:"quantity"`
        OrderId   string `json:"orderId"`
    }

    GetStockReq {
        ProductId int64 `path:"productId"`
    }

    // --- 响应结构体 ---
    StockResponse {
        Code int         `json:"code"`
        Msg  string      `json:"msg"`
        Data interface{} `json:"data"`
    }

    GetStockData {
        TotalStock     int `json:"totalStock"`
        AvailableStock int `json:"availableStock"`
    }
)

service stock-api {
    @doc "扣减库存"
    @handler deductStockHandler
    post /stock/deduct (DeductStockReq) returns (StockResponse)

    @doc "回滚库存"
    @handler rollbackStockHandler
    post /stock/rollback (RollbackStockReq) returns (StockResponse)

    @doc "获取库存信息"
    @handler getStockHandler
    get /stock/:productId (GetStockReq) returns (StockResponse)
}

4.生成各http服务代码

bash 复制代码
# --- 网关服务 ---
# 网关通常是一个 API Gateway 类型的服务
goctl api go -api api/gateway.api -dir gateway

# --- 用户服务 ---
goctl api go -api api/user.api -dir user

# --- 商品服务 ---
goctl api go -api api/product.api -dir product

# --- 订单服务 ---
goctl api go -api api/order.api -dir order

# --- 购物车服务 ---
goctl api go -api api/cart.api -dir cart

# --- 支付服务 ---
goctl api go -api api/payment.api -dir payment


# --- 库存服务 ---
# 库存服务通常是一个 RPC 服务,用于内部服务间调用
# 假设你已经定义了 stock.proto
# goctl rpc protoc api/stock.proto --go_out=stock --go-grpc_out=stock --zrpc_out=stock
# 如果先用 API 风格开发,命令如下:

goctl api go -api api/stock.api -dir stock

ETCD

下载

go 复制代码
https://github.com/etcd-io/etcd/tree/v3.6.7

运行

启动 Etcd: 解压后,在本地启动一个单节点的 Etcd 服务。

图形界面

下载
go 复制代码
https://github.com/evildecay/etcdkeeper/releases
特点

etcdkeeper 目前最流行、最简单易用的 Etcd 可视化工具。它是一个单文件的二进制应用,无需任何依赖,开箱即用
特点:

  1. 单文件部署:下载一个二进制文件,直接运行即可,非常方便。
  2. 界面简洁直观:左侧是目录树,右侧是键值对,操作简单。
  3. 功能全面:支持增、删、改、查,以及树形结构的展示。
  4. 跨平台:提供 Windows, macOS, Linux 版本。
运行

解压进入目录

go 复制代码
etcdkeeper.exe -p 9999
2025/12/30 15:04:22 main.go:103: listening on 0.0.0.0:9999
2025/12/30 15:04:51 main.go:638: POST v3 connect success.
2025/12/30 15:04:51 main.go:701: GET v3 /
2025/12/30 15:04:53 main.go:701: GET v3 user.rpc/7587891840418209374

浏览器打开

go 复制代码
http://127.0.0.1:9999/etcdkeeper/

进入左上角设置用户名和密码

RPC文件生成,配置

在每个服务的配置文件中添加 Etcd 配置

你需要修改每个服务的 etc/xxx-api.yaml 文件,告诉它们如何连接到 Etcd。

以 user/etc/user-api.yaml 为例

go 复制代码
Name: user-api
Host: 0.0.0.0
Port: 8888
# ... 其他配置 ...

# 新增 Etcd 配置
Etcd:
  Hosts:
  - 127.0.0.1:2379
  Key: user.api # 这个 Key 是服务在 Etcd 中的唯一标识

服务间通信 (Inter-Service Communication)

这是微服务架构的核心。我们将以 "订单服务调用用户服务获取用户信息" 为例,演示如何实现服务间调用。

1.将被调用方改造为 RPC 服务 (以 user 服务为例)

HTTP API 服务主要用于对外(给前端或网关)提供服务。服务间的高效通信应该使用 RPC。

创建 user.proto: 在 api 目录下创建一个 user.proto 文件,定义 user 服务提供的 RPC 接口。

api/user.proto

protobuf 复制代码
syntax = "proto3";

package user;

option go_package = "./user";

message IdRequest {
  int64 id = 1;
}

message UserResponse {
  int64 id = 1;
  string username = 2;
  string email = 3;
}

service User {
  rpc GetUserById(IdRequest) returns (UserResponse);
}
生成 RPC 代码: 使用 goctl 生成 user 的 RPC 服务代码
bash 复制代码
# 在项目根目录下执行
goctl rpc protoc api/user.proto --go_out=user/rpc --go-grpc_out=user/rpc --zrpc_out=user/rpc
整合 RPC 和 HTTP 服务

现在 user 目录下既有 HTTP API 代码,也有了 RPC 代码。

你需要在 user.go 中同时启动这两个服务。

** 1. 在 order 的配置文件中添加 user 服务的 RPC 配置:**

order/etc/order-api.yaml

yaml 复制代码
Name: order-api
Host: 0.0.0.0
Port: 8889
# ... 其他配置 ...

# 新增要调用的 user 服务的 RPC 配置
UserRpc:
  Etcd:
    Hosts:
    - 127.0.0.1:2379
    Key: user.rpc # 这个 Key 必须和 user 服务在 Etcd 中注册的 Key 一致

** 2.新增:在调用的user服务的RPC配置 **

RpcClientConf:order/internal/config/config.go

go 复制代码
package config

import (
    "github.com/zeromicro/go-zero/rest"
    "github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
    rest.RestConf
    UserRpc zrpc.RpcClientConf // 新增这一行
}

3.在 order 的服务上下文中初始化 RPC 客户端:

order/internal/svc/servicecontext.go

go 复制代码
package svc

import (
	"finejade/shop-mall/order/internal/config"
	// 1. 导入生成的 user rpc 客户端包
	//    这个路径是根据你的项目结构和 user.proto 中的 go_package 生成的
	"finejade/shop-mall/user/rpc/userclient"

	"github.com/zeromicro/go-zero/zrpc"
)

type ServiceContext struct {
	Config config.Config
	// 2. 在这里声明一个 UserRpc 客户端实例
	//    它的类型是 userclient.User
	UserRpc userclient.User
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		// 3. 在这里初始化 UserRpc 客户端
		//    zrpc.MustNewClient 会根据配置自动从 Etcd 发现服务并创建连接
		UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
	}
}
阶段四:实现业务逻辑
  • 现在,基础设施已经搭建完毕,你可以开始填充每个服务 internal/logic/ 目录下的业务逻辑代码了。例如:
  • 在 user 服务中连接数据库,实现用户的增删改查。
  • 在 product 服务中实现商品列表和详情的查询。
  • 在 order 服务中,实现创建订单的完整流程:
    • 调用 user RPC 验证用户信息。
    • 调用 product RPC 获取商品价格。
    • 调用 stock RPC 预扣减库存。
    • 在本地数据库创建订单记录。
    • 返回订单 ID。

5. 启动

以user为例,启动user-rpc服务,如果需要,也可以启动user http服务

  • 1、启动rpc服务
bash 复制代码
cd shop/user/rpc
go run user.go
Starting server at 0.0.0.0:8885...
  • 2、启动http服务
bash 复制代码
cd shop/user
go run user.go
Starting server at 0.0.0.0:8885...

6.测试

访问order服务,通过rpc查询user服务数据

go 复制代码
http://127.0.0.1:8881/order/list

改造product模块为rpc

1. 生成proto3文件

go 复制代码
syntax = "proto3";

package product;
option go_package = "./product";
message IdRequest {
  int64 id = 1;
}

message ProductResponse {
  int64 id = 1;
  string name = 2;
  string description = 3;
  float price = 4;
}

service Product {
  rpc GetProductById(IdRequest) returns (ProductResponse);
}

2. 命令生成product rpc

go 复制代码
goctl rpc protoc api/product.proto --go_out=product/rpc --go-grpc_out=product/rpc --zrpc_out=product/rpc

3. order调用添加配置文件

order/etc/order-api.yaml

go 复制代码
ProductRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: product.rpc # 这个 Key 必须和 product 服务注册的 Key 一致

4. 给order.api新增商品名称字段

api/order.api

并且重新生成 order服务模块代码 命令行:goctl api go -api api/order.api -dir order

go 复制代码
	OrderInfo {
		Id       int64  `json:"id"`
		UserId   int64  `json:"userId"`
		UserName string `json:"userName"` // <-- 新增字段,用于存放从 user-rpc 获取的用户名
		//新增商品名称字段
		ProductName string      `json:"productName"`  // 新增字段,用于存放从 product-rpc 获取的商品名称
		TotalPrice  float64     `json:"totalPrice"`
		Status      string      `json:"status"` // e.g., "pending_payment", "paid", "shipped"
		Items       []OrderItem `json:"items"`
		CreateTime  string      `json:"createTime"`
	}

5. config文件新增product rpc配置

路径:order/internal/config/config.go

ProductRpc zrpc.RpcClientConf

go 复制代码
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2

package config

import (
	"github.com/zeromicro/go-zero/rest"
	"github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
	rest.RestConf
	// 新增:要调用的user服务的RPC配置
	UserRpc zrpc.RpcClientConf
	// 新增:要调用的product服务的RPC配置
	ProductRpc zrpc.RpcClientConf
}

6. 声明product rpc服务客户端

order/internal/svc/servicecontext.go

go 复制代码
package svc

import (
	"finejade/shop-mall/order/internal/config"
	"finejade/shop-mall/product/rpc/productclient"

	// 1. 导入生成的 user rpc 客户端包
	//    这个路径是根据你的项目结构和 user.proto 中的 go_package 生成的
	"finejade/shop-mall/user/rpc/userclient"

	"github.com/zeromicro/go-zero/zrpc"
)

type ServiceContext struct {
	Config config.Config
	// 2. 在这里声明一个 UserRpc 客户端实例
	//    它的类型是 userclient.User
	UserRpc    userclient.User
	ProductRpc productclient.Product
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		// 3. 在这里初始化 UserRpc 客户端
		//    zrpc.MustNewClient 会根据配置自动从 Etcd 发现服务并创建连接
		UserRpc:    userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
		ProductRpc: productclient.NewProduct(zrpc.MustNewClient(c.ProductRpc)),
	}
}

测试

go 复制代码
http://127.0.0.1:8883/order/list

常用命令

部分命令可能因为版本问题有变动

命令 主要功能 实例
goctl api new 快速创建新项目骨架 goctl api new user-api
goctl api go 核心:根据 .api 生成 Go 项目代码 goctl api go -api user.api -dir .
goctl api format 格式化 .api 文件 goctl api format api/user.api --dir api
goctl api validate 校验 .api 文件语法 goctl api validate --api api/user.api
goctl api -o 快速创建 *.api 文件,存在提示已存在,不存在则直接创建 goctl api -o example.api
goctl api doc 生成静态 HTML 文档 goctl api doc -api user.api -dir ./docs
goctl api swagger 生成 Swagger (OpenAPI) JSON 文件 goctl api swagger -api user.api -dir .
goctl api dart 为 Flutter 生成 API 调用代码 goctl api dart -api user.api -dir ./dart-api

goctl api format api/user.api --dir api

格式化前

格式化后(对齐了)

检测api语法

bash 复制代码
 goctl api validate --api api/user.api

错误版本

正确版本

快速创建api

go 复制代码
goctl api -o xxx.api
  1. 已存在的文件
  2. 不存在的文件

swagger文档生成

bash 复制代码
goctl api swagger -api  api/user.api -dir ./docs
goctl api swagger -api  api/order.api -dir ./docs

生成静态html文档

bash 复制代码
goctl api doc -api api/user.api -dir ./docs

为 TypeScript 生成 API 调用代码

go 复制代码
 goctl api ts -api api/user.api -dir ./ts-api

swagger接口文档使用

安装

bash 复制代码
go install github.com/swaggo/swag/cmd/swag@latest

参数说明

go-zero支持通过注解丰富Swagger文档内容,主要注解包括:

注解 作用 示例
@summary 接口简短描述 @summary 用户注册接口
@description 接口详细说明 @description 用于新用户注册账号,返回用户ID
@tags 接口分类标签 @tags 用户管理
@accept 请求数据格式 @accept application/json
@produce 响应数据格式 @produce application/json
@param 自定义请求参数 @param Authorization header string true "Bearer token"
@success 成功响应描述 @success 200 {object} RegisterResponse "注册成功"
@failure 错误响应描述 @failure 400 {object} ErrorResponse "参数错误"

带注解的API示例

go 复制代码
service user-api {
  @handler RegisterHandler
  @summary 用户注册接口
  @description 用于新用户注册账号,用户名需3-20个字符,密码需6-32个字符
  @tags 用户管理
  @accept application/json
  @produce application/json
  @param Authorization header string false "Bearer token"
  @success 200 {object} RegisterResponse "注册成功"
  @failure 400 {object} ErrorResponse "参数错误"
  @failure 500 {object} ErrorResponse "服务器内部错误"
  post /api/user/register (RegisterRequest) returns (RegisterResponse)
}

搭建swagger ui

下载
bash 复制代码
https://github.com/swagger-api/swagger-ui/releases

# 或者csdn下载

https://download.csdn.net/download/xxpxxpoo8/92520157
部署

解压后把文件复制到项目根目录下swagger-ui文件夹里

修改接口地址

js 复制代码
window.onload = function() {
  //<editor-fold desc="Changeable Configuration Block">

  // the following lines will be replaced by docker/configurator, when it runs in a docker-container
  window.ui = SwaggerUIBundle({
    url: "http://localhost:8080/docs/user.json",
    dom_id: '#swagger-ui',
    deepLinking: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl
    ],
    layout: "StandaloneLayout"
  });

  //</editor-fold>
};

在根目录下新建serve_swagger.go启动文件

go 复制代码
// serve_swagger.go
package main

import (
	"log"
	"net/http"
)

func main() {
	// 创建一个文件服务器,用于提供当前目录下的所有文件
	fs := http.FileServer(http.Dir("."))
	http.Handle("/", fs)

	log.Println("Serving Swagger UI at http://localhost:8080/swagger-ui/dist/index.html")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

运行

go 复制代码
go run serve_swagger
打开浏览器查看
go 复制代码
http://localhost:8080/swagger-ui/dist/#/default/getUserInfoHandler

docker打包部署

切换到shop/user下运行

go-zero 和goctl是独立分开的

如果 goctl命令未找到请安装goctl go install github.com/zeromicro/go-zero/tools/goctl@latest

1.构建dockerfile文件

在根目录下构建dockerfile文件

bash 复制代码
 goctl docker --go user/user.go --exe user

2.设置国内镜像加速器(大部分没法用了)

如果国外镜像超时,可以使用国内代理

bash 复制代码
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json

daemon.json

目前国内我找到能用的镜像就只有https://docker.1ms.run了

bash 复制代码
{
  "registry-mirrors": [
	"https://docker.1ms.run"
  ]
}

3.构建镜像

bash 复制代码
# 确保在 /root/shop 目录
cd /root/shop

# 重新构建镜像
docker build -t user-api:v1 -f ./user/Dockerfile .
bash 复制代码
FROM golang:alpine AS builder

LABEL stage=gobuilder

ENV CGO_ENABLED 0


RUN apk update --no-cache && apk add --no-cache tzdata

WORKDIR /build
# 在这里添加国内代理
ENV GOPROXY=https://goproxy.cn,direct
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .

RUN go build -ldflags="-s -w" -o /app/user ./user



FROM scratch

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai

WORKDIR /app
COPY --from=builder /app/user /app/user
COPY user/etc /app/etc

CMD ["./user", "-f", "etc/user-api.yaml"]

4. 启动docker服务

go 复制代码
docker run --rm -it -p 8881:8881 user:v1
相关推荐
Tony Bai11 小时前
高并发后端:坚守 Go,还是拥抱 Rust?
开发语言·后端·golang·rust
Rysxt_17 小时前
ThingsBoard RPC订阅教程
mqtt·rpc·thingsboard
小股虫19 小时前
分布式事务:在增长中台,我们如何做到“发出去的内容”和“记录的数据”不打架?
分布式·微服务·云原生·架构·团队建设·方法论
是三好19 小时前
分布式事务seata
java·分布式·seata
DICOM医学影像19 小时前
15. Go-Ethereum测试Solidity ERC20合约 - Go-Ethereum调用合约方法
开发语言·后端·golang·区块链·智能合约·以太坊·web3.0
optimistic_chen19 小时前
【Redis 系列】常用数据结构---Hash类型
linux·数据结构·redis·分布式·哈希算法
yuankunliu20 小时前
【分布式事务】4、分布式事务Seata的高级应用详解
分布式
java1234_小锋20 小时前
ZooKeeper集群中服务器之间是怎样通信的?
分布式·zookeeper·云原生
我要用代码向我喜欢的女孩表白21 小时前
对象存储路径文件1TB以上文件比对,go语言
ios·golang·xcode