RPC框架 之 Apach thrift

Thrift

  • 1,Apache Thrift 主要用于各个服务之间的RPC通信,支持跨语言,常用语言:C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi都支持。

  • 2,Thrift 是一个典型的CS(客户端/服务器)结构,客户端和服务端可以使用不同的语言开发,既然客户端和服务端都能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言,这种语言就是IDL(Interface Description Language), .thrift 就是一种IDL语言

Trift 数据类型(Base Types)
Trift 不支持无符号类型,因为很多编程语言不存在无符号类型,比如java,php
基础数据类型
  • byte: 有符号字节。

  • i16: 16位有符号整数。

  • i32:32位有符号整数。

  • i64:64位有符号整数。

  • double: 64位 浮点数。

  • string: 字符串。

    1:optional string username,
    2:optional i32 age,
特殊数据类型
  • binary:一系列未编码的字节

  • N.B.。

Structs结构体
Thrift structs 定义了公共对象,也就是oop语言中的常说的类,但是他不具有继承性.结构体可以包含很多字段,字段包含的内容: numeric field IDs, optional default values, 结构体的目的就是将一些数据聚合在一起,方便传输管理
struct Person {
    1:optional string username,
    2:optional i32 age,
    3:optional bool married
}
容器类型(Containers)
  • list: 一系列由T类型的数据组成的有序列表,元素可以重复。

  • set: 一系列由T类型的数据组成的无序集合,元素不可重复。

  • map: 一个字典结构,key为K 类型,value为V 类型,相当于java中的HashMap.

1: list<string> strings,
2: list<i32> newlist,
3: set<i32> newset,
4: set<string> a_set2500,
5: map<i32, i32> newmap,
6: map<string,string> map_field,
异常(Exceptions)
thift支持自定义exception,规则与struct一样,
exception NotFoundException {
}

exception InvalidRequestException {
    1: required string why
}

exception DataException{
 1:optional string message;
 2:optional string callStack,
 3:optional string date
}
服务(Services)
Thrift 定义服务相当于java中创建Interface一样,创建的service经过代码生成命令之后就会生成客户端和服务器端的框架代码。
  • 一个服务(Services)可以定义多个函数。
    service FacebookService {
        string getName(),
        map<string, i64> getCounters(),
        i64 getCounter(1: string key),
    }

    service PersonService{
        Person getPersonByUsername(1:required string username) throws(1:DataException dataException),

        void savePerson(1:required Person person) throws(1:DataException dataException)
    }
类型定义(typedef)
thirift 支持类似c++ 一样的typedef定义,相当于改了别名,语法:
typedef DefinitionType Identifier
typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String

使用
struct Person {
    1: optional String username,
    2: optional int age,
    3: optional boolean married
}
常量(const)
thrift 也支持常量定义,使用const 关键字,语法:
const FieldType Identifier = ConstValue

const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
命名空间
Thirft的命名空间相当于java中package的意思,主要目的是组织代码。thrift使用namespace定义命名空间:
namespace 语言名 路径
    namespace java thrift.generated
    namespace php tutorial
文件包含
Trift也支持文件包含,相当于php/c/c++中的include,java中的import.使用关键字include定义:
include “文件名”

include "paratent.thrift"
注释
Trifit注释方式支持shell风格的注释,支持c/c++ 风格的注释,即#和//开头的语句都当做注释,/**/包含的语句就是注释。
可选与必选
thrift 提供两个关键字required,option,分别用于表示对应的字段是必填的还是可选的。默认是可选
struct People{
    1: required string name;
    2: optional i32 age;
}

一个完整的thrift 文件

namespace java thrift.generated
namespace php tutorial

typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String

struct Person {
    1: optional String username,
    2: optional int age,
    3: optional boolean married
}

exception DataException {
    1: optional String message,
    2: optional String callStack,
    3: optional String date
}

service PersonService{
    Person getPersonByUsername(1:required String username ) throws(1: DataException dataException),
    void savePerson(1:required Person person) throws(1: DataException dataEception),
    String testSave(1:required String name)
}

Thrift 工作原理

  • 如何实现多语言之间的通信?

  • 1,数据传输使用socket(多种语言均支持),数据再以特定的格式发送,接收语言进行解析。

  • 2,定义thrift 的文件,由thrift文件(IDL)生成双方语言的接口,model,在生成的model以及接口中会有解码编码的代码。

安装thrift

brew install thrift

生成代码

thrift -r --gen java src/thrift/person.thrift

thrift -r --java php src/thrift/person.thrift
或者
thrift -r --java php:server src/thrift/person.thrift

java thrift示例

idl users.thrift
namespace java com.lihao.netty.thrift2
namespace php thrift

typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String


struct User{
    1: String username,
    2: int age,
    3: int id,

}

struct UserRequest{
    1:int id;
    2:String token;
    3:String username;
    4:String passworld;
}


exception DataException {
    1: String message;
    2: String callStack;
    3: String date
}

