Microservices have everything from code to k8s deployment (v. home stay service)

Posted by billybathgate on Mon, 14 Feb 2022 04:06:41 +0100

We will use a series to explain the complete practice of microservices from requirements to online, from code to k8s deployment, from logging to monitoring.

The whole project uses the micro services developed by go zero, which basically includes go zero and some middleware developed by relevant go zero authors. The technology stack used is basically the self-developed component of the go zero project team, which is basically the go zero software.

Actual project address: https://github.com/Mikaelemmmm/go-zero-looklook

1. Business structure diagram of home stay service

2. Dependency

Travel api relies on travel rpc and user center rpc

Usercenter rpc depends on identity rpc

travel is divided into several businesses

  • homestay: home stay
// Home stay module v1 version interface
	prefix: travel/v1
	group: homestay
service travel {
	@doc "Home stay list (preferred for you)"
	@handler homestayList
	post /homestay/homestayList (HomestayListReq) returns (HomestayListResp)
	@doc "Landlord's list of all B & B"
	@handler businessList
	post /homestay/businessList (BusinessListReq) returns (BusinessListResp)
	@doc "Guess you like the home stay list"
	@handler guessList
	post /homestay/guessList (GuessListReq) returns (GuessListResp)
	@doc "B & B details"
	@handler homestayDetail
	post /homestay/homestayDetail (HomestayDetailReq) returns (HomestayDetailResp)
  • Homestay business: home stay
// Interface of v1 version of store module
	prefix: travel/v1
	group: homestayBussiness
service travel {
	@doc "Best landlord"
	@handler goodBoss
	post /homestayBussiness/goodBoss (GoodBossReq) returns (GoodBossResp)
	@doc "Shop list"
	@handler homestayBussinessList
	post /homestayBussiness/homestayBussinessList (HomestayBussinessListReq) returns (HomestayBussinessListResp)
	@doc "Landlord information"
	@handler homestayBussinessDetail
	post /homestayBussiness/homestayBussinessDetail (HomestayBussinessDetailReq) returns (HomestayBussinessDetailResp)
  • homestayComment: home stay comment
// Home stay comment module v1 version interface
	prefix: travel/v1
	group: homestayComment
service travel {
	@doc "Home stay review list"
	@handler commentList
	post /homestayComment/commentList (CommentListReq) returns (CommentListResp)

3. Example: home stay list (preferred for you)

1. api service

1. Write api interface file


type (
	HomestayListReq {
		LastId   int64  `json:"lastId"`
		PageSize int64  `json:"pageSize"`
		RowType  string `json:"rowType"` //preferredHomestay: preferred home stay
	HomestayListResp {
		List []Homestay `json:"list"`


import (

// Home stay module v1 version interface
	prefix: travel/v1
	group: homestay
service travel {
	@doc "Home stay list (preferred for you)"
	@handler homestayList
	post /homestay/homestayList (HomestayListReq) returns (HomestayListResp)

2. goctl generates api code

1) The command line goes to the app/travel/cmd/api/desc directory.

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 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 recommendations are configured in the background, we have created an activity table (here you can also choose to configure them in redis). In short, we first get the configured recommended home stay id from the activity table, and then get the corresponding home stay information list through the id.

2 [tips] mapreduce

It can be seen here that after I get the id set, instead of ordinary foreach getting data one by one, I use go zero to get data for our encapsulated mapreduce. In this way, I can get data concurrently, rather than taking one after it is completed, which greatly shortens the time. I just want to show this function to the build, Some students have to be serious. They can pass an id slice or id arr to rpc, and then get each in rpc concurrently. There's nothing wrong with this. I'm just showing you this function

3. rpc service

Define protobuf file


// model
message Homestay {
    int64   id = 1;
    string  title = 2;
    string  subTitle = 3;
    string  banner = 4;
    string  info = 5;
    int64   peopleNum = 6;            // Number of people
    int64   homestayBusinessId = 7;   // Store id
    int64   userId = 8;               // Landlord id
    int64   rowState = 9;             // 0: off the shelf 1: on the shelf
    int64   rowType = 10;             // Sales type 0: sold by room 1: sold by person time
    string  foodInfo = 11;            // Meal standard
    int64   foodPrice = 12;           // Meal price (points)
    int64   homestayPrice = 13;       // B & B price (points)
    int64   marketHomestayPrice = 14; // Home stay market price (points)

// req ,resp
message HomestayDetailReq {
  int64   id = 1;
message HomestayDetailResp {
  Homestay homestay = 1;

// service
service travel {
    // B & B details
    rpc homestayDetail(HomestayDetailReq) returns(HomestayDetailResp);
  • Using goctl to generate code, you don't need to knock it out manually

    1) From the command line, enter the app/travel/cmd/rpc/pb directory.

    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 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 write logic code

    There is no logic here. Query Findone and return it to the api, because the api is passed through id. then you can see that we have used another artifact copier provided by the gorm author mentioned in the previous chapter. In the previous section, we used it in the api to copy the data of rpc's proto file to the api file. You can see here, We can also copy the data returned by the model to the data of proto. How is it convenient.

4. [tips] model cache, singleflight

Why we don't go to findlist here is because we have a cache in findone method. When we query data one by one according to id, only db will be hit for the first time, and redis cache will be hit at other times. This is not only fast, but also on redis when traffic surges, This will greatly improve the access speed and db support ability of our system.

Generally, we maintain the db cache by ourselves, but go zero uses the model generated by the supporting built-in tool goctl and the code implemented by sqlc+sqlx to realize automatic cache management. We don't need to manage the cache at all. We just need to write sql data with sqlx. sqlc will automatically help us manage the cache 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 at the moment of failure, go zero will only release one thread when querying db. Other threads are waiting. When this thread gets the data back from the database, it will cache the data to redis. At the same time, all previous threads will wait for the data to be shared and returned, When subsequent incoming threads check the same data, they will only enter redis instead of db.

In this way, after rpc gets all the data, it can return to the front-end display.

4. Summary

The other services have no business logic, so we won't explain them one by one here. We basically know what they are by looking at the api documents. We can check them by ourselves according to the example code above. Later, we will explain the complex business involved one by one

Project address



Welcome to go zero and star support us!

Wechat communication group

Focus on the "micro service practice" official account and click on the exchange group to get the community community's two-dimensional code.

Topics: Go Redis