SlideShare une entreprise Scribd logo
1  sur  6
Télécharger pour lire hors ligne
Thrift 服务(Server)复用的设计与实现
作者:billowqiu@163.com

介绍
Thrift 作为一个跨语言的 rpc 框架,为后端服务间的多语言混合开发提供了高可靠,可
扩展,以及高效的实现。但是自从 2007 年 Facebook 开源后的 6 年时间内一直缺少一个多路
复用的功能(Multiplexing Services),也就是在一个 Server 上面实现多个 Service 调用。比如
要实现一个后端服务,很多时候不仅仅只是实现业务服务接口,往往还会预留一些调试,
监
控服务接口,以往要实现多个 Service 在一个 Server 上面调用,要么将多个服务糅合成一个
庞大的服务(图 1)
,要么将多个 Service 分摊到不同的 Server 上(图 2)
。最近的版本 0.9.1
终于实现内置的多路复用,
本文简要分析一下该功能的设计与实现,
并提供一个简单的示例。

图1
图2



第一种方式将所有的接口放到一个服务中,会导致新接口增加时的代码维护成本



第二种方式采取将不同的 Service 绑定到不同的 Server,因为多个 Server 会监听多个端
口,最后导致运维方面的管理和维护成本增加(端口在某些时候是一个有限资源)

设计
Thrift 的架构如下:

图3

Thrift 采取了很优雅的分层设计,下面简述各层的主要功能:


Transport
负责传输数据的接口,有文件,内存,套接字等实现。



Protocol
负责数据的协议交互接口,有二进制,Json 等实现。



Processor
负责输入输出数据处理的接口,其实就是对 Protocol 的处理。



Server
包括了上面各层的创建和管理,
并提供网络服务的功能,
网络服务这块目前有四个实现,

分别是最简单的单线程阻塞,多线程阻塞,线程池阻塞和基于 libevent 的非阻塞模式。
实现多路复用有以下几个需要注意的地方:



代码接口兼容



协议实现兼容



不依赖任何 Server 层代码,也不需要新的 Server 实现

0.9.1 之前版本不能多个 Service 在同一个 Server 上面调用,
主要是因为在协议层只把 Service
的函数名打包,
没有将 ServiceName 打包进去,
所以在 Processor 层默认只能处理一个 Service。
新版本中通过新增以下设计(红色部分)完成了 Service 的多路复用:
图4

图5



Client 增加一个 MultiplexProtcol 实现,在原有协议基础上增加 ServiceName 的打包



Server 增加一个 MultiplexProssor 实现,分离不同的具体服务

实现
从 Release-Notes 看到目前已经有 Java,Delphi,C#,C++几个语言实现了该功能,具体到
C++实现按照 THRIFT-1902 的介绍,是直接移植的 java 版本。

新增代码
protocol/TMultiplexedProtocol.h
protocol/TMultiplexedProtocol.cpp
protocol/TProtocolDecorator.h
processor/TMultiplexedProcessor.h

主要逻辑
1)

TMultiplexedProtocol 类重写 writeMessageBegin_virt 方法, Service 的函数名前新增了
在
ServiceName,并附带了一个分隔符;该类采取了 Decorator 模式将绝大部分操作转发到
实际的 protocol 对象。

2)

TMultiplexedProcessor 类增加了一个存放 service 的 map,
typedef std::map< std::string, shared_ptr<TProcessor> > services_t;

key 为 ServiceName , 这 样 在 process 方 法 中 先 解 出 TMultiplexedProtocol 传 递 过 来 的
ServiceName,
通过该 key 查找到对应的 Processor 对象,
再调用该 Processor 的 process 方法,
这样就完美的实现了多个 serivice 的共存。

使用示例
IDL:
namespace cpp thrift.multiplex.demo
service FirstService
{
void blahBlah()
}
service SecondService
{
void blahBlah()
}
Server:
int port = 9090;
shared_ptr<TProcessor> processor1(new FirstServiceProcessor
(shared_ptr<FirstServiceHandler>(new FirstServiceHandler())));
shared_ptr<TProcessor> processor2(new SecondServiceProcessor
(shared_ptr<SecondServiceHandler>(new SecondServiceHandler())));
//使用 MultiplexedProcessor
shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
//注册各自的 Service
processor->registerProcessor("FirstService", processor1);
processor->registerProcessor("SecondService", processor2);
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
Client:
shared_ptr<TSocket> transport(new TSocket("localhost", 9090));
transport->open();
shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
shared_ptr<TMultiplexedProtocol> mp1(new TMultiplexedProtocol(protocol, "FirstService"));
shared_ptr<FirstServiceClient> service1(new FirstServiceClient(mp1));
shared_ptr<TMultiplexedProtocol> mp2(new TMultiplexedProtocol(protocol, "SecondService"));
shared_ptr<SecondServiceClient> service2(new SecondServiceClient(mp2));
service1->blahBlah();
service2->blahBlah();

