æ¾ÂÂæ¯对 使ç¨go-zeroå¿«éÂÂæÂÂ建微æÂÂå¡çÂÂ亲æÂÂå®Âè·µ
ç¼ÂÃ¥ÂÂAPI Gateway代ç Â
mkdir bookstore && cd bookstore
go mod init bookstore
mkdir api && goctl api -o api/bookstore.api
syntax = "v1"
info(
title: "xx使ç¨go-zero"
desc: "xxç¨æÂ¥ä¸ÂæÂÂgo-zero"
author: "xxxx"
email: "xxxx@gmail.com"
)
type (
addReq struct {
book string `form:"book"`
price int64 `form:"price"`
}
addResp struct {
ok bool `json:"ok"`
}
)
type (
checkReq struct {
book string `form:"book"`
}
checkResp struct {
found bool `json:"found"`
price int64 `json:"price"`
}
)
service bookstore-api {
@handler AddHandler
get /add (addReq) returns (addResp)
@handler CheckHandler
get /check (checkReq) returns (checkResp)
}
cd api && goctl api go -api bookstore.api -dir .
api
âÂÂâÂÂâ bookstore.api // apiå®Âä¹Â
âÂÂâÂÂâ bookstore.go // mainÃ¥Â
¥å£å®Âä¹Â
âÂÂâÂÂâ etc
â âÂÂâÂÂâ bookstore-api.yaml // éÂ
Âç½®æÂÂ件
âÂÂâÂÂâ internal
âÂÂâÂÂâ config
â âÂÂâÂÂâ config.go // å®Âä¹ÂéÂ
Âç½®
âÂÂâÂÂâ handler
â âÂÂâÂÂâ addhandler.go // å®Âç°addHandler
â âÂÂâÂÂâ checkhandler.go // å®Âç°checkHandler
â âÂÂâÂÂâ routes.go // å®Âä¹Âè·¯ç±å¤ÂçÂÂ
âÂÂâÂÂâ logic
â âÂÂâÂÂâ addlogic.go // å®Âç°AddLogic
â âÂÂâÂÂâ checklogic.go // å®Âç°CheckLogic
âÂÂâÂÂâ svc
â âÂÂâÂÂâ servicecontext.go // å®Âä¹ÂServiceContext
âÂÂâÂÂâ types
âÂÂâÂÂâ types.go // å®Âä¹Â请æ±ÂãÂÂè¿ÂÃ¥ÂÂç»ÂæÂÂä½Â
go run bookstore.go -f etc/bookstore-api.yaml
å¯å¨API GatewayæÂÂå¡ï¼Âé»Â认侦åά8888端å£
å 为é»Â认çÂÂæÂÂçÂÂapi/etc/bookstore-api.yml
为:
Name: bookstore-api
Host: 0.0.0.0
Port: 8888
æÂÂæÂÂ示ä¸Âè½½ï¼ÂÃ¥ÂÂ次è¿Âè¡Â:
{"@timestamp":"2023-02-16T16:31:09.658+08:00","caller":"stat/usage.go:61","content":"CPU: 0m, MEMORY: Alloc=2.5Mi, TotalAlloc=2.5Mi, Sys=14.5Mi, NumGC=0","level":"stat"}
{"@timestamp":"2023-02-16T16:31:09.662+08:00","caller":"load/sheddingstat.go:61","content":"(api) shedding_stat [1m], cpu: 0, total: 0, pass: 0, drop: 0","level":"stat"}
{"@timestamp":"2023-02-16T16:31:15.044+08:00","caller":"stat/metrics.go:210","content":"(bookstore-api) - qps: 0.0/s, drops: 0, avg time: 0.0ms, med: 0.0ms, 90th: 0.0ms, 99th: 0.0ms, 99.9th: 0.0ms","level":"stat"}
ä¼Âå®Âæ¶(é»Â认ä¸ÂÃ¥ÂÂéÂÂ)è¾Âåºcpuï¼ÂÃ¥ÂÂ
Ã¥ÂÂçÂÂçÂÂç»Â计信æ¯ï¼Âå¯以éÂÂè¿Â
logx.DisableStat()
ç¦Âç¨ (å¯以åÂÂå°èªå®Âä¹Â模æ¿.tpléÂÂ)
è¿ÂÃ¥ÂÂçÂÂæ¯nullï¼Â并ä¸Âæ¯é¢ÂæÂÂçÂÂ{"found":false,"price":0}
è¿Âæ¯å 为ï¼Â
respæ¯ä¸Â个æÂÂéÂÂï¼Âè¿Âæ ·ç´æÂÂ¥returnä¼Âæ¯nilï¼ÂéÂÂè¦Âå¦Âä¸Âæ¾å¼Â声æÂÂ
éÂÂå¯æÂÂå¡ï¼ÂÃ¥ÂÂ次åÂÂ起请æ±Âï¼Âè¿Âæ ·çÂÂresponse就符åÂÂé¢ÂæÂÂäºÂ~
ç®åÂÂåªè¿ÂÃ¥ÂÂäºÂ个空å¼ï¼ÂæÂ¥ä¸ÂæÂ¥ä¼Âå¨rpcæÂÂå¡éÂÂå®Âç°ä¸Âå¡é»è¾Â
å¯以修æ¹internal/svc/servicecontext.goæ¥传éÂÂæÂÂå¡ä¾ÂèµÂï¼Âå¦ÂæÂÂéÂÂè¦Â,æ¯Âå¦ÂConfigï¼ÂAuthï¼ÂÃ¥ÂÂç»Âç¨å°çÂÂRPCçÂÂï¼Â
å®Âç°é»è¾Âå¯以修æ¹internal/logicä¸ÂçÂÂ对åºÂæÂÂ件(å¦ÂæÂÂæÂ¥å£è¾Âå¤Âï¼Âå¯以å¨.apiéÂÂå®Âä¹Âä¸ÂÃ¥ÂÂçÂÂgroupï¼Â使ç¨goctlçÂÂæÂÂ代ç Âæ¶ï¼Âä¼Âèªå¨å¨logicä¸Âæ ¹æ®groupÃ¥ÂÂ称åÂÂ建ä¸ÂÃ¥ÂÂçÂÂæÂÂ件夹)
å¯以éÂÂè¿ÂgoctlçÂÂæÂÂÃ¥ÂÂç§Â客æ·端è¯Âè¨ÂçÂÂapiè°Âç¨代ç Â(ä¾Â客æ·端åÂÂå¦使ç¨ï¼Âæ¯æÂÂå¤Âç§Âè¯Âè¨Â)
ç¼ÂÃ¥ÂÂRPC代ç Â
ç¼ÂÃ¥ÂÂadd rpcæÂÂå¡
Ã¥ÂÂå°bookstoreç®å½Âä¸Â
mkdir -p rpc/add && cd rpc/add
goctl rpc template -o add.proto
ä¿®æ¹åÂÂæÂÂ件å 容å¦Âä¸Âï¼Â
syntax = "proto3";
package add;
option go_package = "./pb";
message addReq {
string book = 1;
int64 price = 2;
}
message addResp {
bool ok = 1;
}
service adder {
rpc add(addReq) returns(addResp);
}
goctl rpc protoc add.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.
rpc/add
âÂÂâÂÂâ add.go // rpcæÂÂå¡mainå½æ°
âÂÂâÂÂâ add.proto // rpcæÂ¥å£å®Âä¹Â
âÂÂâÂÂâ adder
â âÂÂâÂÂâ adder.go // æÂÂä¾ÂäºÂå¤Âé¨è°Âç¨æ¹æ³Âï¼Âæ éÂÂä¿®æ¹
â âÂÂâÂÂâ adder_mock.go // mockæ¹æ³Âï¼ÂæµÂè¯Âç¨
â âÂÂâÂÂâ types.go // request/responseç»ÂæÂÂä½Âå®Âä¹Â
âÂÂâÂÂâ etc
â âÂÂâÂÂâ add.yaml // éÂ
Âç½®æÂÂ件
âÂÂâÂÂâ internal
â âÂÂâÂÂâ config
â â âÂÂâÂÂâ config.go // éÂ
Âç½®å®Âä¹Â
â âÂÂâÂÂâ logic
â â âÂÂâÂÂâ addlogic.go // addä¸Âå¡é»è¾Âå¨è¿ÂéÂÂå®Âç°
â âÂÂâÂÂâ server
â â âÂÂâÂÂâ adderserver.go // è°Âç¨åÂ
¥å£, ä¸ÂéÂÂè¦Âä¿®æ¹
â âÂÂâÂÂâ svc
â âÂÂâÂÂâ servicecontext.go // å®Âä¹ÂServiceContextï¼Âä¼ éÂÂä¾ÂèµÂ
âÂÂâÂÂâ pb
âÂÂâÂÂâ add.pb.go
go run add.go -f etc/add.yaml
å¯è¿Âè¡Â该æÂÂå¡
é»Â认æ¯ÂéÂÂä¸ÂÃ¥ÂÂéÂÂè¾ÂåºcpuÃ¥ÂÂå åÂÂä¿¡æ¯
{"@timestamp":"2023-02-16T20:02:10.640+08:00","caller":"stat/usage.go:61","content":"CPU: 0m, MEMORY: Alloc=3.3Mi, TotalAlloc=6.2Mi, Sys=15.9Mi, NumGC=3","level":"stat"}
{"@timestamp":"2023-02-16T20:02:10.656+08:00","caller":"load/sheddingstat.go:61","content":"(rpc) shedding_stat [1m], cpu: 0, total: 0, pass: 0, drop: 0","level":"stat"}
ç¼ÂÃ¥ÂÂcheck rpcæÂÂå¡
Ã¥ÂÂå°bookstoreç®å½Âä¸Â
mkdir -p rpc/check && cd rpc/check
goctl rpc template -o check.proto
ä¿®æ¹åÂÂæÂÂ件å 容å¦Âä¸Âï¼Â
syntax = "proto3";
package check;
option go_package = "./pb";
message checkReq {
string book = 1;
}
message checkResp {
bool found = 1;
int64 price = 2;
}
service checker {
rpc check(checkReq) returns(checkResp);
}
goctl rpc protoc check.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.
rpc/check
âÂÂâÂÂâ check.go // rpcæÂÂå¡mainå½æ°
âÂÂâÂÂâ check.proto // rpcæÂ¥å£å®Âä¹Â
âÂÂâÂÂâ checker
â âÂÂâÂÂâ checker.go // æÂÂä¾ÂäºÂå¤Âé¨è°Âç¨æ¹æ³Âï¼Âæ éÂÂä¿®æ¹
â âÂÂâÂÂâ checker_mock.go // mockæ¹æ³Âï¼ÂæµÂè¯Âç¨
â âÂÂâÂÂâ types.go // request/responseç»ÂæÂÂä½Âå®Âä¹Â
âÂÂâÂÂâ etc
â âÂÂâÂÂâ check.yaml // éÂ
Âç½®æÂÂ件
âÂÂâÂÂâ internal
â âÂÂâÂÂâ config
â â âÂÂâÂÂâ config.go // éÂ
Âç½®å®Âä¹Â
â âÂÂâÂÂâ logic
â â âÂÂâÂÂâ checklogic.go // checkä¸Âå¡é»è¾Âå¨è¿ÂéÂÂå®Âç°
â âÂÂâÂÂâ server
â â âÂÂâÂÂâ checkerserver.go // è°Âç¨åÂ
¥å£, ä¸ÂéÂÂè¦Âä¿®æ¹
â âÂÂâÂÂâ svc
â âÂÂâÂÂâ servicecontext.go // å®Âä¹ÂServiceContextï¼Âä¼ éÂÂä¾ÂèµÂ
âÂÂâÂÂâ pb
âÂÂâÂÂâ check.pb.go
go run check.go -f etc/check.yaml
å¯è¿Âè¡Â该æÂÂå¡
ä¿®æ¹etc/check.yamlçÂÂ端å£为8081ï¼Âå 为8080å·²ç»Â被addæÂÂå¡使ç¨äºÂï¼Â
Ã¥ÂÂÃ¥ÂÂå»修æ¹API Gateway代ç Âï¼Âè°Âç¨add/check rpcæÂÂå¡
api/etc/bookstore-api.yamlï¼Âå¢Âå å¦Âä¸Âå 容
Add:
Etcd:
Hosts:
- localhost:2379
Key: add.rpc
Check:
Etcd:
Hosts:
- localhost:2379
Key: check.rpc
éÂÂè¿Âetcdèªå¨åÂȌÂÂç°å¯ç¨çÂÂaddÃ¥ÂÂcheckæÂÂå¡
ä¿®æ¹api/internal/config/config.goå¦Âä¸Âï¼Âå¢Âå add&checkæÂÂå¡ä¾ÂèµÂ
ä¿®æ¹api/internal/svc/servicecontext.goï¼Âå¦Âä¸Âï¼Â
éÂÂè¿ÂServiceContextå¨ä¸ÂÃ¥ÂÂä¸Âå¡é»è¾Âä¹Âé´传éÂÂä¾ÂèµÂ
(é®ï¼ÂæÂÂä¹Â解å³ä¾ÂèµÂ注堥é®é¢Â)
ä¿®æ¹api/internal/logic/addlogic.goéÂÂçÂÂAddæ¹æ³Âï¼Âå¦Âä¸Âï¼Â
éÂÂè¿Âè°Âç¨adderçÂÂAddæ¹æ³Âå®Âç°添å å¾书å°bookstoreç³»ç»Â
ä¿®æ¹api/internal/logic/checklogic.goéÂÂçÂÂCheckæ¹æ³Âï¼Âå¦Âä¸Âï¼Â
éÂÂè¿Âè°Âç¨checkerçÂÂCheckæ¹æ³Âå®Âç°ä»Âbookstoreç³»ç»Âä¸Âæ¥询å¾书çÂÂä»·æ ¼
å®Âä¹Âæ°æ®åºÂ表ç»ÂæÂÂï¼Â并çÂÂæÂÂCRUD+cache代ç Â
bookstoreä¸ÂÃ¥ÂÂ建rpc/modelç®å½Â
mkdir -p rpc/model
ï¼Âä¸Âè¿Âä¸Âè¬习æ¯æÂÂè¿Â个modelæÂÂ件夹æ½åºæÂ¥ï¼ÂÃ¥ÂÂapiï¼Ârpcå¨ä¸Âå±Âï¼Â
å¨rpc/modelç®å½Âä¸Âç¼ÂÃ¥ÂÂÃ¥ÂÂ建book表çÂÂsqlæÂÂ件book.sqlï¼Âå¦Âä¸Âï¼Â
CREATE TABLE `book`
(
`book` varchar(255) NOT NULL COMMENT 'book name',
`price` int NOT NULL COMMENT 'book price',
PRIMARY KEY(`book`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
è¿Âå ¥mysqlå½令è¡Âï¼ÂÃ¥ÂÂ建DBÃ¥ÂÂtable
create database gozero;
source book.sql;
å¨rpc/modelç®å½Âä¸Âæ§è¡Âå¦Âä¸Âå½令çÂÂæÂÂCRUD+cache代ç Âï¼Â-c表示使ç¨redis cache
goctl model mysql ddl -c -src book.sql -dir .
ä¿®æ¹add rpcÃ¥ÂÂcheck rpcï¼Âè°Âç¨crud+cache代ç Â
ä¿®æ¹rpc/add/etc/add.yamlÃ¥ÂÂrpc/check/etc/check.yamlï¼ÂÃ¥ÂÂå¢Âå å¦Âä¸Âå 容ï¼Â
DataSource: root:123456@@tcp(xxx.xxx.xx.xx:3306)/gozero
#DataSource: root:123456@@tcp(localhost:3306)/gozero?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai #å¯以è¿Âæ ·æÂÂå®Âä¸ÂäºÂÃ¥Â
¶ä»Âä¿¡æ¯
Table: book
Cache:
- Host: localhost:6379
å¯以使ç¨å¤Â个redisä½Â为cacheï¼Âæ¯æÂÂredisÃ¥ÂÂç¹æÂÂè rediséÂÂ群
ä¿®æ¹rpc/add/internal/config.goÃ¥ÂÂrpc/check/internal/config.goï¼Âå¦Âä¸Âï¼Â
ä¿®æ¹rpc/add/internal/svc/servicecontext.goÃ¥ÂÂrpc/check/internal/svc/servicecontext.goï¼Âå¦Âä¸Âï¼Â
ä¿®æ¹rpc/add/internal/logic/addlogic.goï¼Âå¦Âä¸Â
ä¿®æ¹rpc/check/internal/logic/checklogic.goï¼Âå¦Âä¸Âï¼Â
项ç®使ç¨
éÂÂè¦Âå Âå ¨é¨å¯å¨apiæÂÂå¡æÂÂä¾ÂèµÂçÂÂrpcæÂÂå¡ãÂÂå¦ÂæÂÂå Âå¯å¨apiï¼ÂÃ¥ÂÂä¼ÂæÂ¥éÂÂï¼Â
error: context deadline exceeded, make sure rpc service "add.rpc" is already started
å ¨é¨å¯å¨ï¼Â
(Ã¥ÂÂé¢å¯以 -fæÂÂå®Âä¸ÂÃ¥ÂÂç¯å¢ÂçÂÂxxx.yaml)
è°Âç¨add api,æ°å¢Âå¾书
curl -i "http://localhost:8888/add?book=Bible&price=10"
æ¤æ¶çÂÂæ°æ®åºÂï¼Âbook表éÂÂæ°å¢ÂäºÂä¸Âè¡Âæ°æ®
è°Âç¨check api,æ£ÂæÂ¥æÂÂ挾书çÂÂä»·æ ¼
curl -i "http://localhost:8888/check?book=Bible"
éÂÂå¯check rpcï¼ÂÃ¥ÂÂ次æ§è¡Âcurl -i "http://localhost:8888/check?book=Bible"