Kitex的简单使用 | 青训营笔记

508 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第3篇笔记

Kitex可以很方便的帮助我们对服务进行拆分,使得更方便进行团队协作编写代码,本文将通过实现一个极简的注册登录来简单的了解Kitex的使用。

1. 安装Kitex和thriftgo

首先安装go语言环境并配置好代理,参见go语言基础 | 青训营笔记第一部分。然后执行以下命令

go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
go install github.com/cloudwego/thriftgo@latest

添加环境变量,在/etc/profile文件中添加export PATH=~/go/bin:$PATH并执行

source /etc/profile

最后执行下列语句,检查是否安装成功

kitex --version
thriftgo --version

2. 安装etcd

参照etcd Install,先下载etcd,将文件解压到合适的文件夹下,并将该文件目录添加到/etc/profile文件中,然后执行

source /etc/profile

最后执行下列语句,检查是否安装成功

etcd --version

image.png

3. 编写IDL文件

IDL(Interface Definition Language,接口定义语言),对于我们将要实现的极简的注册登录而言,IDL相对比较简单,request只需要用户名和密码,response只需要返回一个status_code和status_msg。

namespace go user

struct BaseResponse {
    1:i64 status_code
    2:string status_msg
}

struct CreateUserResponse {
    1:string username
    2:string password
}

struct CreateUserResponse {
    1:BaseResponse base_resp
}

struct CheckUserRequest {
    1:string username
    2:string password
}

struct CheckUserResponse {
    1:BaseResponse base_resp
}

service UserService {
    CreateUserResponse CreateUser(1:CreateUserRequest req)
    CheckUserResponse CheckUser(1:CheckUserRequest req)
}

4. 使用Kitex生成服务段代码

使用以下命令,module name为demo,service name为user

kitex -module demo -service user user.thrift 

go mod tidy下载所需要的包,因为目前使用的Kitex版本为v0.3.1,需要添加这两条命令

go mod edit -droprequire=github.com/apache/thrift/lib/go/thrift
go mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0

5. 编写服务端代码

  1. main.go
  • 将服务注册到etcd,etcd默认会开启2379端口
r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"})
if err != nil {
    panic(err)
}
  • 指定user服务端口
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:6660")
if err != nil {
    panic(err)
}
  • 完善NewServer方法参数
svr := user.NewServer(new(UserServiceImpl),
    server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "user"}), // server name
    server.WithServiceAddr(addr),                                                // address
    server.WithRegistry(r),
)
  • 设置一个全局变量存放用户名和密码,在main函数里初始化
var Users map[string]string
Users := make(map[string]string)
  1. handler.go
  • CreateUser函数

先new一个CreateUserResponse的对象,检查Users的map中是否以及存在req中的username,若有,返回相应的状态码和信息,若没有,将username和password加入map,并返回注册成功的状态码和信息。

resp = new(user.CreateUserResponse)

_, ok := Users[req.Username]

if ok {
    resp.BaseResp = &user.BaseResponse{
        StatusCode: 1,
        StatusMsg:  "用户名已被使用",
    }
} else {
    Users[req.Username] = req.Password
    resp.BaseResp = &user.BaseResponse{
        StatusCode: 0,
        StatusMsg:  "注册成功",
    }
}

return resp, nil
  • CheckUser函数

先new一个CreateUserResponse的对象,检查Users的map中是否以及存在req中的username,若有,检查密码是否与req中的password相同,若相同,则返回登录成功的状态码和信息,否则,返回其他相应的状态码和信息。

resp = new(user.CheckUserResponse)

password, ok := Users[req.Username]
if ok {
    if password == req.Password {
        resp.BaseResp = &user.BaseResponse{
            StatusCode: 0,
            StatusMsg:  "登录成功",
        }
    } else {
        resp.BaseResp = &user.BaseResponse{
            StatusCode: 1,
            StatusMsg:  "用户名或密码错误",
	}
    }
} else {
    resp.BaseResp = &user.BaseResponse{
        StatusCode: 1,
        StatusMsg:  "用户不存在",
    }
}

return resp, nil

6. 编写客户端代码

创建rpc目录,在该目录下user.go文件中编写客户端代码, 从etcd发现服务,etcd默认会开启2379端口

package rpc

import (
    "context"
    "demo/kitex_gen/user"
    "demo/kitex_gen/user/userservice"

    "github.com/cloudwego/kitex/client"
    etcd "github.com/kitex-contrib/registry-etcd"
)

var userClient userservice.Client

func InitRPC() {
    r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"})
    if err != nil {
        panic(err)
    }

    c, err := userservice.NewClient("user", client.WithResolver(r))
    if err != nil {
        panic(err)
    }
    userClient = c
}

func CreateUser(ctx context.Context, req *user.CreateUserRequest) (resp *user.CreateUserResponse, err error) {
    return userClient.CreateUser(ctx, req)
}

func CheckUser(ctx context.Context, req *user.CheckUserRequest) (resp *user.CheckUserResponse, err error) {
    return userClient.CheckUser(ctx, req)
}

7. 编写HTTP Server代码

创建http目录,在该目录下server.go文件中编写客户端代码

package main

import (
    "context"
    "demo/kitex_gen/user"
    "demo/rpc"

    "github.com/gin-gonic/gin"
)

func main() {
    rpc.InitRPC()
    r := gin.Default()
    r.POST("/register", func(c *gin.Context) {
        username := c.Query("username")
        password := c.Query("password")
	resp, err := rpc.CreateUser(context.Background(), &user.CreateUserRequest{
            Username: username,
            Password: password,
        })
        if err != nil {
            c.JSON(200, gin.H{
                "status_code": 1,
		"status_msg":  "服务错误",
            })
	}

	c.JSON(200, gin.H{
            "status_code": resp.BaseResp.StatusCode,
            "status_msg":  resp.BaseResp.StatusMsg,
        })
    })
    r.POST("/login", func(c *gin.Context) {
        username := c.Query("username")
	password := c.Query("password")
	resp, err := rpc.CheckUser(context.Background(), &user.CheckUserRequest{
            Username: username,
            Password: password,
        })
	if err != nil {
            c.JSON(200, gin.H{
                "status_code": 1,
		"status_msg":  "服务错误",
            })
	}

	c.JSON(200, gin.H{
            "status_code": resp.BaseResp.StatusCode,
            "status_msg":  resp.BaseResp.StatusMsg,
	})
    })
    r.Run()
}

8. 运行

  1. 启动etcd
etcd
  1. 启动user服务
sh build.sh
sh output/bootstrap.sh
  1. 启动http服务
go run http/server.go

9. postman测试

  1. 注册接口

image.png

  1. 登录接口

image.png