【Java】分布式RPC通信框架Apache Thrift 使用总结
简介
Apache Thrift是Facebook开源的跨语言的RPC通信框架,目前已经捐献给Apache基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于thrift研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。
RPC即Remote Procedure Call,翻译为远程过程调用。任何RPC协议的实现终极目标都是让使用者在调用远程方法的时候就像是调用本地方法一样简单,从而提高使用远程服务的效率。
现代互联网架构多数基于SOA思想而搭建,即面向服务化的架构。服务提供方称为Provider,服务的使用方称为Consumer,有时也把服务提供方称为Server端,使用方称为Client端,即典型的CS模型。这里的远程调用,主要指跨进程的调用,Provider和Consumer可能是同一机器的不同进程,也可能在不同的机器,通过网络相互通信,大部分情况下两者会部署在不同的物理机器上,这种情况下由于网络通信的开销就会对RPC框架的性能要求极高。
下面分别从服务端和客户端的视角来介绍Thrift在RPC中的应用。
服务端(Server)
服务端需要发布一个服务给别人使用,首先要约定好服务的接口,包括以下几个部分:
- 服务的名称
- 服务使用时的参数
- 返回结果
Thrift自己规定了一套接口定义语言(IDL)来描述服务,用后缀为.thrift的文件来描述,比如我们要提供一个打招呼的服务,传入姓名,然后返回一段友好的语句,Thrift文件HelloService.thrift的内容如下:
- namespace java com.yuanwhy.service
- service HelloService{
- string sayHello(1:string name)
- }
Thrift文件定义好之后,就约定好了接口的使用方式,但是仍然还不能使用,需要我们用thrift命令来生成对应的编程语言的文件,比如用一下命令来生成HelloService.class的Java文件。
- thrift -r --gen java HelloService.thrift
命令行参数 -r 代表递归生成里面引用的其他文件, --gen 后面跟生成的目标语言,最后跟上thrift文件。
生成的Java文件里会有一个接口HelloService.Iface,这就是一个普通的Java Interface,服务端要提供该接口的实现,实现之前需要引用libthrift的jar包,比如我们这么实现:
- package com.yuanwhy.service;
- import org.apache.thrift.TException;
- public class HelloServiceImpl implements HelloService.Iface {
- @Override
- public String sayHello(String name) throws TException {
- return "Hello, " + name + "!";
- }
- }
这样,服务端就实现了服务的逻辑部分,但是要让别人在网络上真正可用,我们还得把这个服务发布出去,发布的方式就是借助Socket编程,监听一个对外服务的端口,这也是网络通讯的基本套路。利用Thrift提供的API,在HelloServiceProvider类中启动Thrift服务:
- package com.yuanwhy.demo;
- import com.yuanwhy.service.HelloService;
- import com.yuanwhy.service.HelloServiceImpl;
- import org.apache.thrift.TProcessor;
- import org.apache.thrift.server.TServer;
- import org.apache.thrift.server.TSimpleServer;
- import org.apache.thrift.transport.TServerSocket;
- import org.apache.thrift.transport.TTransportException;
- public class HelloServiceProvider {
- /**
- * 启动 Thrift 服务器
- *
- * @param args
- */
- public static void main(String[] args) {
- try {
- // 设置服务端口为 7911
- TServerSocket serverTransport = new TServerSocket(7911);
- TProcessor processor = new HelloService.Processor(new HelloServiceImpl());
- TServer server = new TSimpleServer(new TServer.Args(serverTransport).processor(processor));
- System.out.println("Start server on port 7911...");
- server.serve();
- } catch (TTransportException e) {
- e.printStackTrace();
- }
- }
- }
运行main函数之后,服务端就会监听7911端口,开始对外提供sayHello的服务了。
客户端(Client)
客户端想要使用服务端通过thrift发布的服务,只需要遵循面向接口编程的基本思想,引用Java接口,用thrift的API连接服务端即可,比如HelloServiceConsumer类中这么使用sayHello服务:
- package com.yuanwhy.demo;
- import com.yuanwhy.service.HelloService;
- import org.apache.thrift.TApplicationException;
- import org.apache.thrift.TEnum;
- import org.apache.thrift.TException;
- import org.apache.thrift.protocol.TBinaryProtocol;
- import org.apache.thrift.protocol.TProtocol;
- import org.apache.thrift.transport.TSocket;
- import org.apache.thrift.transport.TTransport;
- /**
- * Created by zeze on 2018/03/23.
- */
- public class HelloServiceConsumer {
- public static void main(String[] args) {
- TTransport transport = new TSocket("0.0.0.0", 7911);
- try {
- transport.open();
- TProtocol protocol = new TBinaryProtocol(transport);
- HelloService.Client client = new HelloService.Client(protocol);
- System.out.println(client.sayHello("yuanwhy"));
- transport.close();
- } catch (TApplicationException e) {
- if (e.getType() == TApplicationException.MISSING_RESULT) {
- System.out.println("null");
- }
- } catch (TException e){
- }
- }
- }
客户端运行结果会打印Hello, yuanwhy!
,表明服务调用成功。仔细观察一下客户端的代码会发现,基本和普通的Socket编程没有太大的区别,只是又被thrift做了一层的封装,让我们可以按照约定的接口直接像client.sayHello("yuanwhy")
这样调用远程服务。
注意:客户端如果是在不同的Java项目中调用服务,只需要服务端把thrift文件或者生成的Java接口文件以API的方式提供出来即可,客户端绝对不需要引用HelloServiceImpl实现类,因为目的就是让逻辑在服务端实现,对客户端透明。
另外,当服务端返回null时,客户端会抛一个Type为TApplicationException.MISSING_RESULT
的异常出来,如果不处理就会影响客户端正常的流程。这一点可以在Thrift的生成代码中看出来:
- public String recv_sayHello() throws org.apache.thrift.TException
- {
- sayHello_result result = new sayHello_result();
- receiveBase(result, "sayHello");
- if (result.isSetSuccess()) {
- return result.success;
- }
- throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "sayHello failed: unknown result");
- }
总结
以上对Thrift的使用只做了个简单的介绍,真正在项目中使用Thrift还会涉及很多,比如各种Thrift数据结构的使用,在对Thrift接口进行升级过程中struct的字段最好保留原有字段顺序以达到兼容目的,还比如客户端应该建立连接池机制,而不是每次调用服务时都去新建一次TCP连接等等。
【Java】分布式RPC通信框架Apache Thrift 使用总结的更多相关文章
- RPC通信框架——RCF介绍
现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...
- RPC通信框架——RCF介绍(替换COM)
阅读目录 RPC通信框架 为什么选择RCF 简单的性能测试 参考资料 总结 现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实 ...
- RPC通信框架——RCF介绍
现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...
- 美团分布式服务通信框架及服务治理系统OCTO
一.什么是OCTO 定义: OCTO是美团的分布式服务通信框架及服务治理系统,属于公司级基础设施,目前尚未开源. 目标: 为公司所有业务提供统一的服务通信框架,使业务具备良好的服务运营能力,轻松实现 ...
- 基于netty轻量的高性能分布式RPC服务框架forest<下篇>
基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...
- 基于netty轻量的高性能分布式RPC服务框架forest<上篇>
工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...
- RSF 分布式 RPC 服务框架的分层设计
RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知 ...
- SpringBoot2+Netty打造通俗简版RPC通信框架(升级版)
背景 上篇文章我简单的介绍了自己打造的通俗简版RPC通信框架,这篇是对简版的增强~ 如果大家对此项目还感兴趣的话,可到码云上瞄瞄:Netty-RPC 上 ...
- SpringBoot2+Netty打造通俗简版RPC通信框架
2019-07-19:完成基本RPC通信! 2019-07-22:优化此框架,实现单一长连接! 2019-07-24:继续优化此框架:1.增加服务提供注解(带版本号),然后利用Spring框架的在启动 ...
随机推荐
- 洛谷 [P1024]一元三次方程求解【二分答案】
题目链接:https://www.luogu.org/problemnew/show/P1024 题目描述 有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b ...
- python模块——PrettyTable
python模块——PrettyTable 一. 简介 Python通过prettytable模块将输出内容如表格方式整齐输出,可用来生成美观的ASCII格式的表格,十分实用. python本身并不内 ...
- 获取img的高
我们可以通过css设置图片的width,然后通过 clientWidth获取图片的宽,但是这个宽似乎是css里面定义的width值,但是对于图片的高,使用 clientHeight 来获取似乎是有些问 ...
- openstack IPV6
openstack queens 配置有状态DHCPv6 概念: DHCPv6是一个用来配置工作在IPv6网络上的IPv6主机所需的IP地址.IP前缀和/或其他配置的网络协议. IPv6主机可以使用 ...
- POJ.3537.Crosses and Crosses(博弈论 Multi-SG)
题目链接 \(Description\) 有一个一行n列的棋盘,每个人每次往上放一个棋子,将三个棋子连在一起的人赢.问是否有必胜策略. \(Solution\) 首先一个人若在\(i\)处放棋子,那么 ...
- 【WIN32编程】利用汇编写cs1.6辅助
这篇文章本来在2018.5.1号就写完发圈子去了,这两天跟朋友在网吧打单击才想起来,就顺便把内容发上去把 作者:admin-神风 用CE找到功能的地址 CS1.6下载地址:https://pan.ba ...
- SpringMybatisMapper
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" ...
- Unterminated <c:forEach tag
c:forEach tag意思是这一块有语法错误
- CocosCreator资源工作流程
--摘自官方文档 资源工作流程 添加资源 资源管理器 提供了三种在项目中添加资源的方式: 通过 创建按钮 添加资源 在操作系统的文件管理器中,将资源文件复制到项目资源文件夹下,之后再打开或激活 Coc ...
- 2018年web最新面试知识点总结
00.行内元素有哪些?块级元素有哪些? 空(void)元素有那些? 行内元素:a b span img input select strong 块级元素:div ul ol li ...