微服務框架 go-zero 快速實戰(zhàn)
對于咱們快速了解和將 go-zero 使用起來,我們需要具備如下能力:
基本的環(huán)境安裝和看文檔的能力
Golang 的基本知識
Protobuf 的基本知識
web,rpc 的基本知識
基本的 mysql 知識
其實這些能力,很基礎,不需要多么深入,只需要你有所了解,這樣至少對于咱們?nèi)タ?go-zero 涉及的知識點就不會那么費勁兒
本文分為如下 4 個部分來分別介紹和快速實戰(zhàn)微服務框架 go-zero
微服務框架 go-zero 的基本介紹
go-zero 的環(huán)境搭建
go-zero 的快速實戰(zhàn) rpc , api ,model 部分
微服務框架 go-zero 的基本介紹
go-zero 是一個集成了各種工程實踐的 web 和 rpc 框架。通過彈性設計保障了大并發(fā)服務端的穩(wěn)定性,經(jīng)受了充分的實戰(zhàn)檢驗。
go-zero 中的 api,rpc,數(shù)據(jù)庫等涉及的代碼,都可以給我們一鍵生成,無需耗費我們什么精力
只需要在生成的代碼中填入自己的配置以及邏輯即可,咱們使用 go-zero 可以輕松做到如下效果:
輕松獲得支撐千萬日活服務的穩(wěn)定性
內(nèi)建級聯(lián)超時控制、限流、自適應熔斷、自適應降載等微服務治理能力,無需配置和額外代碼
微服務治理中間件可無縫集成到其它現(xiàn)有框架使用
極簡的 API 描述,一鍵生成各端代碼
自動校驗客戶端請求參數(shù)合法性
大量微服務治理和并發(fā)工具包
對于咱們開發(fā)微服務可謂是極大的提高了開發(fā)效率和質(zhì)量,減少了開發(fā)者的心智負擔
go-zero 官方提供了一張架構圖
從架構圖我們知道,上述的各種效果離不開架構圖中的每一個模塊,本文先展示如下功能的應用:
HTTP 協(xié)議
gRPC 協(xié)議
日志記錄
鏈路追蹤
數(shù)據(jù)庫
ETCD 服務發(fā)現(xiàn)
...
看到 go-zero 有這么多好處,架構圖也非常清晰,是不是有點迫不及待了呢
go-zero 的環(huán)境搭建
不著急,工欲善其事必先利其器,咱們能將 go-zero 玩起來的先決條件是搭建基本的環(huán)境,為了接下來的實戰(zhàn)做鋪墊,咱們需要搭建如下幾個工具
有一臺基本的云服務器最好,虛擬機也沒有問題
安裝 etcd,mysql
安裝 protoc 工具
安裝 goctl 工具
安裝 etcd,mysql
etcd
ETCD_VER=v3.5.0
#?choose?either?URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}
rm?-f?/tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm?-rf?/tmp/etcd-download-test?&&?mkdir?-p?/tmp/etcd-download-test
curl?-L?${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz?-o?/tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar?xzvf?/tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz?-C?/tmp/etcd-download-test?--strip-components=1
rm?-f?/tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
/tmp/etcd-download-test/etcd?--version
/tmp/etcd-download-test/etcdctl?version
/tmp/etcd-download-test/etcdutl?version
安裝完畢后,可以使用 etcdctl version 查看工具的版本
如果想了解 etcd 的基本使用,咱們不著急,本次文章使用不多,無需太過關注 etcd 的細節(jié)
mysql
Linux(centos) 下 Mysql 環(huán)境安裝
安裝 protoc 工具
go?get?-u?github.com/golang/protobuf/protoc-gen-go@v1.3.2
wget?https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-linux-x86_64.zip
unzip?protoc-3.14.0-linux-x86_64.zip
mv?bin/protoc?/usr/local/bin/
安裝完畢后,可以使用 protoc --version 查看工具的版本
安裝 goctl 工具
goctl
讀作 go control
,不要讀成 go C-T-L
。goctl
的意思是不要被代碼控制,而是要去控制它。其中的 go
不是指 golang
安裝咱們 golang 的時候,直接安裝 go 1.16 版本以上的,然后執(zhí)行如下命令即可
GOPROXY=https://goproxy.cn/,direct?go?install?github.com/zeromicro/go-zero/tools/goctl@latest
安裝完畢后,可以使用 goctl --version 查看工具的版本
go-zero 的快速實戰(zhàn)
環(huán)境安裝完畢之后,我們就可以來進行實戰(zhàn)了,剛才有說到 go-zero 是一個集成了各種工程實踐的 web 和 rpc 框架,那么我們就可以來設計 web 部分的接口和 rpc 部分的接口
需求
例如有一個訂單場景,我們需要查詢某個租戶的地址
另外在租戶系統(tǒng)這邊,需要添加租戶
這個時候,我們知道,對于用戶來說,訪問的自然是 http 接口,那對于查詢具體的租戶信息,自然是內(nèi)部微服務來進行處理
一般來說,HTTP 接口對外, RPC 接口對內(nèi)
正如這樣
先來定義 rpc 接口
咱們先建立項目目錄:
mkdir?my_test_demo/mymall?-p
cd?my_test_demo
go?mod?init?my_test_demo
創(chuàng)建租戶的 rpc 模塊
mkdir?mymall/tenant/rpc?-p
cd?mymall/tenant/rpc
編寫 proto 文件
提供兩個 rpc 接口
getTenant
獲取租戶信息
addTenant
添加租戶
tenant.proto
syntax?=?"proto3";
package?tenant;
option?go_package?=?"./tenant";
message?TidReq?{
????string?name?=?1;
}
message?TenantRsp?{
????//?租戶名稱
????string?id?=?1;
????//?租戶名稱
????string?name?=?2;
????//?用戶地址
????string?addr?=?3;
}
message?addTenantReq?{
????//?租戶名稱
????string?name?=?1;
????//?用戶地址
????string?addr?=?2;
}
message?addTenantRsp?{
????//?租戶?id
????string?id?=?1;
}
service?Tenant?{
????rpc?getTenant(TidReq)?returns(TenantRsp);
????rpc?addTenant(addTenantReq)?returns(addTenantRsp);
}
使用 goctl 工具生成 golang 代碼
goctl?rpc?protoc?tenant.proto?--go_out=./protoc?--go-grpc_out=./protoc?--zrpc_out=.
可以看到 goctl 工具給我們生成的代碼目錄是這樣的
├──?etc
│???└──?tenant.yaml
├──?internal
│???├──?config
│???│???└──?config.go
│???├──?logic
│???│???├──?addtenantlogic.go
│???│???└──?gettenantlogic.go
│???├──?server
│???│???└──?tenantserver.go
│???└──?svc
│???????└──?servicecontext.go
├──?protoc
│???└──?tenant
│???????├──?tenant_grpc.pb.go
│???????└──?tenant.pb.go
├──?tenant
│???└──?tenant.go
├──?tenant.go
└──?tenant.proto
這個時候,關于 rpc 自動生成的部分就完成了
定義 api 接口
創(chuàng)建訂單的 api 模塊
回到項目根目錄?my_test_demo
mkdir?mymall/order/api?-p
cd?mymall/order/api
編寫 api
定義一個 Get 方法,url 為 / api /order/get/:name 的 http 接口
order.api
type?(
????????OrderReq?{
????????????????Name?string?`path:"name"`
????????}
????????OrderReply?{
????????????????Id???string?`json:"id"`
????????????????Name?string?`json:"name"`
????????????????Addr?string?`json:"addr"`
????????}
)
service?order?{
????????@handler?getOrder
????????get?/api/order/get/:name?(OrderReq)?returns?(OrderReply)
}
使用 goctl 工具生成代碼
goctl?api?go?-api?order.api??-dir?.
這個時候,我們可以看到,goctl 工具給我們生成的目錄結構和代碼是這個樣子的
├──?etc
│???└──?order.yaml
├──?internal
│???├──?config
│???│???└──?config.go
│???├──?handler
│???│???├──?getorderhandler.go
│???│???└──?routes.go
│???├──?logic
│???│???└──?getorderlogic.go
│???├──?svc
│???│???└──?servicecontext.go
│???└──?types
│???????└──?types.go
├──?order.api
└──?order.go
同樣的, web 部分自動生成的部分就完成了
數(shù)據(jù)庫
創(chuàng)建 model 目錄
回到項目根目錄??my_test_demo
mkdir?mymall/tenant/rpc/protoc/model?-p
cd?mymall/tenant/rpc/protoc/model
編寫 sql
先在 linux 里面進入 mysql,創(chuàng)建一個數(shù)據(jù)庫 test_demo
再創(chuàng)建一張表,表的字段如下面 sql 文件所述
tenant.sql
CREATE?TABLE?`tenant_info`
(
??`id`?varchar(255)?NOT?NULL?COMMENT?'tenant?id',
??`name`?varchar(255)?NOT?NULL?COMMENT?'tenant?name',
??`addr`?varchar(255)?NOT?NULL?COMMENT?'tenant?addr',
??PRIMARY?KEY(`id`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;
向 數(shù)據(jù)表中插入一條數(shù)據(jù),為后續(xù)做準備
insert?into?tenant_info?values("ceshiid",?"約等于公司",?"修羅道哦");
使用 goctl 工具生成 model 部分的代碼
goctl?model?mysql?ddl?-src?tenant.sql?-dir?.
可以看到 goctl 給我們生成的 model 代碼是這個樣子的
├──?tenantinfomodel_gen.go
├──?tenantinfomodel.go
├──?tenant.sql
└──?vars.go
填充邏輯層和配置
Api 部分
修改 mymall/order/api/etc/order.yaml , 加上 etcd 的配置,咱們配置的 rpc 的 key 是 tenant.rpc
Name:?order
Host:?0.0.0.0
Port:?9998
TenantRpc:
??Etcd:
????Hosts:
??????-?127.0.0.1:2379
????Key:?tenant.rpc
修改 ymall/order/api/internal/config/config.go ,Config struct 中加上 rpc 的配置
TenantRpc zrpc.RpcClientConf
修改 mymall/order/api/internal/svc/servicecontext.go ,加上 rpc 的上下文
TenantRpc tenant.Tenant
TenantRpc:tenant.NewTenant(zrpc.MustNewClient(c.TenantRpc)),
修改 mymall/order/api/internal/logic/getorderlogic.go ,對邏輯層加上咱們自定義的邏輯,調(diào)用 rpc 的接口獲取租戶信息
func?(l?*GetOrderLogic)?GetOrder(req?*types.OrderReq)?(resp?*types.OrderReply,?err?error)?{
???//?todo:?add?your?logic?here?and?delete?this?line
rsp?,?err:=l.svcCtx.TenantRpc.GetTenant(l.ctx,?&tenant.TidReq{Name:?req.Name})
???if?err?!=?nil{
??????return?nil,err
???}
???return?&types.OrderReply{
??????Id:?rsp.Id,
??????Name:?rsp.Name,
??????Addr:?rsp.Addr,
???},nil
}
修改 mymall/order/api/internal/handler/getorderhandler.go ,去掉多導入的包
Rpc 部分
修改 mymall/tenant/rpc/etc/tenant.yaml ,加上數(shù)據(jù)源和數(shù)據(jù)表的配置
Name:?tenant.rpc
ListenOn:?127.0.0.1:8080
Etcd:
??Hosts:
??-?127.0.0.1:2379
??Key:?tenant.rpc
DataSource:?root:123456@tcp(localhost:3306)/test_demo
Table:?tenant_info
修改 mymall/tenant/rpc/internal/config/config.go
DataSource string
Table string
修改 mymall/tenant/rpc/internal/svc/servicecontext.go ,添加關于 mysql 的上下文
Model model.TenantInfoModel
Model:model.NewTenantInfoModel(sqlx.NewMysql(c.DataSource)),
修改 mymall/tenant/rpc/protoc/model/tenantinfomodel_gen.go ,新增一個數(shù)據(jù)庫的方法 FindOneByName (這個是根據(jù)業(yè)務自身來選擇是否要加)
FindOneByName(ctx context.Context, name string) (*TenantInfo, error)
func?(m?*defaultTenantInfoModel)?FindOneByName(ctx?context.Context,?name?string)?(*TenantInfo,?error)?{
???query?:=?fmt.Sprintf("select?%s?from?%s?where?`name`?=???limit?1",?tenantInfoRows,?m.table)
???var?resp?TenantInfo
???err?:=?m.conn.QueryRowCtx(ctx,?&resp,?query,?name)
???switch?err?{
???case?nil:
??????return?&resp,?nil
???case?sqlc.ErrNotFound:
??????return?nil,?ErrNotFound
???default:
??????return?nil,?err
???}
}
修改 mymall/tenant/rpc/internal/logic/gettenantlogic.go 填充 GetTenant 的邏輯
效果驗證
打開終端 1 操作 rpc
cd?mymall/tenant/rpc
go?mod?tidy
go?run?tenant.go
打開終端 2 操作 api
cd?mymall/order/api
go?run?order.go
打開終端 3 操作 curl
我們可以先使用 etcdctl 查看一下 tenant.rpc 是否存在
etcdctl?get?tenant.rpc?--prefix
再使用 curl 來請求 api 的接口
curl?-i?"http://localhost:9998/api/order/get/約等于公司"
Api 的日志為
Rpc 的日志
通過上述日志我們知道,對于 api 的請求日志,mysql 的日志,rpc 的日志,咱們都能看到 trace 這個字段,實際上就是通過這個字段來進行鏈路跟蹤的,細心的朋友就可以看到,從 api,到 rpc,到 mysql 這個 trace 字段的值都是同一個, 說明這是同一條調(diào)用鏈上的
其他的細節(jié),咱們后續(xù)再聊
總結
至此,我們了解了 go-zero 微服務框架,快速實戰(zhàn)了一個簡單的 demo,這里我們實際可以體驗到,關于 api,rpc ,或者是 model 層,絕大部分的代碼都是 goctl 生成的,我們需要的就如下幾件事
基本 api ,proto ,sql 的定義
修改 xml 配置 , 和 config.go 的配置
修改 svc 下面的關聯(lián)上下線文
修改 logic 層,填上自己的邏輯
如果對于數(shù)據(jù)庫生成默認的方法,不夠滿足業(yè)務場景,我們也可以依葫蘆畫瓢實現(xiàn)自己的方法,進行使用即可
另外,我們看到咱們定義的 proto 還有一個 addTenant 方法,實際上我們?nèi)崿F(xiàn)的話,可以在 mymall/tenant 下添加 api 目錄,按照上述 api 的添加方式來進行處理即可,感興趣的朋友可以來嘗試一波哦
如果想看源碼的,歡迎訪問地址:https://github.com/qingconglaixueit/my_test_Demo
感謝閱讀,歡迎交流,點個贊,關注一波 再走吧
歡迎點贊,關注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質(zhì)量的動力
好了,本次就到這里
技術是開放的,我們的心態(tài),更應是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵云原生,歡迎點贊關注收藏,下次見~