service UserService{
    User login(1:required UserRequest userRequst) throws(1: DataException dataException);
    void logOut(1:required UserRequest userRequst) throws(1: DataException dataException);
    list<User> userList()  throws(1: DataException dataException);
}

生成代码
thrift -r --gen java src/thrift/users.thrift
实现service 接口方法 UserServiceIml.java
public class UserServiceIml implements UserService.Iface {
    @Override
    public User login(UserRequest userRequst) throws DataException, TException {
        System.out.println("--------服务器:login--------------");
        System.out.println(userRequst);
        User user =  new User();
        user.setId(2);
        user.setUsername("张三");
        user.setAge(20);
        return user;
    }

    @Override
    public void logOut(UserRequest userRequst) throws DataException, TException {
        System.out.println("--------服务器:logOut--------------");
        System.out.println(userRequst);


    }

    @Override
    public List<User> userList() throws DataException, TException {
        System.out.println("--------服务器:userList--------------");

      List userList =   new ArrayList<>();

        User user =  new User();
        user.setId(2);
       user.setUsername("我会回来的");
        user.setAge(20);

        User user1 =  new User();
        user1.setId(2);
        user1.setUsername("张三-2---");
        user1.setAge(20);

        User user2 =  new User();
        user2.setId(2);
        user2.setUsername("张三---123");
        user2.setAge(20);


        userList.add(user);
        userList.add(user1);
        userList.add(user2);
        return userList;
    }
}

服务端 Server.java

public class Server {
    public static void main(String... args) throws Exception {
        /**
         *  +-------------------------------------------+
         | Server                                    |
         | (single-threaded, event-driven etc)       |
         +-------------------------------------------+
         | Processor                                 |
         | (compiler generated)                      |
         +-------------------------------------------+
         | Protocol                                  |
         | (JSON, compact etc)                       |
         +-------------------------------------------+
         | Transport                                 |
         | (raw TCP, HTTP etc)                       |
         +-------------------------------------------+
         */
        TNonblockingServerSocket socket = new TNonblockingServerSocket(7788);

        THsHaServer.Args arg = new THsHaServer.Args(socket).minWorkerThreads(2).maxWorkerThreads(4);
        UserService.Processor<UserServiceIml> processor = new UserService.Processor<>(new UserServiceIml());

        //协议 二进制压缩
        arg.protocolFactory(new TCompactProtocol.Factory());
        //传输 帧
        arg.transportFactory(new TFramedTransport.Factory());
        // 处理器
        arg.processorFactory(new TProcessorFactory(processor));

        TServer server  = new THsHaServer(arg);

        System.out.println("Thrift Server Started");

        server.serve();



    }

}

java客户端 client
public class Client {
    public static void main(String ...args)  {
        TTransport transport = new TFastFramedTransport(new TSocket("localhost",7788),600);

        TCompactProtocol protocol = new TCompactProtocol(transport);

        UserService.Client client = new UserService.Client(protocol);

        try {
            transport.open();
            UserRequest request = new UserRequest();
            request.setUsername("li si");
            request.setPassworld("****");
            User user = client.login(request);
            System.out.println("--------------------------------");
            System.out.println(user);
            System.out.println("--------------------------------");

            List<User> list = client.userList();

            System.out.println(list);
            System.out.println("--------------------------------");


        } catch (Exception ex){
            ex.printStackTrace();
        } finally {
            transport.close();
        }


    }
}

php客户端
  • 生成php代码
thrift -r --gen php src/thrift/users.thrift

UserClient.php

header("Content-Type: text/html; charset=UTF-8");
ini_set("display_errors", 'On');
error_reporting(E_ALL);
require_once __DIR__ . '/lib/Thrift/ClassLoader/ThriftClassLoader.php';

use Thrift\ClassLoader\ThriftClassLoader;
use \Thrift\Transport\TSocket;
use \Thrift\Transport\TFramedTransport;
use \Thrift\Protocol\TCompactProtocol;
use \thrift\UserServiceClient;

$GEN_DIR = __DIR__ . '/gen-php';

$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ . '/lib');
$loader->registerDefinition('thrift', $GEN_DIR);
$loader->register();


$socket = new TSocket("localhost", 7788);

$transport = new TFramedTransport($socket);
$protoc = new TCompactProtocol($transport);

$client = new UserServiceClient($protoc);
echo 1;
try {
    $transport->open();
    echo 2;
    $request = new \thrift\UserRequest();
    $request->username = "张三";
    $user = $client->login($request);
    print_r($user);
    echo 3;
    $list = $client->userList();
    echo $list[0]->username."ok";




} catch (\tutorial\DataException $ex) {
    echo 'error';
    print 'TException: ' . $ex->getMessage() . "\n";

}
$transport->close();

代码步骤
thfit服务器端代码
  1. 创建Handler,用于处理业务逻辑,数据处理接口.

  2. 基于Handler创建Processor,数据处理对象

  3. 创建Transport(通信方式),数据传输方式

  4. 创建Protocol方式(设定传输格式),数据传输协议

  5. 基于Processor, Transport和Protocol创建Server

  6. 运行Server