总结
Thrift 通过在客户端采取的 decorator 模式巧妙的在协议层将 ServiceName 传递到服务端,服
务端通过常见的手段将 ServiceName 和具体的 Processor 进行映射,完美的解决了 Server 对
Service 的多路复用问题。

参考资料
1.
2.
3.
4.

http://thrift.apache.org/docs/concepts/
https://issues.apache.org/jira/browse/THRIFT-1902
https://issues.apache.org/jira/browse/THRIFT-563
http://bigdata.impetus.com/whitepaper

Contenu connexe

Similaire à Thrift多路复用的设计与实现

Subversion快速入门教程
Subversion快速入门教程Subversion快速入门教程
Subversion快速入门教程wensheng wei
 
Paas研究介绍
Paas研究介绍Paas研究介绍
Paas研究介绍snakebbf
 
微博基于Docker的混合云平台设计与实践
微博基于Docker的混合云平台设计与实践微博基于Docker的混合云平台设计与实践
微博基于Docker的混合云平台设计与实践Weibo Corporation
 
從SOA到REST -- Web Service、WCF、WebAPI的應用情境
從SOA到REST -- Web Service、WCF、WebAPI的應用情境從SOA到REST -- Web Service、WCF、WebAPI的應用情境
從SOA到REST -- Web Service、WCF、WebAPI的應用情境MIS2000 Lab.
 
0506 Windows Server 2008 終端機服務
0506 Windows Server 2008 終端機服務0506 Windows Server 2008 終端機服務
0506 Windows Server 2008 終端機服務Timothy Chen
 
Dev ops 簡介
Dev ops 簡介Dev ops 簡介
Dev ops 簡介hugo lu
 
DevOps Days Taipei 2018
DevOps Days Taipei 2018DevOps Days Taipei 2018
DevOps Days Taipei 2018Cobra Chen
 
Asp.net mvc 4 web api 開發簡介
Asp.net mvc 4 web api 開發簡介Asp.net mvc 4 web api 開發簡介
Asp.net mvc 4 web api 開發簡介Gelis Wu
 
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性liu sheng
 
Ce07ncs002006000056
Ce07ncs002006000056Ce07ncs002006000056
Ce07ncs002006000056jbcinvest
 
新浪微博大规模基于Docker的混合云应用实践 -王关胜
新浪微博大规模基于Docker的混合云应用实践 -王关胜新浪微博大规模基于Docker的混合云应用实践 -王关胜
新浪微博大规模基于Docker的混合云应用实践 -王关胜Weibo Corporation
 
Exchange server 2010规划与设计
Exchange server 2010规划与设计Exchange server 2010规划与设计
Exchange server 2010规划与设计popskf
 

Similaire à Thrift多路复用的设计与实现 (12)

Subversion快速入门教程
Subversion快速入门教程Subversion快速入门教程
Subversion快速入门教程
 
Paas研究介绍
Paas研究介绍Paas研究介绍
Paas研究介绍
 
微博基于Docker的混合云平台设计与实践
微博基于Docker的混合云平台设计与实践微博基于Docker的混合云平台设计与实践
微博基于Docker的混合云平台设计与实践
 
從SOA到REST -- Web Service、WCF、WebAPI的應用情境
從SOA到REST -- Web Service、WCF、WebAPI的應用情境從SOA到REST -- Web Service、WCF、WebAPI的應用情境
從SOA到REST -- Web Service、WCF、WebAPI的應用情境
 
0506 Windows Server 2008 終端機服務
0506 Windows Server 2008 終端機服務0506 Windows Server 2008 終端機服務
0506 Windows Server 2008 終端機服務
 
Dev ops 簡介
Dev ops 簡介Dev ops 簡介
Dev ops 簡介
 
DevOps Days Taipei 2018
DevOps Days Taipei 2018DevOps Days Taipei 2018
DevOps Days Taipei 2018
 
