微服务

在上一篇我们已经演示了怎样快速创建一个单体服务,接下来我们来演示一下如何快速创建微服务, 在本小节中,api部分其实和单体服务的创建逻辑是一样的,只是在单体服务中没有服务间的通讯而已, 且微服务中api服务会多一些rpc调用的配置。

前言

本小节将以一个订单服务调用用户服务来简单演示一下,演示代码仅传递思路,其中有些环节不会一一列举。

情景提要

假设我们在开发一个商城项目,而开发者小明负责用户模块(user)和订单模块(order)的开发,我们姑且将这两个模块拆分成两个微服务①

[!NOTE] ①:微服务的拆分也是一门学问,这里我们就不讨论怎么去拆分微服务的细节了。

演示功能目标

  • 订单服务(order)提供一个查询接口
  • 用户服务(user)提供一个方法供订单服务获取用户信息

服务设计分析

根据情景提要我们可以得知,订单是直接面向用户,通过http协议访问数据,而订单内部需要获取用户的一些基础数据,既然我们的服务是采用微服务的架构设计, 那么两个服务(user,order)就必须要进行数据交换,服务间的数据交换即服务间的通讯,到了这里,采用合理的通讯协议也是一个开发人员需要 考虑的事情,可以通过http,rpc等方式来进行通讯,这里我们选择rpc来实现服务间的通讯,相信这里我已经对”rpc服务存在有什么作用?”已经作了一个比较好的场景描述。 当然,一个服务开发前远不止这点设计分析,我们这里就不详细描述了。从上文得知,我们需要一个

  • user rpc
  • order api

两个服务来初步实现这个小demo。

创建mall工程

  1. $ cd ~/go-zero-demo
  2. $ mkdir mall && cd mall

创建user rpc服务

  • 创建user rpc服务

    1. $ cd ~/go-zero-demo/mall
    2. $ mkdir -p user/rpc && cd user/rpc
  • 添加user.proto文件,增加getUser方法

    1. $ vim ~/go-zero-demo/mall/user/rpc/user.proto
    1. syntax = "proto3";
    2. package user;
    3. message IdRequest {
    4. string id = 1;
    5. }
    6. message UserResponse {
    7. // 用户id
    8. string id = 1;
    9. // 用户名称
    10. string name = 2;
    11. // 用户性别
    12. string gender = 3;
    13. }
    14. service User {
    15. rpc getUser(IdRequest) returns(UserResponse);
    16. }
  • 生成代码

    1. $ cd ~/go-zero-demo/mall/user/rpc
    2. $ goctl rpc proto -src user.proto -dir .
    3. protoc -I=/Users/xx/mall/user user.proto --go_out=plugins=grpc:/Users/xx/mall/user/user
    4. Done.
  • 填充业务逻辑

    1. $ vim internal/logic/getuserlogic.go
    1. package logic
    2. import (
    3. "context"
    4. "go-zero-demo/mall/user/internal/svc"
    5. "go-zero-demo/mall/user/user"
    6. "github.com/tal-tech/go-zero/core/logx"
    7. )
    8. type GetUserLogic struct {
    9. ctx context.Context
    10. svcCtx *svc.ServiceContext
    11. logx.Logger
    12. }
    13. func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
    14. return &GetUserLogic{
    15. ctx: ctx,
    16. svcCtx: svcCtx,
    17. Logger: logx.WithContext(ctx),
    18. }
    19. }
    20. func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
    21. return &user.UserResponse{
    22. Id: "1",
    23. Name: "test",
    24. }, nil
    25. }

创建order api服务

  • 创建 order api服务

    1. $ cd ~/go-zero-demo/mall
    2. $ mkdir -p order/api && cd order/api
  • 添加api文件

    1. $ vim order.api
    1. type(
    2. OrderReq {
    3. Id string `path:"id"`
    4. }
    5. OrderReply {
    6. Id string `json:"id"`
    7. Name string `json:"name"`
    8. }
    9. )
    10. service order {
    11. @handler getOrder
    12. get /api/order/get/:id (OrderReq) returns (OrderReply)
    13. }
  • 生成order服务
    1. $ goctl api go -api order.api -dir .
    2. Done.
  • 添加user rpc配置

    1. $ vim internal/config/config.go
    1. package config
    2. import "github.com/tal-tech/go-zero/rest"
    3. import "github.com/tal-tech/go-zero/zrpc"
    4. type Config struct {
    5. rest.RestConf
    6. UserRpc zrpc.RpcClientConf
    7. }
  • 添加yaml配置

    1. $ vim etc/order.yaml
    1. Name: order
    2. Host: 0.0.0.0
    3. Port: 8888
    4. UserRpc:
    5. Etcd:
    6. Hosts:
    7. - 127.0.0.1:2379
    8. Key: user.rpc
  • 完善服务依赖

    1. $ vim internal/svc/servicecontext.go
    1. package svc
    2. import (
    3. "go-zero-demo/mall/order/api/internal/config"
    4. "go-zero-demo/mall/user/rpc/userclient"
    5. "github.com/tal-tech/go-zero/zrpc"
    6. )
    7. type ServiceContext struct {
    8. Config config.Config
    9. UserRpc userclient.User
    10. }
    11. func NewServiceContext(c config.Config) *ServiceContext {
    12. return &ServiceContext{
    13. Config: c,
    14. UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
    15. }
    16. }
  • 添加order演示逻辑

    getorderlogic添加业务逻辑

    1. $ vim ~/go-zero-demo/mall/order/api/internal/logic/getorderlogic.go
    1. func (l *GetOrderLogic) GetOrder(req types.OrderReq) (*types.OrderReply, error) {
    2. user, err := l.svcCtx.UserRpc.GetUser(l.ctx, &userclient.IdRequest{
    3. Id: "1",
    4. })
    5. if err != nil {
    6. return nil, err
    7. }
    8. if user.Name != "test" {
    9. return nil, errors.New("用户不存在")
    10. }
    11. return &types.OrderReply{
    12. Id: req.Id,
    13. Name: "test order",
    14. }, nil
    15. }

启动服务并验证

  • 启动etcd
    1. $ etcd
  • 启动user rpc

    1. $ go run user.go -f etc/user.yaml
    1. Starting rpc server at 127.0.0.1:8080...
  • 启动order api

    1. $ go run order.go -f etc/order.yaml
    1. Starting server at 0.0.0.0:8888...
  • 访问order api

    1. curl -i -X GET \
    2. http://localhost:8888/api/order/get/1
    1. HTTP/1.1 200 OK
    2. Content-Type: application/json
    3. Date: Sun, 07 Feb 2021 03:45:05 GMT
    4. Content-Length: 30
    5. {"id":"1","name":"test order"}

[!TIP] 在演示中的提及的api语法,rpc生成,goctl,goctl环境等怎么使用和安装,快速入门中不作详细概述,我们后续都会有详细的文档进行描述,你也可以点击下文的【猜你想看】快速跳转的对应文档查看。

源码

mall源码

猜你想看