咱们用一个系列来解说从需要到上线、从代码到k8s部署、从日志到监控等各个方面的微服务残缺实际。

整个我的项目应用了go-zero开发的微服务,根本蕴含了go-zero以及相干go-zero作者开发的一些中间件,所用到的技术栈根本是go-zero项目组的自研组件,根本是go-zero全家桶了。

实战我的项目地址:https://github.com/Mikaelemmm...

1、民宿服务业务架构图

2、依赖关系

travel-api(民宿api) 依赖 travel-rpc(民宿rpc)、usercenter-rpc(用户核心rpc)

usercenter-rpc(用户核心rpc)依赖 identity-rpc(受权核心rpc)

travel分为几个业务

  • homestay :民宿房源
// 民宿模块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 : 民宿店家
// 店铺模块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 : 民宿评论
// 民宿评论模块v1版本的接口@server(    prefix: travel/v1    group: homestayComment)service travel {    @doc "民宿评论列表"    @handler commentList    post /homestayComment/commentList (CommentListReq) returns (CommentListResp)}

3、举例:民宿列表(为你优选)

1、api服务

1、写api接口文件

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生成api代码

1)命令行进入app/travel/cmd/api/desc目录下。

2)去我的项目目录下deploy/script/gencode/gen.sh中,复制如下一条命令,在命令行中执行(命令行要切换到app/travel/cmd目录)

$ goctl api go -api *.api -dir ../  -style=goZero

3、关上app/travel/cmd/api/internal/logic/homestay/homestayListLogic.go

因为咱们的举荐是在后盾配置的,所以咱们创立了一个流动表(这里你也能够抉择配置到redis中),总之咱们就是先从流动表中拿到配置的举荐民宿id,而后再通过id去获取对应民宿信息列表。

2【小技巧】 mapreduce

这里能够看到,我拿到了id汇合之后,不是一般的foreach一个个获取,而是应用了go-zero为咱们封装好了的mapreduce获取数据,这样就能够并发去获取数据,而不是要去取一个实现之后再取下一个,工夫上大大缩短了,这里只是想给搭建展现这样一个性能,有的同学非要较真,能够传递一个id slice或者id arr到rpc,而后在rpc中在去并发获取每个,这样也没什么不好,我这里只是给大家展现这个性能

3、rpc服务

定义protobuf文件

app/travel/cmd/rpc/pb/travel.proto

// modelmessage 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 、respmessage HomestayDetailReq {  int64   id = 1;}message HomestayDetailResp {  Homestay homestay = 1;}// serviceservice travel {    // 民宿详情    rpc homestayDetail(HomestayDetailReq) returns(HomestayDetailResp);}
  • 应用goctl生成代码,这里不须要本人手动敲

    1)命令行进入app/travel/cmd/rpc/pb目录下。

    2)去我的项目目录下deploy/script/gencode/gen.sh中,复制如下两条命令,在命令行中执行(命令行要切换到app/travel/cmd目录)

    $ goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../  --zrpc_out=../$ sed -i "" 's/,omitempty//g' *.pb.go
  • 关上app/travel/cmd/rpc/internal/logic/homestayDetailLogic.go写逻辑代码

    这里没什么逻辑,查问Findone,而后返回给api,因为api那边是通过id传递过去的,而后能够看到咱们这边又一次应用了前一章提到的gorm作者提供的另外一款神器copier,上一节是在api中应用,将rpc的proto文件的数据copy到api文件 , 这里能够看到,咱们把model返回的数据copy给proto的数据同样能够用,怎么样是不是很不便。

4、【小技巧】 model cache、singleflight

在这里为什么咱们不去findlist,是因为咱们在findone办法中有缓存,咱们一个个依据id查问数据时候,只有第一次会命中db,其余工夫根本都是命中的redis cache,这样不仅速度快,就算流量激增的时候,也不会全部打到db上,而是都在redis上,这样会大大提高咱们零碎的访问速度以及db撑持能力。

个别咱们本人保护db cache会写的零零散散,然而go-zero应用了配套内置工具goctl生成的model,自带sqlc+sqlx实现的代码,实现了主动缓存治理,咱们基本不须要去治理缓存,只须要用sqlx写 sql数据,sqlc会主动帮咱们治理缓存,并且是通过singleflight ,也就是说即便缓存在某个工夫生效,在生效那一刻同时有大量并发申请进来时,go-zero在查问db时候也只会放行一个线程进来,其余线程是在期待,当这个线程从数据库拿数据回来之后将该数据缓存到redis同时所有之前期待线程共享此数据返回,后续在进来的线程查雷同数据时,就只会进入到redis中而不会进入到db。

这样rpc拿到所有数据之后,就能够返回给前端显示了。

4、小结

其余的几个服务没有业务什么逻辑性的这里就不再一一阐明,看api文档根本都晓得是什么了,依据下面例子代码自行查看即可,前面有牵扯业务简单的中央会逐个阐明

我的项目地址

https://github.com/zeromicro/go-zero

欢送应用 go-zerostar 反对咱们!

微信交换群

关注『微服务实际』公众号并点击 交换群 获取社区群二维码。