Asp.net mvc 4 web api 開發簡介
Asp.net mvc 4 web api 開發簡介Asp.net mvc 4 web api 開發簡介
Asp.net mvc 4 web api 開發簡介
 
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性
20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性
 
Ce07ncs002006000056
Ce07ncs002006000056Ce07ncs002006000056
Ce07ncs002006000056
 
新浪微博大规模基于Docker的混合云应用实践 -王关胜
新浪微博大规模基于Docker的混合云应用实践 -王关胜新浪微博大规模基于Docker的混合云应用实践 -王关胜
新浪微博大规模基于Docker的混合云应用实践 -王关胜
 
Exchange server 2010规划与设计
Exchange server 2010规划与设计Exchange server 2010规划与设计
Exchange server 2010规划与设计
 

Plus de billowqiu

Eugene letuchy erlangatfacebook
Eugene letuchy erlangatfacebookEugene letuchy erlangatfacebook
Eugene letuchy erlangatfacebookbillowqiu
 
分布式文件系统FastDFS架构剖析
分布式文件系统FastDFS架构剖析分布式文件系统FastDFS架构剖析
分布式文件系统FastDFS架构剖析billowqiu
 
On designing and deploying internet scale services
On designing and deploying internet scale servicesOn designing and deploying internet scale services
On designing and deploying internet scale servicesbillowqiu
 
基于Zookeeper的配置信息存储方案的设计与实现
基于Zookeeper的配置信息存储方案的设计与实现基于Zookeeper的配置信息存储方案的设计与实现
基于Zookeeper的配置信息存储方案的设计与实现billowqiu
 
Redis实战《红丸出品》
Redis实战《红丸出品》Redis实战《红丸出品》
Redis实战《红丸出品》billowqiu
 
Redis运维之道 新浪:杨海朝
Redis运维之道 新浪:杨海朝Redis运维之道 新浪:杨海朝
Redis运维之道 新浪:杨海朝billowqiu
 
Libevent源码深度剖析
Libevent源码深度剖析Libevent源码深度剖析
Libevent源码深度剖析billowqiu
 

Plus de billowqiu (7)

Eugene letuchy erlangatfacebook
Eugene letuchy erlangatfacebookEugene letuchy erlangatfacebook
Eugene letuchy erlangatfacebook
 
分布式文件系统FastDFS架构剖析
分布式文件系统FastDFS架构剖析分布式文件系统FastDFS架构剖析
分布式文件系统FastDFS架构剖析
 
On designing and deploying internet scale services
On designing and deploying internet scale servicesOn designing and deploying internet scale services
On designing and deploying internet scale services
 
基于Zookeeper的配置信息存储方案的设计与实现
基于Zookeeper的配置信息存储方案的设计与实现基于Zookeeper的配置信息存储方案的设计与实现
基于Zookeeper的配置信息存储方案的设计与实现
 
Redis实战《红丸出品》
Redis实战《红丸出品》Redis实战《红丸出品》
Redis实战《红丸出品》
 
Redis运维之道 新浪:杨海朝
Redis运维之道 新浪:杨海朝Redis运维之道 新浪:杨海朝
Redis运维之道 新浪:杨海朝
 
Libevent源码深度剖析
Libevent源码深度剖析Libevent源码深度剖析
Libevent源码深度剖析
 

