← 返回文章列表

Go-Zero 微服務框架

學習 go-zero 的框架結構與服務開發流程。

go

簡介

go-zero是一個整合了各種工程實踐的 web 和 rpc 框架。透過彈性設計保障了大併發服務端的穩定性,經受了充分的實戰檢驗。

go-zero 包含極簡的 API 定義和生成工具 goctl,可以根據定義的 api 檔案一鍵生成 Go, iOS, Android, Kotlin, Dart, TypeScript, JavaScript 程式碼,並可直接執行。

go-zero框架能輕鬆獲得支撐千萬日活服務的穩定性,內建級聯超時控制、限流、自適應熔斷、自適應降載等微服務治理能力,無需配置和額外程式碼,微服務治理中介軟體可無縫整合到其它現有框架使用,極簡的 API 描述,一鍵生成各端程式碼,自動校驗客戶端請求引數合法性,大量微服務治理和併發工具包。

go-zero框架具有強大的工具支援,儘可能少的程式碼編寫,極簡的介面,完全相容 net/http,支援中介軟體,方便擴充套件,高效能,面向故障程式設計,彈性設計,內建服務發現、負載均衡,內建限流、熔斷、降載,且自動觸發,自動恢復,API 引數自動校驗,超時級聯控制,自動快取控制,鏈路跟蹤、統計報警等,高併發支撐,穩定保障了疫情期間每天的流量洪峰。

下面是官方給的架構圖

go

安裝和快速使用

安裝

這裡主要是go-zero、goctl和go-zero的安裝指令,可以參照官方的文件:快速開始

注意先安裝go,關於go的安裝和配置可以見部落格:g的安裝和使用

# go-zero安装
go get -u github.com/zeromicro/go-zero@latest
# goctl安装
go install github.com/zeromicro/go-zero/tools/goctl@latest
# protoc安装
goctl env check --install --verbose --force

go

快速使用

Api demo

在這裡我建立了一個資料夾GoZeroDemo存放go-zero微服務框架學習期間的相關程式碼,之後初始化專案,並使用gpctl自動生成簡單API相關檔案

# 创建并进入项目
mkdir GoZeroDemo && cd GoZeroDemo
# 初始化项目并命名
go mod init gozerodemo
# 使用goctl创建API服务
goctl api new greet
# 安装缺失的依赖
go mod tidy

下面是生成的程式碼框架,包括配置檔案、main檔案、配置定義檔案、網路路由相關檔案、請求邏輯檔案、業務邏輯相關檔案以及業務相關結構體檔案等等。

go

之後我們根據官方說明,在greetlogic.go中實現Greet,做簡單的 Say Hello,測試效果如下,一個簡單的單體服務就構建完成了。

go

透過簡單的使用go-zero我們可以發現,框架的作用就是幫你生成配套程式碼,你只需要完成相應的業務邏輯。

gRPC demo

繼續在GoZeroDemo目錄下建立gRPC服務aorange

# 使用goctl创建RPC服务
goctl rpc new aorange
# 安装缺失的依赖
go mod tidy

go

之後按照文件進行簡單修改測試:gRPC-demo

go

MySQL

建立sql檔案,之後透過goctl生成對應的golang檔案和操作方法,具體參考:mysql程式碼生成

goctl model mysql ddl --src user.sql --dir .

go

Mongo

mongo 不像 mysql 一樣有建表語句,索引等集中有規律的約束資訊,因此 mongo 程式碼的生成無需類似 sql 或者資料庫連結一樣的資訊。,具體參考:mongo程式碼生成

goctl model mongo --type user --dir .

go

format

還可以透過goctl進行格式化,具體見:api檔案格式化

goctl api format --dir demo.api

Goctl

下面是goctl相關的指令和說明,我們常用的就是api和rpc

go

Api

go

參考官方給的api示例,我們使用goctl透過api檔案建立服務

首先建立專案資料夾新增user.api

之後在終端輸入指令

goctl api go -api user.api -dir . -style goZero
syntax = "v1"

