Thrift与golang应用

Apache Thrift是一种流行的远程服务调用框架,它采用接口描述定义并创建服务,它的特定是支持多种语言,可以指定多种传输协议、传输层与服务类型快速创建高效服务。

Thrift

数据类型

基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:未知编码文本或二进制字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:
service:对应服务的类

协议

  • TBinaryProtocol — 二进制编码格式进行数据传输
  • TCompactProtocol — 高效率的、密集的二进制编码格式进行数据传输
  • TJSONProtocol — 使用 JSON 的数据编码协议进行数据传输
  • TSimpleJSONProtocol — 只提供 JSON 只写的协议,适用于通过脚本语言解析

传输层

  • TSocket — 使用阻塞式 I/O 进行传输,是最常见的模式
  • TFramedTransport — 使用非阻塞方式,按块的大小进行传输,类似于 Java 中的 NIO
  • TNonblockingTransport — 使用非阻塞方式,用于构建异步客户端

服务类型

  • TSimpleServer — 单线程服务器端使用标准的阻塞式 I/O
  • TThreadPoolServer — 多线程服务器端使用标准的阻塞式 I/O
  • TNonblockingServer — 多线程服务器端使用非阻塞式 I/O

架构图

定义Thrift文件

Base.thrift文件为API基类描述:

namespace java com.qiknow.proto

/**
 * 请求头信息
 */
struct ReqHeader{
    /**
     * Token
     */
    1: string token
}

/**
 * 用户信息
 */
struct UserInfo{
    /**
     * 头像
     */
    1: string headImgPath
    /**
     * 用户姓名
     */
    2: string name
    /**
     * 昵称
     */
    3: string nickname
    /**
     * 性别(1男,2女,0未知)
     */
    4: i32 gender
    /**
     * 电话
     */
    5: string phoneNo
    /**
     * 用户的标签
     */
    6: list<string> tags
    /**
     * 用户ID
     */
    7: i64 userId
    /**
     * 用户关系。1:其他关系,2:我的关注者,3:关注我的人,4:互相关注,5:好友关系,
     */
    8: i32 relationship
}

Req.thrift为请求描述:

include "Base.thrift"
namespace java com.qiknow.proto

/**
 * 加好友请求参数
 */
struct AddFriendReq{
    1: Base.ReqHeader header
    /**
     * 申请者用户ID
     */
    2: i64 requesterId
    /**
     * 被申请者用户ID
     */
    3: i64 approverId
    /**
     * 加好友备注信息
     */
    4: string comments
}

Resp.thrift为返回描述:

include "Base.thrift"
namespace java com.qiknow.proto

struct AddFriendResp {
    /**
     * 状态码
     */
    1: i32 status
    /**
     * 返回结果描述
     */
    2: string msg
}

UserService.thrift为服务接口描述:

include "Req.thrift"
include "Resp.thrift"

namespace java com.qiknow.proto

/**<pre>
描述:账号服务,包括登录的、登出、获取验证码、修改密码、用户信息等相关功能接口
</pre> */   
service UserService{

    /**<pre>
    描述:申请加好友
    参数:申请加好友参数
    结果:返回申请结果
    认证方式:Token
    </pre> */
    Resp.AddFriendResp AddFriend(1: Req.AddFriendReq req)

}

生成代码

使用thrift生成代码

thrift --gen go -out proto/ idl/UserService.thrift
thrift --gen go -out proto/ idl/Resp.thrift
thrift --gen go -out proto/ idl/Req.thrift
thrift --gen go -out proto/ idl/Base.thrift

编写代码

获取git.apache.org/thrift.git/lib/go/thrift依赖

go get git.apache.org/thrift.git/lib/go/thrift

创建对应的Handler

package handler

import (
    "thrift/proto/req"
    "thrift/proto/resp"
)
type UserHandler struct {
}

func NewUserHandler() *UserHandler {
    return &UserHandler{}
}


// <pre>
// 描述:申请加好友
// 参数:申请加好友参数
// 结果:返回申请结果
// 认证方式:Token
// </pre>
//
// Parameters:
//  - Req
func (p *UserHandler) AddFriend(req *req.AddFriendReq) (r *resp.AddFriendResp, err error) {
    return &resp.AddFriendResp{},nil
}

测试

package handler

import (
    "testing"
    "thrift/proto/req"
    "thrift/proto/resp"
    "thrift/proto/userservice"
    "time"

    "git.apache.org/thrift.git/lib/go/thrift"
    "github.com/stretchr/testify/assert"
)

const SERVER_ADDRESS = "127.0.0.1:56783"

func init() {
    testing
    transportFactory := thrift.NewTTransportFactory()
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
    go runServer(transportFactory, protocolFactory, SERVER_ADDRESS)
    time.Sleep(time.Second)
}

// runServer 启动服务器
func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string) error {
    var transport thrift.TServerTransport
    var err error
    transport, err = thrift.NewTServerSocket(addr)
    if err != nil {
        return err
    }
    handler := NewUserHandler()
    processor := userservice.NewUserServiceProcessor(handler)
    server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)
    return server.Serve()
}

func TestServer(t *testing.T) {
    var (
        friendResp *resp.AddFriendResp
    )
    // 建立连接
    var transport, err = thrift.NewTSocket(SERVER_ADDRESS)
    assert.NoError(t, err)
    assert.NotNil(t, transport)
    client := userservice.NewUserServiceClientFactory(transport, thrift.NewTBinaryProtocolFactoryDefault())
    assert.NotNil(t, client)
    err = transport.Open()
    assert.NoError(t, err)
    friendResp, err = client.AddFriend(&req.AddFriendReq{
        RequesterId: 100001,
        ApproverId:  100002,
    })
    assert.NotNil(t, friendResp)
    assert.NoError(t, err)
}

Apache Thrift – 可伸缩的跨语言服务开发框架

Leave a Reply

Your email address will not be published. Required fields are marked *