We use a series to explain the complete practice of microservices from requirements to online, from code to k8s deployment, from logging to monitoring, etc.
The whole project uses microservices developed by go-zero, which basically includes go-zero and some middleware developed by related go-zero authors. The technology stack used is basically the self-developed components of the go-zero project team, basically go -zero the whole family bucket.
Actual project address: https://github.com/Mikaelemmmm/go-zero-looklook
1. Business architecture diagram of homestay service
2. Dependencies
travel-api (homestay api) depends on travel-rpc (homestay rpc), usercenter-rpc (user center rpc)
usercenter-rpc (user center rpc) depends on identity-rpc (authorization center rpc)
travel is divided into several businesses
- homestay : Homestay listings
// 民宿模块v1版本的接口
@server(
prefix: travel/v1
group: homestay
)
service travel {
@doc "民宿列表(为你优选)"
@handler homestayList
post /homestay/homestayList (HomestayListReq) returns (HomestayListResp)
@doc "房东所有民宿列表"
@handler businessList
post /homestay/businessList (BusinessListReq) returns (BusinessListResp)
@doc "猜你喜欢民宿列表"
@handler guessList
post /homestay/guessList (GuessListReq) returns (GuessListResp)
@doc "民宿详情"
@handler homestayDetail
post /homestay/homestayDetail (HomestayDetailReq) returns (HomestayDetailResp)
}
- homestayBusiness : Homestay shop
// 店铺模块v1版本的接口
@server(
prefix: travel/v1
group: homestayBussiness
)
service travel {
@doc "最佳房东"
@handler goodBoss
post /homestayBussiness/goodBoss (GoodBossReq) returns (GoodBossResp)
@doc "店铺列表"
@handler homestayBussinessList
post /homestayBussiness/homestayBussinessList (HomestayBussinessListReq) returns (HomestayBussinessListResp)
@doc "房东信息"
@handler homestayBussinessDetail
post /homestayBussiness/homestayBussinessDetail (HomestayBussinessDetailReq) returns (HomestayBussinessDetailResp)
}
- homestayComment : Homestay comment
// 民宿评论模块v1版本的接口
@server(
prefix: travel/v1
group: homestayComment
)
service travel {
@doc "民宿评论列表"
@handler commentList
post /homestayComment/commentList (CommentListReq) returns (CommentListResp)
}
3. Example: Homestay list (preferred for you)
1. api service
1. Write the api interface file
app/travel/cmd/api/desc/homestay/homestay.api
type (
HomestayListReq {
LastId int64 `json:"lastId"`
PageSize int64 `json:"pageSize"`
RowType string `json:"rowType"` //preferredHomestay:优选民宿
}
HomestayListResp {
List []Homestay `json:"list"`
}
)
app/travel/cmd/api/desc/travel.api
import (
"homestay/homestay.api"
....
)
// 民宿模块v1版本的接口
@server(
prefix: travel/v1
group: homestay
)
service travel {
@doc "民宿列表(为你优选)"
@handler homestayList
post /homestay/homestayList (HomestayListReq) returns (HomestayListResp)
......
}
2. goctl generates api code
1) Enter the app/travel/cmd/api/desc directory from the command line.
2) Go to deploy/script/gencode/gen.sh in the project directory, copy the following command and execute it on the command line (the command line should be switched to the app/travel/cmd directory)
$ goctl api go -api *.api -dir ../ -style=goZero
3. Open app/travel/cmd/api/internal/logic/homestay/homestayListLogic.go
Because our recommendation is configured in the background, we created an activity table (here you can also choose to configure it into redis). In short, we first get the configured recommended homestay id from the activity table, and then go to the Get a list of corresponding homestay information.
2 [Tips] mapreduce
As you can see here, after I get the id set, instead of getting the ordinary foreach one by one, I use go-zero to get the data for our packaged mapreduce, so that I can get the data concurrently instead of getting it. After one is completed, the next one is taken out, which greatly shortens the time. Here, I just want to show such a function to the building. Some students have to be serious. They can pass an id slice or id arr to the rpc, and then go to the rpc to get it concurrently. Everyone, there's nothing wrong with this, I'm just showing you this function here
3. RPC service
Define protobuf file
app/travel/cmd/rpc/pb/travel.proto
// model
message Homestay {
int64 id = 1;
string title = 2;
string subTitle = 3;
string banner = 4;
string info = 5;
int64 peopleNum = 6; // 容纳人的数量
int64 homestayBusinessId = 7; // 店铺id
int64 userId = 8; // 房东id
int64 rowState = 9; // 0:下架 1:上架
int64 rowType = 10; // 售卖类型0:按房间出售 1:按人次出售
string foodInfo = 11; // 餐食标准
int64 foodPrice = 12; // 餐食价格(分)
int64 homestayPrice = 13; // 民宿价格(分)
int64 marketHomestayPrice = 14; // 民宿市场价格(分)
}
// req 、resp
message HomestayDetailReq {
int64 id = 1;
}
message HomestayDetailResp {
Homestay homestay = 1;
}
// service
service travel {
// 民宿详情
rpc homestayDetail(HomestayDetailReq) returns(HomestayDetailResp);
}
Use goctl to generate code, you don't need to manually type here
1) Enter the app/travel/cmd/rpc/pb directory from the command line.
2) Go to deploy/script/gencode/gen.sh in the project directory, copy the following two commands, and execute them on the command line (the command line should be switched to the app/travel/cmd directory)
$ goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../ --zrpc_out=../ $ sed -i "" 's/,omitempty//g' *.pb.go
Open app/travel/cmd/rpc/internal/logic/homestayDetailLogic.go to write logic code
There is no logic here, query Findone, and then return it to the api, because the api side is passed by id, and then we can see that we use another artifact copier provided by the author of gorm mentioned in the previous chapter again, The previous section is used in the api. Copy the data of the proto file of the rpc to the api file. Here you can see that we can also use the data returned by the model to copy the data of the proto, how is it very convenient?
4. [Tips] model cache, singleflight
The reason why we don't go to findlist here is because we have a cache in the findone method. When we query data one by one according to the id, only the first time the db will be hit, and the other times are basically the hit redis cache, which is not only fast, but also Even when the traffic surges, it will not all hit the db, but all on the redis, which will greatly improve the access speed of our system and the db support capability.
Generally, we maintain the db cache by ourselves, but go-zero uses the model generated by the supporting built-in tool goctl, and comes with the code implemented by sqlc+sqlx, which realizes automatic cache management, and we do not need to manage the cache at all. , you only need to use sqlx to write sql data, sqlc will automatically help us manage the cache, and it is through singleflight , that is to say, even if the cache fails at a certain time, when a large number of concurrent requests come in at the same time, go-zero is querying When db is used, only one thread will be released, and other threads are waiting. When this thread retrieves the data from the database, the data is cached in redis, and all the waiting threads share the data before returning, and the incoming thread will check the same data later. , it will only enter redis but not db.
In this way, after rpc gets all the data, it can be returned to the front end for display.
4. Summary
The other services have no business logic and will not be explained here. You can basically know what they are by looking at the api documentation. You can view it by yourself according to the above example code.
project address
https://github.com/zeromicro/go-zero
Welcome go-zero
and star support us!
WeChat exchange group
Follow the official account of " Microservice Practice " and click on the exchange group to get the QR code of the community group.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。