【Java】分布式RPC通信框架Apache Thrift 使用总结

时间:2022-12-17 23:27:33

简介

  Apache Thrift是Facebook开源的跨语言的RPC通信框架,目前已经捐献给Apache基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于thrift研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。

  RPC即Remote Procedure Call,翻译为远程过程调用。任何RPC协议的实现终极目标都是让使用者在调用远程方法的时候就像是调用本地方法一样简单,从而提高使用远程服务的效率。

  现代互联网架构多数基于SOA思想而搭建,即面向服务化的架构。服务提供方称为Provider,服务的使用方称为Consumer,有时也把服务提供方称为Server端,使用方称为Client端,即典型的CS模型。这里的远程调用,主要指跨进程的调用,Provider和Consumer可能是同一机器的不同进程,也可能在不同的机器,通过网络相互通信,大部分情况下两者会部署在不同的物理机器上,这种情况下由于网络通信的开销就会对RPC框架的性能要求极高。

【Java】分布式RPC通信框架Apache Thrift 使用总结

下面分别从服务端和客户端的视角来介绍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连接等等。

  理解Thrift基本的运行模式,对后续更深入研究RPC实现机制会有更好的帮助, 更多Thrift数据结构及其使用方法,可以直接访问官网https://thrift.apache.org 来学习。

【Java】分布式RPC通信框架Apache Thrift 使用总结的更多相关文章

  1. RPC通信框架——RCF介绍

    现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...

  2. RPC通信框架——RCF介绍(替换COM)

    阅读目录 RPC通信框架 为什么选择RCF 简单的性能测试 参考资料 总结 现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实 ...

  3. RPC通信框架——RCF介绍

    现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...

  4. 美团分布式服务通信框架及服务治理系统OCTO

     一.什么是OCTO 定义: OCTO是美团的分布式服务通信框架及服务治理系统,属于公司级基础设施,目前尚未开源. 目标: 为公司所有业务提供统一的服务通信框架,使业务具备良好的服务运营能力,轻松实现 ...

  5. 基于netty轻量的高性能分布式RPC服务框架forest<下篇>

    基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...

  6. 基于netty轻量的高性能分布式RPC服务框架forest&lt&semi;上篇&gt&semi;

    工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...

  7. RSF 分布式 RPC 服务框架的分层设计

    RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知 ...

  8. SpringBoot2&plus;Netty打造通俗简版RPC通信框架&lpar;升级版&rpar;

    背景         上篇文章我简单的介绍了自己打造的通俗简版RPC通信框架,这篇是对简版的增强~         如果大家对此项目还感兴趣的话,可到码云上瞄瞄:Netty-RPC         上 ...

  9. SpringBoot2&plus;Netty打造通俗简版RPC通信框架

    2019-07-19:完成基本RPC通信! 2019-07-22:优化此框架,实现单一长连接! 2019-07-24:继续优化此框架:1.增加服务提供注解(带版本号),然后利用Spring框架的在启动 ...

随机推荐

  1. IDEA插件

    Key Promoter 快捷键提示插件,帮助你快速记住快捷键.当你用鼠标完成某功能时,它会指示有相应的快捷键来完成刚才的功能,同时指导你为经常重复的操作建立快捷键. SerialVersionUID ...

  2. redis-集群(cluster)扫盲篇(一)

    什么是redis的集群 按我个人的理解,redis集群就是实现多个redis节点之间进行数据的共享. 集群有什么好处: 将数据自动split到多个节点进行存储. 当集群中的一部分节点失效或者无法进行通 ...

  3. Java Struts文件上传和下载详解

    Struts2文件上传 Struts 2框架提供了内置支持处理文件上传使用基于HTML表单的文件上传.上传一个文件时,它通常会被存储在一个临时目录中,他们应该由Action类进行处理或移动到一个永久的 ...

  4. Android中调用C&plus;&plus;函数的一个简单Demo

    这里我不想多解释什么,对于什么JNI和NDK的相关内容大家自己去百度或谷歌.我对Android的学习也只是个新手.废话少说直接进入正题. 一.在Eclipse中创建一个Android Applicat ...

  5. 区别jquery对象和dom对象及转换方法

    一.jquery对象 由$() 获取,例如 var div = $("#id"); 这个div是jquery对象,它里面没有dom对象自带的方法.常见的dom对象自带的方法, 例如 ...

  6. Vue2 后台管理系统解决方案

    基于Vue.js 2.x系列 + Element UI 的后台管理系统解决方案. github地址:https://github.com/lin-xin/manage-system demo地址:ht ...

  7. ArrayList的实现及原理

    ArrayList ArrayList是最常见以及每个Java开发者最熟悉的集合类了,顾名思义,ArrayList就是一个以数组形式实现的集合,以一张表格来看一下ArrayList里面有哪些基本的元素 ...

  8. animator 新动画

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Animator ...

  9. Vue v-if 和 v-show

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. win10 打开sql server配置管理器

    win10 安装 sql server之后无法在开始菜单找到“sql server 配置管理器(SQL server configuration manager 1)在开始菜单中,无法找到 配置管理器 ...