type (
        // 定义登录接口的 json 请求体
        LoginReq {
                Username string `json:"username"`
                Password string `json:"password"`
        }
        // 定义登录接口的 json 响应体
        LoginResp {
                Id       int64  `json:"id"`
                Name     string `json:"name"`
                Token    string `json:"token"`
                ExpireAt string `json:"expireAt"`
        }
)

type (
        // 定义获取用户信息的 json 请求体
        GetUserInfoReq {
                Id int64 `json:"id"`
        }
        // 定义获取用户信息的 json 响应体
        GetUserInfoResp {
                Id   int64  `json:"id"`
                Name string `json:"name"`
                Desc string `json:"desc"`
        }
        // 定义更新用户信息的 json 请求体
        UpdateUserInfoReq {
                Id   int64  `json:"id"`
                Name string `json:"name"`
                Desc string `json:"desc"`
        }
)

// 定义 HTTP 服务
// @server 语法块主要用于控制对 HTTP 服务生成时 meta 信息,目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
        // 代表当前 service 代码块下的路由生成代码时都会被放到 login 目录下
        group: login
        // 定义路由前缀为 "/v1"
        prefix: /v1
)
// 微服务名称为 user,生成的代码目录和配置文件将和 user 值相关
service user {
        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler login
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/login
        // 请求体为 LoginReq
        // 响应体为 LoginResp,响应体必须有 returns 关键字修饰
        post /user/login (LoginReq) returns (LoginResp)
}

// @server 语法块主要用于控制对 HTTP 服务生成时 meta 信息,目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
        // 代表当前 service 代码块下的所有路由均需要 jwt 鉴权
        // goctl 生成代码时会将当前 service 代码块下的接口
        // 信息添加上 jwt 相关代码,Auth 值为 jwt 密钥,过期
        // 等信息配置的 golang 结构体名称
        jwt: Auth
        // 代表当前 service 代码块下的路由生成代码时都会被放到 user 目录下
        group: user
        // 定义路由前缀为 "/v1"
        prefix: /v1
)
// 注意,定义多个 service 代码块时,服务名称必须一致,因此这里的服务名称必须
// 和上文的 service 名称一样,为 user 服务。
service user {
        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler getUserInfo
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/info
        // 请求体为 GetUserInfoReq
        // 响应体为 GetUserInfoResp,响应体必须有 returns 关键字修饰
        post /user/info (GetUserInfoReq) returns (GetUserInfoResp)

        // 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
        @handler updateUserInfo
        // 定义接口
        // 请求方法为 post
        // 路由为 /user/info/update
        // 请求体为 UpdateUserInfoReq
        // 由于不需要响应体,因此可以忽略不写
        post /user/info/update (UpdateUserInfoReq)
}

go

RPC

go

rpc採用同樣的方式

相關指令和程式碼如下:

goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.
// 声明 proto 语法版本,固定值
syntax = "proto3";

// proto 包名
package greet;

// 生成 golang 代码后的包名
option go_package = "example/proto/greet";

// 定义枚举

enum Status{
  UNSPECIFIED = 0;
  SUCCESS = 1;
  FAILED = 2;
}

// 定义结构体

message Base{
  int32 code = 1;
  string msg = 2;
}

message SendMessageReq{
  string message = 1;
}

message SendMessage{
  // 使用枚举
  Status status = 1;
  // 数组
  repeated string array = 2;
  // map
  map<string,int32> map = 3;
  // 布尔类型
  bool boolean = 4;
  // 序列号保留
  reserved 5;
}

message SendMessageResp{
  Base base = 1;
  SendMessage data = 2;
}

// 定义 Greet 服务
service Greet {
  // 定义客户端流式 rpc
  rpc SendMessage(stream SendMessageReq) returns (SendMessageResp);
}

go

Model

go

以SQL為例,建立sql檔案,透過下面指令生成相關程式碼

goctl model mysql ddl -src"./user.sql" -dir="./sql/model" -c

go

參考資料

go-zero

go-zero官方文件

go的版本管理工具-g的安裝和使用

關於這篇文章的日期

舊日期 2025-01-16 與文章發布記錄不符,現按舊站可確認的首次發布日 2026-01-21 整理。實際創作日期尚無法確認。

原始日期: 2025-01-16 21:15:06 +0800