Thrift is a lightweight, language-independent software stack for point-to-point RPC implementation. Thrift provides clean abstractions and implementations for data transport, data serialization, and application level processing. The code generation system takes a simple definition language as input and generates code across programming languages that uses the abstracted stack to build interoperable RPC clients and servers.
Thrift makes it easy for programs written in different programming languages to share data and call remote procedures. With support for 28 programming languages, chances are Thrift supports the languages that you currently use.
Thrift is specifically designed to support non-atomic version changes across client and server code. This allows you to upgrade your server while still being able to service older clients; or have newer clients issue requests to older servers. An excellent community-provided write-up about thrift and compatibility when versioning an API can be found in the Thrift Missing Guide.
For more details on Thrift’s design and implementation, see the Thrift whitepaper included in this distribution, or at the README.md file in your particular subdirectory of interest.
由于不同的操作系统以及版本上的安装流程不一样,因此需要限定当前的系统环境:
操作系统:从docker库拉取centos7镜像(注:docker指令请自学
)
#docker pull centos:7 // 拉取centos7镜像, 假设镜像ID为"
b5b4d78bc90c
"
#docker run -it b5b4d78bc90c /bin/bash // 启动centos7容器, 假设容器ID为"e78bb3342abe
"
#docker exec -it e78bb3342abe /bin/bash // 进入centos7容器
在centos7容器中执行如下指令安装thrift的依赖库:
#yum -y install automake libtool flex bison pkgconfig gcc-c++ boost-devel libevent-devel zlib-devel ruby-devel openssl-devel python-devel
完成依赖环境的安装后,可在centos7容器中执行如下指令安装thrift程序:
#wget http://archive.apache.org/dist/thrift/0.13.0/thrift-0.13.0.tar.gz
#tar -zxvf thrift-0.13.0.tar.gz
#cd thrift-0.13.0
#./boostrash.sh
#./configure
#make
#make install
在进行编译的过程中,会出现各种问题。相关问题描述和解决方案如下:
g++: error: /usr/lib64/libboost_unit_test_framework.a: No such file or directory
make[4]: *** [Makefile:1275: processor_test] Error 1
make[4]: Leaving directory ‘/root/download/thrift-0.13.0/lib/cpp/test’
make[3]: *** [Makefile:1557: check] Error 2
make[3]: Leaving directory ‘/root/download/thrift-0.13.0/lib/cpp/test’
make[2]: *** [Makefile:1515: check-recursive] Error 1
make[2]: Leaving directory ‘/root/download/thrift-0.13.0/lib/cpp’
make[1]: *** [Makefile:585: check-recursive] Error 1
make[1]: Leaving directory ‘/root/download/thrift-0.13.0/lib’
make: *** [Makefile:686: check-recursive] Error 1
#wget https://golang.org/dl/go1.14.4.linux-amd64.tar.gz
#tar -zxvf go.1.14.4
#mv go /usr/local/src/go
#mkdir -p /data/go/src/
#export GOPATH=/data/go/
#export GOROOT=/usr/local/src/go/
#export PATH=$PATH:$GOROOT/bin/
#yum -y install git
#go get https://github.com/apache/thrift.git
假设当前我们想通过thrift实现的以下功能:
thrift
| - - client
| `-- client.go
| - - example.thrift
` - - server
`-- server.go
namespace go example // go表示golang
struct Data {
1: string text
}
service format_data {
Data do_format(1:Data data),
}
可通过thrift命令对该文件进行处理,生成指定语言的代码。比如生成golang代码:
#thrift --out . --gen go ./example.thrift
package main
import (
"fmt"
"net"
"context"
"github.com/apache/thrift/lib/go/thrift"
"thrift/example"
)
const (
HOST = "127.0.0.1"
PORT = "8080"
)
func main() {
// 与服务端建立TCP长连接
socket, err := thrift.NewTSocket(net.JoinHostPort(HOST, PORT))
if err != nil {
fmt.Printf("Create sokcet failed! errmsg:%s", err.Error())
return
}
// 建立套接字与传输对象的关联
transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())
transport, err := transportFactory.GetTransport(socket)
if nil != err {
fmt.Printf("Get transport failed! errmsg:%s\n", err.Error())
return
}
// 建立传输对象与自定义的远程过程的关联
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
client := example.NewFormatDataClientFactory(transport, protocolFactory)
if err := transport.Open(); err != nil {
fmt.Printf("Open transport failed! errmsg:%s", err.Error())
return
}
defer transport.Close()
// 调用自定义的远程过程
data := example.Data{Text: "hello, world!"}
d, err := client.DoFormat(context.Background(), &data)
if nil != err {
fmt.Printf("Call rpc failed! errmsg:%s", err.Error())
return
}
fmt.Println(d.Text)
}
package main
import (
"context"
"fmt"
"strings"
"github.com/apache/thrift/lib/go/thrift"
"thrift/example"
)
// 实现远程过程
type FormatDataImpl struct{}
func (fdi *FormatDataImpl) DoFormat(ctx context.Context, data *example.Data) (r *example.Data, err error) {
var data example.Data
data.Text = strings.ToUpper(data.Text)
return &data, nil
}
const (
HOST = "127.0.0.1"
PORT = "8080"
)
func main() {
// 新建处理过程对象
handler := &FormatDataImpl{}
processor := example.NewFormatDataProcessor(handler)
// 新建套接字对象
socket, err := thrift.NewTServerSocket(HOST + ":" + PORT)
if err != nil {
fmt.Printf("Create socket failed! errmsg:%s", err.Error())
return
}
// 新建传输对象
transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
// 新建服务对象:将处理过程、套接字、传输对象、协议类型进行关联
server := thrift.NewTSimpleServer4(processor, socket, transportFactory, protocolFactory)
fmt.Printf("Running! host:%s port:%s", HOST, PORT)
// 启动服务
server.Serve()
}
在测试中,客户端能够正常的返回数据。但在实际生产环境中,存在多协程并发访问的情况,只有使用“连接池”才能真正发挥TCP长连接的高效优势。