Thrift多路复用的设计与实现

  • 1. Thrift 服务(Server)复用的设计与实现 作者:billowqiu@163.com 介绍 Thrift 作为一个跨语言的 rpc 框架,为后端服务间的多语言混合开发提供了高可靠,可 扩展,以及高效的实现。但是自从 2007 年 Facebook 开源后的 6 年时间内一直缺少一个多路 复用的功能(Multiplexing Services),也就是在一个 Server 上面实现多个 Service 调用。比如 要实现一个后端服务,很多时候不仅仅只是实现业务服务接口,往往还会预留一些调试, 监 控服务接口,以往要实现多个 Service 在一个 Server 上面调用,要么将多个服务糅合成一个 庞大的服务(图 1) ,要么将多个 Service 分摊到不同的 Server 上(图 2) 。最近的版本 0.9.1 终于实现内置的多路复用, 本文简要分析一下该功能的设计与实现, 并提供一个简单的示例。 图1
  • 2. 图2  第一种方式将所有的接口放到一个服务中,会导致新接口增加时的代码维护成本  第二种方式采取将不同的 Service 绑定到不同的 Server,因为多个 Server 会监听多个端 口,最后导致运维方面的管理和维护成本增加(端口在某些时候是一个有限资源) 设计 Thrift 的架构如下: 图3 Thrift 采取了很优雅的分层设计,下面简述各层的主要功能:
  • 3.  Transport 负责传输数据的接口,有文件,内存,套接字等实现。  Protocol 负责数据的协议交互接口,有二进制,Json 等实现。  Processor 负责输入输出数据处理的接口,其实就是对 Protocol 的处理。  Server 包括了上面各层的创建和管理, 并提供网络服务的功能, 网络服务这块目前有四个实现, 分别是最简单的单线程阻塞,多线程阻塞,线程池阻塞和基于 libevent 的非阻塞模式。 实现多路复用有以下几个需要注意的地方:  代码接口兼容  协议实现兼容  不依赖任何 Server 层代码,也不需要新的 Server 实现 0.9.1 之前版本不能多个 Service 在同一个 Server 上面调用, 主要是因为在协议层只把 Service 的函数名打包, 没有将 ServiceName 打包进去, 所以在 Processor 层默认只能处理一个 Service。 新版本中通过新增以下设计(红色部分)完成了 Service 的多路复用:
  • 4. 图4 图5  Client 增加一个 MultiplexProtcol 实现,在原有协议基础上增加 ServiceName 的打包  Server 增加一个 MultiplexProssor 实现,分离不同的具体服务 实现 从 Release-Notes 看到目前已经有 Java,Delphi,C#,C++几个语言实现了该功能,具体到 C++实现按照 THRIFT-1902 的介绍,是直接移植的 java 版本。 新增代码 protocol/TMultiplexedProtocol.h protocol/TMultiplexedProtocol.cpp
  • 5. protocol/TProtocolDecorator.h processor/TMultiplexedProcessor.h 主要逻辑 1) TMultiplexedProtocol 类重写 writeMessageBegin_virt 方法, Service 的函数名前新增了 在 ServiceName,并附带了一个分隔符;该类采取了 Decorator 模式将绝大部分操作转发到 实际的 protocol 对象。 2) TMultiplexedProcessor 类增加了一个存放 service 的 map, typedef std::map< std::string, shared_ptr<TProcessor> > services_t; key 为 ServiceName , 这 样 在 process 方 法 中 先 解 出 TMultiplexedProtocol 传 递 过 来 的 ServiceName, 通过该 key 查找到对应的 Processor 对象, 再调用该 Processor 的 process 方法, 这样就完美的实现了多个 serivice 的共存。 使用示例 IDL: namespace cpp thrift.multiplex.demo service FirstService { void blahBlah() } service SecondService { void blahBlah() } Server: int port = 9090; shared_ptr<TProcessor> processor1(new FirstServiceProcessor (shared_ptr<FirstServiceHandler>(new FirstServiceHandler()))); shared_ptr<TProcessor> processor2(new SecondServiceProcessor (shared_ptr<SecondServiceHandler>(new SecondServiceHandler()))); //使用 MultiplexedProcessor
  • 6. shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor()); //注册各自的 Service processor->registerProcessor("FirstService", processor1); processor->registerProcessor("SecondService", processor2); shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); server.serve(); Client: shared_ptr<TSocket> transport(new TSocket("localhost", 9090)); transport->open(); shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport)); shared_ptr<TMultiplexedProtocol> mp1(new TMultiplexedProtocol(protocol, "FirstService")); shared_ptr<FirstServiceClient> service1(new FirstServiceClient(mp1)); shared_ptr<TMultiplexedProtocol> mp2(new TMultiplexedProtocol(protocol, "SecondService")); shared_ptr<SecondServiceClient> service2(new SecondServiceClient(mp2)); service1->blahBlah(); service2->blahBlah(); 总结 Thrift 通过在客户端采取的 decorator 模式巧妙的在协议层将 ServiceName 传递到服务端,服 务端通过常见的手段将 ServiceName 和具体的 Processor 进行映射,完美的解决了 Server 对 Service 的多路复用问题。 参考资料 1. 2. 3. 4. http://thrift.apache.org/docs/concepts/ https://issues.apache.org/jira/browse/THRIFT-1902 https://issues.apache.org/jira/browse/THRIFT-563 http://bigdata.impetus.com/whitepaper