thrift客户端:
  1. 创建Transport

  2. 创建Protocol方式

  3. 基于Transport和Protocol创建Client

  4. 运行Client的方法

Thrift 深入了解

Thrift 架构图

client
表示与服务端连接的那个对象,进行方法调用,
write/read
    thift 帮助我们自动生成的, write 是将客户端的数据写到socket(服务器端),read 从socket读到客户端  
TProtocal
应用层 表示协议 数据格式 比如json
TTransport
传输层 
TCompactProtocol 即使使用charlse 抓包 拿到数据也是二进制
Thrift 传输格式Protocol
  • TBinaryProtocol 二进制格式

  • TCompactProtocol 压缩二进制格式(常用的方式)

  • TJSONProtocol JSON格式

  • TSimpleJSONProtocal 提供json只写协议,生成的文件很容易通过脚本语言解析。

  • TDebugProtocal 使用易懂的可读的文本格式,以便于debug

Thrift 传输方式Transport
  • TSocket 阻塞式socket

  • TFramedTransport 以frame 为单位进行传输,非阻塞式服务中使用(常用的方式)

  • TFileTransport 以文件形式进行传输

  • TMemoryTransport 将内存用于I/O , java 实现时内部实际使用了简单的ByteArrayOutputStream。

  • TZlibTransport 使用zlib进行压缩,与其他传输方式联合使用。当前无java实现。

Thrift 支持的服务模型
  • TSimpleServer 简单的单线程服务模型,常用于测试

  • TThreadPoolServer 多线程服务模型,使用标准的阻塞式IO

  • TNonbolockingServer - 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)

  • THsHaServer - THsHa 引入了线程池去处理,其模型把读写任务放倒线程池去处理;
    Half-sync/Half-async的处理模式,Half-async是在处理IO事件上(accept/read/write io),
    Half-sync用于handler对rpc同步处理(常用方式)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 目前常见的Apache RPC框架有:Apache ThriftApache Avro、Apache Qpid、Apache HBase、Apache ActiveMQ和Apache Axis2。 ### 回答2: Apache bRPC是一个基于C++的远程过程调用(RPC框架,与其他类似的RPC框架相比,它具有以下特点和优势: 1. gRPC:gRPC是一个由Google开发的开源RPC框架,支持多种编程语言,包括C++。与bRPC类似,它也基于Protocol Buffers和HTTP/2,提供高性能和可靠的跨网络通信。 2. ThriftApache Thrift是一个多语言的跨平台RPC框架,可以生成不同语言的代码。它支持C++、Java、Python等多种编程语言,具有广泛的应用领域和丰富的特性。 3. Dubbo:Dubbo是阿里巴巴开源的分布式服务框架,主要用于Java语言。它支持服务治理、服务注册中心等功能,并且具有较高的性能和可靠性。 4. Apache ThriftApache Tooth是由 Facebook 开发的一个高效的远程服务通讯框架,其可传递的数据类型: 再Python中:bool, byte, i16, i32, i64,内建字符串,列表和map 再C++中:bool. tropical,byte,short.int.long.字符串.数组和实体。 5. Cap'n Proto:Cap'n Proto是一个高效的RPC和序列化框架,设计目标是提供高性能和低延迟的数据通信。它支持C++、Python、Java等多种编程语言,可以用于构建分布式系统。 总结:以上所列举的框架都是流行且功能强大的RPC框架,虽然有些框架可能在具体实现细节上有所差异,但它们都提供了便捷的远程服务通信和跨语言的支持。根据具体的需求和项目背景,可以选择合适的RPC框架来实现分布式系统。 ### 回答3: Apache bRPC是一个基于Apache Avro协议的分布式RPC框架,它主要用于构建高效、易于扩展的分布式系统。 除了Apache bRPC,还有一些类似的RPC框架可供选择,如下所示: 1. Apache Dubbo:Dubbo是一种高性能、轻量级的分布式服务框架,支持面向接口的远程方法调用。Dubbo具有灵活的服务治理和负载均衡策略,可实现服务的快速扩展和集群部署。 2. gRPC:gRPC是一个高性能、开源的通用RPC框架,由Google开发并采用Protocol Buffers作为IDL。它支持多种编程语言,提供强大的流控、认证和负载均衡功能。 3. ThriftThrift是一种可伸缩、跨语言的RPC框架,最初由Facebook开发。它支持多种数据编码格式,包括二进制、JSON和压缩格式。Thrift适用于复杂数据结构和大规模分布式系统。 4. MessagePack-RPC:MessagePack-RPC是一个高性能、轻量级的RPC框架,使用了MessagePack作为序列化协议。它支持多种编程语言,具有简单易用的API和低延迟的性能特点。 尽管这些框架都可以实现RPC通信,但它们在协议、性能、语言支持和功能方面有所不同。选择合适的RPC框架应根据项目的需求、开发团队的熟悉程度和系统的规模来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值