精华内容
下载资源
问答
  • thrift原理

    2018-04-16 18:07:09
    初识Thrift背景简介Thrift原理初识Thrift 初次接触Thrift是学习自学netty的时候,之后在公司的一个项目开始实际得接触。这个项目是一个广告投放的项目,基础信息在DB和Redis中存放着,当用户的请求过来的时候需要...
    • 初识Thrift
    • 背景简介
    • Thrift原理

    初识Thrift

            初次接触Thrift是学习自学netty的时候,之后在公司的一个项目开始实际得接触。这个项目是一个广告投放的项目,基础信息在DB和Redis中存放着,当用户的请求过来的时候需要匹配出一个合适的广告和策略,对时时性要求比较高,考虑到性能的问题,这个匹配的过程要用C来写。但是由于DB和redis存放的数据都是非常基础的数据,而且匹配的逻辑比较麻烦,如果全放到C端,当数据量大的时候性能还是不够。解决方案是起另一个程序定时的去将DB和Redis的数据做初步的处理,将合适的数据推送到C端的服务器内存中。这块的逻辑是非常麻烦的,我们也知道C开发起来是比较麻烦的,所以当时的决定是推送端由java来写,接收端由C来写。这就需要一种跨语言的RPC通信框架。

    背景简介

    Thrift简介

            thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

            thrift早期由facebook内部团队开发, 是为了解决facebook 系统中各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性,属于远程方法调用的一种。在2007 年facebook 提交Apache 基金会将Thrift 作为一个开源项目。

    RPC

            RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序布式多程序在内的应用程序更加容易。

    RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。


            简单的说,RPC就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法并得到返回的结果。RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯) RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式) RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

    IDL

            IDL是Interface description language的缩写,指接口描述语言,是CORBA规范的一部分,是跨平台开发的基础。IDL是用来描述软件组件接口的一种计算机语言。IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流。
    IDL通常用于远程调用软件。 在这种情况下,一般是由远程客户终端调用不同操作系统上的对象组件,并且这些对象组件可能是由不同计算机语言编写的。IDL建立起了两个不同操作系统间通信的桥梁。

    从本质上讲,OMG IDL接口定义语言不是作为程序设计语言体现在CORBA体系结构中的,而是用来描述产生对象调用请求的客户对象和服务对象之间的接口的语言。OMG IDL文件描述数据类型和方法框架,而服务对象则为一个指定的对象实现提供上述数据和方法。

    Thrift原理

    架构

    流程

            前面说到,Thrift是一种RPC通信框架,在完成客户端到服务端的RPC调用过程中,Thrift主要用到了传输层、协议层和处理类三个主要的核心类。具体过程如下:

            1.通过IDL定义一个接口的thrift文件,然后通过thrift的多语言编辑功能,将接口定义的thrift文件翻译成对应的语言版本的接口文件。

             1)异步客户端类AsyncClient和异步接口AsyncIface,本节暂不涉及这些异步操作相关内容;

           2)同步客户端类Client和同步接口Iface,Client类继承自TServiceClient,并实现了同步接口Iface;Iface就是根据thrift    文件中所定义的接口函数所生成;Client类是在开发Thrift的客户端程序时使用,Client类是Iface的客户端存根实现, Iface在开发Thrift服务器的时候要使用,Thrift的服务器端程序要实现接口Iface。

            3)Processor类,该类主要是开发Thrift服务器程序的时候使用,该类内部定义了一个map,它保存了所有函数名到函数对象的映射,一旦Thrift接到一个函数调用请求,就从该map中根据函数名字找到该函数的函数对象,然后执行它;

            4)参数类,为每个接口函数定义一个参数类,例如:为接口getInt产生一个参数类:getInt_args,一般情况下,接口函数参数类的命名方式为:接口函数名_args;

            5)返回值类,每个接口函数定义了一个返回值类,例如:为接口getInt产生一个返回值类:getInt_result,一般情况下,接口函数返回值类的命名方式为:接口函数名_result;

            2.客户端通过接口文件中的客户端部分生成的client对象,来调用thrift文件中的那些接口函数,但是,客户端调用接口函数时实际上调用的是接口函数的本地存根实现。

            3.接口函数的存根实现将调用请求发送给thrift服务器端,Thrift会将客户端程序调用的函数名和参数传递给协议层(TProtocol),协议层将函数名和参数按照协议格式进行封装,然后封装的结果交给下层的传输层。此处需要注意:要与Thrift服务器程序所使用的协议类型一样,否则Thrift服务器程序便无法在其协议层进行数据解析;

            4.传输层(TTransport)将协议层传递过来的数据进行处理,例如传输层的实现类TFramedTransport就是将数据封装成帧的形式,即“数据长度+数据内容”,然后将处理之后的数据通过网络发送给Thrift服务器;此处也需要注意:要与Thrift服务器程序所采用的传输层的实现类一致,否则Thrift的传输层也无法将数据进行逆向的处理;

            5.Thrift服务端的协议类(TProtocol)将传输层处理之后的数据按照协议进行解封装,并将解封装之后的数据交个Processor类进行处理;

            6.Thrift服务端的Processor类根据协议层(TProtocol)解析的结果,按照函数名找到函数名所对应的函数对象;

            7.Thrift服务端使用传过来的参数调用这个找到的函数对象;

            8.Thrift服务端将函数对象执行的结果交给协议层;

            9.Thrift服务器端的协议层将函数的执行结果进行协议封装;

            10.Thrift服务器端的传输层将协议层封装的结果进行处理,例如封装成帧,然后发送给Thrift客户端程序;

            11.Thrift服务器端的传输层将协议层封装的结果进行处理,例如封装成帧,然后发送给Thrift客户端程序;

            12.Thrift客户端的协议层将数据按照协议格式进行解封装,然后得到具体的函数执行结果,并将其交付给调用函数;

    数据结构

    •     基本类型 

        bool:布尔值

        byte:8位有符号整数

        i16:16位有符号整数,对应java中的short

        i32:32位有符号整数,对应java中的int

        i64:64位有符号整数,对应java中的long

        double:64位浮点数

        string:未知编码文本或二进制字符串

    •     结构体类型

        struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean

    •     容器类型

        list:对应java中的ArrayList

        set:对应java中的HashSet

        map:对应java中的HashMap

    •     异常类型
    •     服务类型

           service:对应服务的类

           Thrift在客户端和服务器端传递数据的时候(包括发送调用请求和返回执行结果),都是将数据按照TMessage进行组装,然后发送;TMessage包括三部分:消息的名称、消息的序列号和消息的类型,消息名称为字符串类型,消息的序列号为32位的整形,消息的类型为byte类型,消息的类型共有如下17种;

    协议(TProtocol)

            Thrift可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本 (text) 和二进制 (binary) 传输协议,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数。常用协议有以下几种:常用协议有以下几种:

    • TBinaryProtocol

            是Thrift的默认协议,使用二进制编码格式进行数据传输,基本上直接发送原始数据

    • TCompactProtocol

            压缩的、密集的数据传输协议,基于Variable-length quantity的zigzag 编码格式

    • TJSONProtocol

            以JSON(JavaScript Object Notation)数据编码协议进行数据传输

    • TDebugProtocol

            常常用以编码人员测试,以文本的形式展现方便阅读

    传输类(TTransport)

    • TSocket

            阻塞型 socket,用于客户端,采用系统函数 read 和 write 进行读写数据。

    • TServerSocket

            非阻塞型 socket,用于服务器端,accecpt 到的 socket 类型都是 TSocket(即阻塞型 socket)。

    • TBufferedTransport和TFramedTransport

        都是有缓存的,均继承TBufferBase,调用下一层 TTransport 类进行读写操作,吗,结构极为相似。其中 TFramedTransport 以帧为传输单位,帧结构为:4个字节(int32_t)+传输字节串,头4个字节是存储后面字节串的长度,该字节串才是正确需要传输的数据,因此TFramedTransport 每传一帧要比 TBufferedTransport 和 TSocket 多传4个字节。

    • TMemoryBuffer

            继承 TBufferBase,用于程序内部通信用,不涉及任何网络I/O,可用于三种模式:(1)OBSERVE模式,不可写数据到缓存;(2)TAKE_OWNERSHIP模式,需负责释放缓存;(3)COPY模式,拷贝外面的内存块到TMemoryBuffer。

    • TFileTransport

            直接继承 TTransport,用于写数据到文件。对事件的形式写数据,主线程负责将事件入列,写线程将事件入列,并将事件里的数据写入磁盘。这里面用到了两个队列,类型为 TFileTransportBuffer,一个用于主线程写事件,另一个用于写线程读事件,这就避免了线程竞争。在读完队列事件后,就会进行队列交换,由于由两个指针指向这两个队列,交换只要交换指针即可。它还支持以chunk(块)的形式写数据到文件。

    • TFDTransport

            是非常简单地写数据到文件和从文件读数据,它的 write 和 read 函数都是直接调用系统函数 write 和 read 进行写和读文件。

    • TSimpleFileTransport

            直接继承 TFDTransport,没有添加任何成员函数和成员变量,不同的是构造函数的参数和在 TSimpleFileTransport 构造函数里对父类进行了初始化(打开指定文件并将fd传给父类和设置父类的close_policy为CLOSE_ON_DESTROY)。

    • TZlibTransport

            跟 TBufferedTransport 和 TFramedTransport一样,调用下一层 TTransport 类进行读写操作。它采用<zlib.h>提供的 zlib 压缩和解压缩库函数来进行压解缩,写时先压缩再调用底层 TTransport 类发送数据,读时先调用 TTransport 类接收数据再进行解压,最后供上层处理

    • TZlibTransport

            继承 TSocket,阻塞型 socket,用于客户端。采用 openssl 的接口进行读写数据。checkHandshake()函数调用SSL_set_fd 将 fd 和 ssl 绑定在一起,之后就可以通过 ssl 的 SSL_read和SSL_write 接口进行读写网络数据。

    • TSSLServerSocket

            继承 TServerSocket,非阻塞型 socket, 用于服务器端。accecpt 到的 socket 类型都是 TSSLSocket 类型。

    • THttpClient和THttpServer

            是基于 Http1.1 协议的继承 Transport 类型,均继承 THttpTransport,其中 THttpClient 用于客户端,THttpServer 用于服务器端。两者都调用下一层TTransport 类进行读写操作,均用到TMemoryBuffer 作为读写缓存,只有调用 flush() 函数才会将真正调用网络 I/O 接口发送数据。

    Tprocessor层

            处理层就是服务器端定义的处理业务逻辑,它的主要代码是**Service.java文件中的Iface接口和Processor类。Iface接口:这个接口中的所有方法都是用户定义在IDL文件中的service的方法,它需要抛出TException这个检查异常,服务器端需要定义相应的实现类去 implements **.Iface 接口,完成服务的业务逻辑。Processor类:这个类中定义了一个processMap,里面包含了service中定义的方法,服务器端在构造这个Processor对象的时候,唯一需要做的就是把实现service(Iface)的对象作为参数传递给Processor的构造函数。

    Server层

            server是Thrift框架中的最高层,它创建并管理下面的三层,同时提供了客户端调用时的线程调度逻辑。服务层的基类是TServer,它相当于一个容器,里面包含了TProcessor,TTransport,TProtocol,并实现对它们的管理和调度。其中,protocol 定义了消息是怎样序列化的;transport 定义了消息是怎样在客户端和服务器端之间通信的;server 用于从 transport 接收序列化的消息,根据 protocol 反序列化之,调用用户定义的消息处理器,并序列化消息处理器的响应,然后再将它们写回 transport。
            Thrift 模块化的结构使得它能提供各种 server 实现。下面列出了 Java 中可用的 server 实现:
    • TSimpleServer
    • TNonblockingServer
    • THsHaServer
    • TThreadedSelectorServer
    • TThreadPoolServer            

    TSimpleServer

            TSimpleServer的工作模式只有一个工作线程,循环监听新请求的到来并完成对请求的处理,TSimplerServer 接受一个连接,处理连接请求,直到客户端关闭了连接,它才会去接受一个新的连接。正因为它只在一个单独的线程中以阻塞 I/O 的方式完成这些工作,所以它只能服务一个客户端连接,其他所有客户端在被服务器端接受之前都只能等待,所以它只是在简单的演示时候使用。

    TnonblockingServer

            TNonblockingServer 使用非阻塞的 I/O 解决了 TSimpleServer 一个客户端阻塞其他所有客户端的问题。它使用了java.nio.channels.Selector,通过调用 select(),它使得你阻塞在多个连接上,而不是阻塞在单一的连接上。当一个或多个连接准备好被接收/读/写时,select() 调用便会返回。TNonblockingServer 处理这些连接的时候,要么接受它,要么从它那读数据,要么把数据写到它那里,然后再次调用 select() 来等待下一个可用的连接。通用这种方式,server 可同时服务多个客户端,而不会出现一个客户端把其他客户端全部“饿死”的情况。


            TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,所有消息是被调用 select() 方法的同一个线程处理的。在业务处理比较复杂、耗时的时候,某些接口函数需要执行时间较长,多个调用请求任务依然是顺序一个接一个执行,此时该模式效率也不高,假设有10个客户端,处理每条消息所需时间为30000毫秒,那么,latency 和吞吐量分别是多少?当一条消息被处理的时候,其他9个客户端就等着被 select,所以客户端需要等待30秒钟才能从服务器端得到回应,吞吐量就是0.3个请求/秒,这个效率就相当低了。

    THsHaServer

            THsHaServer类是TNonblockingServer类的子类,TNonblockingServer模式中,采用一个线程来完成对所有socket的监听和业务处理,造成了效率的低下,THsHaServer模式的引入则是部分解决了这些问题。THsHaServer模式中,引入一个线程池来专门进行业务处理。


               与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升。但是,主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。

    TThreadPoolServer模式

            TThreadPoolServer模式采用阻塞socket方式工作,主线程负责阻塞式监听“监听socket”中是否有新socket到来,业务处理交由一个线程池来处理。


            线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。还有就是按照线程池模式,有一个专用的线程用来接受连接,一旦接受了一个连接,它就会被放入 ThreadPoolExecutor 中的一个 worker 线程里处理。worker 线程被绑定到特定的客户端连接上,直到它关闭。一旦连接关闭,该 worker 线程就又回到了线程池中。这意味着,在极端情况下如果有1万个并发的客户端连接,你就需要运行1万个线程。所以它对系统资源的消耗不像其他类型的 server 一样那么“友好”。

    TthreadedSelectorServer

            TThreadedSelectorServer模式是目前Thrift提供的最高级的模式,它内部有如果几个部分构成:

    • 一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
    • 若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是由这些线程来完成;
    • 一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
    • 一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交个ExecutorService线程池中的线程完成此次调用的具体执行;

            TThreadedSelectorServer模式中有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况;TThreadedSelectorServer对于大部分应用场景性能都不会差,因此,如果实在不知道选择哪种工作模式,使用TThreadedSelectorServer就可以。

    展开全文
  • 【thrift】 thrift原理浅析

    万次阅读 2014-07-06 14:28:14
    【thrift】 thrift原理浅析 上文介绍了 thrift 入门例子 下面简单介绍 thrift 的基本原理 这里以 thrift server端为例子 1.创建socket /*  * thrift 封装的 socket 层,使用端口7911构建一个非...
    【thrift】 thrift原理浅析

    上文介绍了 thrift 入门例子
    下面简单介绍 thrift 的基本原理

    这里以 thrift server端为例子

    1.创建socket
    /*
                 * thrift 封装的 socket 层,使用端口7911构建一个非阻塞的socket
                 */
            TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);

    server端创建的socket ,这是非阻塞的serversocket,使用的将是nio

    看下源码:TNonblockingServerSocket 构造方法最终会调用下面的构造方法
    public TNonblockingServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
        clientTimeout_ = clientTimeout;
        try {
          serverSocketChannel = ServerSocketChannel. open();
          serverSocketChannel.configureBlocking( false);

          // Make server socket
          serverSocket_ = serverSocketChannel.socket();
          // Prevent 2MSL delay problem on server restarts
          serverSocket_.setReuseAddress( true);
          // Bind to listening port
          serverSocket_.bind(bindAddr);
        } catch (IOException ioe) {
          serverSocket_ = null;
          throw new TTransportException( "Could not create ServerSocket on address " + bindAddr.toString() + ".");
        }
      }
    构造方法包含的内容很明显,就是创建一个serversocket,并绑定到指定的端口

    2.创建输入输出流协议对象
            /*
             * thrift 协议层,这里使用的是 二进制协议
             */
            Factory proFactory = new TBinaryProtocol.Factory();

    抽取其中部分代码,如下,TBinaryProtocol 对象定义了数据序列化和反序列化的操作
    private byte [] i32out = new byte[4];
      public void writeI32( int i32) throws TException {
        i32out[0] = (byte)(0xff & (i32 >> 24));
        i32out[1] = (byte)(0xff & (i32 >> 16));
        i32out[2] = (byte)(0xff & (i32 >> 8));
        i32out[3] = (byte)(0xff & (i32));
        trans_.write(i32out, 0, 4);
      }

    private byte [] i32rd = new byte[4];
      public int readI32() throws TException {
        byte[] buf = i32rd;
        int off = 0;

        if (trans_.getBytesRemainingInBuffer() >= 4) {
          buf = trans_.getBuffer();
          off = trans_.getBufferPosition();
          trans_.consumeBuffer(4);
        } else {
          readAll(i32rd, 0, 4);
        }
        return
          ((buf[off] & 0xff) << 24) |
          ((buf[off+1] & 0xff) << 16) |
          ((buf[off+2] & 0xff) <<  8) |
          ((buf[off+3] & 0xff));
      }

    3.数据读写处理
    /*
             * thrift idl接口的实现类
             */
            HelloServiceImpl testimpl = new HelloServiceImpl();
           
            /*
             * thrift Processor 业务逻辑处理层
             */
            TProcessor processor = new HelloService.Processor<HelloServiceImpl>(testimpl);

    定义我们Service的实现类 HelloServiceImpl 
    创建Processor,HelloServiceImpl 实现类作为参数传入Processor构造方法里
    processor主要完成的事情:
    1.把idl里定义的方法进行封装,最终暴露出一个统一的接口给thrift server进行调用
    2.封装protocol和transport层,包括输入输出流的处理细节、序列化反序列化

    看下thrift 生成的 HelloService 里的 Processor 类:
    processor类继承 TBaseProcessor
      public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
        private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());

    // Processor的构造方法
    // getProcessMap 里把我们定义的方法 helloWorld 封装成对象并设置到map里
        public Processor(I iface) {
          super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
        }

        protected Processor(I iface, Map<String,  org.apache.thrift.ProcessFunction<I, ? extends   org.apache.thrift.TBase>> processMap) {
          super(iface, getProcessMap(processMap));
        }

        private static <I extends Iface> Map<String,  org.apache.thrift.ProcessFunction<I, ? extends   org.apache.thrift.TBase>> getProcessMap(Map<String,  org.apache.thrift.ProcessFunction<I, ? extends   org.apache.thrift.TBase>> processMap) {
          processMap.put("helloWorld", new helloWorld());
          return processMap;
        }

    // 这里定义了一个对象,里面封装了 对外暴露的接口方法,如demo里,我定义了 helloWorld 方法
        public static class helloWorld<I extends Iface> extends org.apache.thrift.ProcessFunction<I, helloWorld_args> {
          public helloWorld() {
            super("helloWorld");
          }

          public helloWorld_args getEmptyArgsInstance() {
            return new helloWorld_args();
          }

          protected boolean isOneway() {
            return false;
          }

    // getResult 重写了父类的方法
    // 这个getResult里 iface.helloWorld 会实际调用 我们的业务方法并返回结果
          public helloWorld_result getResult(I iface, helloWorld_args args) throws org.apache.thrift.TException {
            helloWorld_result result = new helloWorld_result();
            result. success = iface.helloWorld(args. hello);
            return result;
          }
        }

    // Processor 继承的 TBaseProcessor 类
    public abstract class TBaseProcessor<I> implements TProcessor {
      private final I iface;
      private final Map<String,ProcessFunction<I, ? extends TBase>> processMap;

    // Processor构造方法调用 TBaseProcessor 方法,设置Service类及对外提供的接口方法map
      protected TBaseProcessor (I iface, Map<String, ProcessFunction<I, ? extends TBase>> processFunctionMap) {
        this.iface = iface;
        this.processMap = processFunctionMap;
      }

      public Map<String,ProcessFunction<I, ? extends TBase>> getProcessMapView() {
        return Collections.unmodifiableMap(processMap );
      }
    // 这个process 方法是processor最终暴露出去的方法
    // 方法的整体逻辑很明确:从输入流读取数据,解析得到要调用的方法并进行调用

      @Override
      public boolean process(TProtocol in, TProtocol out) throws TException {
        TMessage msg = in.readMessageBegin();
        ProcessFunction fn = processMap.get(msg.name);
        if (fn == null) {
          TProtocolUtil.skip(in, TType.STRUCT);
          in.readMessageEnd();
          TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD , "Invalid method name: '"+msg.name+"'");
          out.writeMessageBegin( new TMessage(msg. name, TMessageType.EXCEPTION, msg.seqid ));
          x.write(out);
          out.writeMessageEnd();
          out.getTransport().flush();
          return true;
        }

        fn.process(msg.seqid, in, out, iface);
        return true;
      }
    }

    在processor中,我们看到 helloWorld 类 继承了 ProcessFunction
    在processFunction 的 process 方法里,可以看到processor处理输入输出流的具体流程
    public abstract class ProcessFunction<I, T extends TBase> {
      private final String methodName;

      private static final Logger LOGGER = LoggerFactory.getLogger(ProcessFunction. class.getName());

      public ProcessFunction(String methodName) {
        this.methodName = methodName;
      }

      public final void process(int seqid, TProtocol iprot, TProtocol oprot, I iface) throws TException {
    // 先从输入流里读取出数据
        T args = getEmptyArgsInstance();
        try {
          args.read(iprot);
        } catch (TProtocolException e) {
          iprot.readMessageEnd();
          TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR , e.getMessage());
          oprot.writeMessageBegin( new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
          x.write(oprot);
          oprot.writeMessageEnd();
          oprot.getTransport().flush();
          return;
        }
        iprot.readMessageEnd();
        TBase result = null;

    // 然后调用子类的重写的 getResult 方法,即最终是调用我们写的业务方法
        try {
          result = getResult(iface, args);
        } catch(TException tex) {
          LOGGER.error("Internal error processing " + getMethodName(), tex);
          TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR ,
            "Internal error processing " + getMethodName());
          oprot.writeMessageBegin( new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
          x.write(oprot);
          oprot.writeMessageEnd();
          oprot.getTransport().flush();
          return;
        }
    // 然后把结果返回,thrift 里有个oneway 方法,oneway的方法调用完不等待直接返回
        if(!isOneway()) {
          oprot.writeMessageBegin( new TMessage(getMethodName(), TMessageType.REPLY, seqid));
          result.write(oprot);
          oprot.writeMessageEnd();
          oprot.getTransport().flush();
        }
      }

    }

    在thrift里,把方法给封装成了对象,通过方法名进行关联
    通信的过程通过两个变量进行定位调用
    iface 变量定位到具体的实现类,server与client共用一套idl生成的代码,编译期就确定好了
    ProcessFunction 会定位到具体的方法,这个是运行中动态确定的

    4.server服务

    Args rpcArgs = new Args(serverTransport);

            rpcArgs.processor(processor);

            rpcArgs.protocolFactory(proFactory);

            /*
             * thrift server
             */
            TServer server = new THsHaServer(rpcArgs);
           
            server.serve();
    这个是server的初始化及启动

    thrift server模型大概4种,分别为:
    TSimpleServer:单线程阻塞模型,accept一个连接、处理,然后返回结果
    THsHaServer:nio非阻塞,使用了reactor模型,网络连接处理和IO读写由一个线程完成,业务处理由线程池处理
    TThreadPoolServer:线程池阻塞,主线程侦听连接,accept的连接放到线程池工作线程处理
    TThreadedSelectorServer:nio非阻塞,使用了两层reactor
         网络连接处理由一个reactor线程处理,IO读写由另外的reactor线程处理,业务处理由线程池处理


    下面基于THsHaServer模型来分析

    TServer server = new THsHaServer(rpcArgs);
    这个构造方法的作用就是创建并初始化 server,初始化数据就是前面我们创建的 transport、protocol和Processor

    我们从 server.serve() 这个方法来入手
    /**
       * Begin accepting connections and processing invocations.
       */
      public void serve() {
        // start any IO threads
        if (!startThreads ()) {
          return;
        }

        // start listening, or exit
        if (!startListening()) {
          return;
        }

        setServing(true);

        // this will block while we serve
        waitForShutdown();

        setServing(false);

        // do a little cleanup
        stopListening ();
      }

    serve 方法里主要的是 startThreads 这个方法
    startThreads 方法主要作用就是创建 reactor 线程SelectAcceptThread
    protected boolean startThreads() {
        // start the selector
        try {
          selectAcceptThread_ = new SelectAcceptThread((TNonblockingServerTransport)serverTransport_ );
          selectAcceptThread_.start();
          return true;
        } catch (IOException e) {
          LOGGER.error("Failed to start selector thread!", e);
          return false;
        }
      }

    SelectAcceptThread这个线程的代码逻辑很明确,就是处理侦听和IO读写
    public void run() {
          try {
            if (eventHandler_ != null) {
              eventHandler_.preServe();
            }
    // 线程不断轮询,处理网络事件
            while (!stopped_) {
              select();
              processInterestChanges();
            }
            for (SelectionKey selectionKey : selector.keys()) {
              cleanupSelectionKey(selectionKey);
            }
          } catch (Throwable t) {
            LOGGER.error("run() exiting due to uncaught error", t);
          } finally {
            stopped_ = true;
          }
        }

    // select 方法侦听网络事件,根据事件类型进行不同处理
        /**
         * Select and process IO events appropriately:
         * If there are connections to be accepted, accept them.
         * If there are existing connections with data waiting to be read, read it,
         * buffering until a whole frame has been read.
         * If there are any pending responses, buffer them until their target client
         * is available, and then send the data.
         */
        private void select() {
          try {
            // wait for io events.
            selector.select();

            // process the io events we received
            Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
            while (!stopped_ && selectedKeys.hasNext()) {
              SelectionKey key = selectedKeys.next();
              selectedKeys.remove();

              // skip if not valid
              if (!key.isValid()) {
                cleanupSelectionKey(key);
                continue;
              }

              // if the key is marked Accept, then it has to be the server
              // transport.
              if (key.isAcceptable()) {
                handleAccept();
              } else if (key.isReadable()) {
                // deal with reads
                handleRead(key);
              } else if (key.isWritable()) {
                // deal with writes
                handleWrite(key);
              } else {
                LOGGER.warn( "Unexpected state in select! " + key.interestOps());
              }
            }
          } catch (IOException e) {
            LOGGER.warn("Got an IOException while selecting!", e);
          }
        }

    下面分别看下处理网络连接和读的情况
    /**
         * Accept a new connection.
         */
        private void handleAccept () throws IOException {
          SelectionKey clientKey = null;
          TNonblockingTransport client = null;
          try {
            // accept the connection
            client = (TNonblockingTransport) serverTransport.accept();
            clientKey = client.registerSelector( selector, SelectionKey.OP_READ);

    // 创建的链接,会构建出一个buffer对象,封装链接对象、输入输出流对象,数据读写细节
            // add this key to the map
              FrameBuffer frameBuffer = processorFactory_.isAsyncProcessor() ?
                      new AsyncFrameBuffer(client, clientKey,SelectAcceptThread.this ) :
                      new FrameBuffer(client, clientKey,SelectAcceptThread.this );

              clientKey.attach(frameBuffer);
          } catch (TTransportException tte) {
            // something went wrong accepting.
            LOGGER.warn("Exception trying to accept!", tte);
            tte.printStackTrace();
            if (clientKey != null) cleanupSelectionKey(clientKey);
            if (client != null) client.close();
          }
        }


     /**
         * Do the work required to read from a readable client. If the frame is
         * fully read, then invoke the method call.
         */
        protected void handleRead(SelectionKey key) {
          FrameBuffer buffer = (FrameBuffer) key.attachment();
    // 从输入流读取数据放入 buffer中
          if (!buffer.read()) {
            cleanupSelectionKey(key);
            return;
          }

          // if the buffer's frame read is complete, invoke the method.
          if (buffer.isFrameFullyRead()) {
    // 如果数据读取完成了,就调用 THsHaServer.requestInvoke 方法
            if (!requestInvoke(buffer)) {
              cleanupSelectionKey(key);
            }
          }
        }
    requestInvoke 方法实际上是构建一个Runnable对象,扔到线程池去处理,实际最终会调用 FrameBuffer.invoke 方法
     protected boolean requestInvoke(FrameBuffer frameBuffer) {
        try {
          Runnable invocation = getRunnable(frameBuffer);
    // 构建线程任务,扔到线程池
          invoker.execute(invocation);
          return true;
        } catch (RejectedExecutionException rx) {
          LOGGER.warn("ExecutorService rejected execution!", rx);
          return false;
        }
      }

    看下 FrameBuffer.invoke , 里面我们可以看到 processorFactory_.getProcessor( inTrans_).process( inProt_outProt_);
    这里我看到了之前 说的 Processor 的方法的入口
    /**
         * Actually invoke the method signified by this FrameBuffer.
         */
        public void invoke() {
          frameTrans_.reset(buffer_.array());
          response_.reset();
         
          try {
            if (eventHandler_ != null) {
              eventHandler_.processContext( context_, inTrans_, outTrans_);
            }
    // process 方法就会触发Processor层的处理了
            processorFactory_.getProcessor( inTrans_).process( inProt_, outProt_);
            responseReady();
            return;
          } catch (TException te) {
            LOGGER.warn("Exception while invoking!", te);
          } catch (Throwable t) {
            LOGGER.error("Unexpected throwable while invoking!", t);
          }
          // This will only be reached when there is a throwable.
          state_ = FrameBufferState. AWAITING_CLOSE;
          requestSelectInterestChange();
        }


    5.client
    下面看下client端,是如何发起调用的
    /*
              * 这里的client 为thrift 编译生成的代码 HelloService 里client类
              */
             Client client = new Client(protocol);
            
             /*
              * 调用 方法 helloWorld  整个 RPC调用过程由thrift处理,feel so easy
              */
             String res = client.helloWorld( "I'm client");

    看下 client类的 helloWorld 方法
    逻辑很明确, 发起调用请求,然后等待获取调用结果
     public String helloWorld(String hello) throws org.apache.thrift.TException
        {
          send_helloWorld(hello);
          return recv_helloWorld();
        }

        public void send_helloWorld(String hello) throws org.apache.thrift.TException
        {
          helloWorld_args args = new helloWorld_args();
          args.setHello(hello);
          sendBase("helloWorld", args);
        }

        public String recv_helloWorld() throws org.apache.thrift.TException
        {
          helloWorld_result result = new helloWorld_result();
          receiveBase(result, "helloWorld");
          if (result.isSetSuccess()) {
            return result. success;
          }
          throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "helloWorld failed: unknown result");
        }

    调用的 sendBase receiveBase 这两个方法封装了数据读写的逻辑
    protected void sendBase(String methodName, TBase args) throws TException {
        oprot_.writeMessageBegin( new TMessage(methodName, TMessageType. CALL, ++seqid_));
        args.write(oprot_);
        oprot_.writeMessageEnd();
        oprot_.getTransport().flush();
      }

      protected void receiveBase(TBase result, String methodName) throws TException {
        TMessage msg = iprot_.readMessageBegin();
        if (msg.type == TMessageType. EXCEPTION) {
          TApplicationException x = TApplicationException. read(iprot_);
          iprot_.readMessageEnd();
          throw x;
        }
        if (msg.seqid != seqid_) {
          throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID , methodName + " failed: out of sequence response" );
        }
        result.read(iprot_);
        iprot_.readMessageEnd();
      }
    展开全文
  • thrift原理浅析

    2021-04-02 15:03:40
    RPC 原理 RPC( Remote Procedure Call ) 远程调用过程。 1. 定义了一个接口文件,描述了对象,对象成员,接口方法等一系列信息。 2.通过RPC 框架提供的编译器,将接口说明文件编译成对应的语言文件。 2. 在客户端和...

    RPC 原理

    RPC( Remote Procedure Call ) 远程调用过程。

    1. 定义了一个接口文件,描述了对象,对象成员,接口方法等一系列信息。
    2.通过RPC 框架提供的编译器,将接口说明文件编译成对应的语言文件。
    2. 在客户端和服务的分别引用 RPC 编译器生成的文件,即可像调用本地方法一样远程调用。
    

    RPC 通信过程如下:
    在这里插入图片描述

    1. 客户端以正常方式调用客户桩(client stub)
    2. 客户桩生成一个消息,然后调用本地操作系统。
    3. 客户端操作系统将消息发送给原程操作系统。
    4. 远程操作系统将消息交给服务器桩
    5. 服务器桩将参数提取出来,然后调用服务过程
    6. 服务器执行要求的操作,操作完成后将结果返回给服务器桩,
    7. 服务器桩将结果打包成一个消息, 然后调用本地操作系统。
    8. 服务器操作系统将含有结果的消息发送给客户端操作系统
    9. 客户端操作系统将消息交给客户桩
    10. 客户桩将结果提取出来,返回给他的调用方 
    
    • 资源粒度, RPC 调用类似于本地调用,RESTful API 每一次添加接口都可能需要额外开发接口的数据,这相当于应用视图中再写一次方法调用。
    • 流量消耗,RestFull API 在应用层和使用 HTTP 协议, 即使是传输高效的 JSON 也会消耗较大流量, RPC 可以使用 TCP,也可以使用 UDP , 而且可以编码,降低数据大小和减少流量消耗。

    Thrift 架构

    Thrift 作用于各个服务之间的 RPC 通信,支持跨语言,thrift 是一个典型的 CS 框架,客户端服务端可以使用不同的语言开发, thrift 通过 IDL (Interface Description Language) 来关联客户端和服务器。

    Thrift 整体架构

    在这里插入图片描述

    • your code 是业务逻辑代码
    • FooService.Client /Foo.Processor() + Foo.Write() Foo.Read是 thrift 根据 IDL 生成的客户端和服务端代码,对应的是 RPC 中的 Client Stub 和 Server Stub
    • TProtocol 是用来对数据进行序列化和反序列化。
    • TTransport 提供传输数据功能,使用 Apache Thrift 可以方便的定义一个服务并选择不同的传输协议。

    Thrift 网络栈架构

    在这里插入图片描述

    TTransport 层

    • TSocket :阻塞 Socket
    • TFrametransport :以 frame 为单位进行传输, 非阻塞式服务中使用
    • TFileTransport : 以文件形式进行传输

    TProtocol 层

    代表 thrift 客户端和服务端之间的传输数据的协议,指的是客户端和服务端传输数据的格式,比如 Json, thrift 中有如下格式:

    • TBinaryProtocol:二进制格式
    • TCompactProtocol: 压缩格式
    • TJSONProtocol : Json 格式
    • TSimpleJsonProtocol: 提供只写的 JSON 协议

    Thrift 支持的 Server 模型

    • TSimpleServer : 用于简单的单线程模型,常用于测试
    • TThreadPoolServer :多线程模型,使用标准的阻塞 IO
    • TNoBlockingServer: 多线程服务模型,使用非阻塞 IO,需要使用TFramedTransport 数据传输方式。
    • THsHaServer : THsHa 引入了线程池去处理,其模型读写任务放到线程池去处理,Half-sync/Half-async处理模式,Half-async是在处理IO事件上(accept/read/write io),Half-sync用于handler对rpc的同步处理;

    Thrift 支持的基本数据类型

    • byte: 有符号字节
    • i16: 16 位有符号整数
    • i32 : 32 位有符号整数
    • i64: 64 位有符号整数
    • double : 64 位浮点数
    • string : 字符串

    Thrift 支持的容器类型

    • list: 一系列由 T 类型的数据组成的有序列表, 元素可以重复
    • set : 一系列由 T 类型组成的无序集合,元素不可以重复
    • map: 一个字典结构,Key 为 K 类型, Value 为 V 类型,和 Java 中的 HashMap 类似

    thrift 支持 struct 类型,可以将一些数据类型聚合到一块。

    struct People {
        1:string name;
        2:i32 age;
        3:string gender;
    }
    

    thrift 支持枚举类型

    enum Gender {
        MALE,
        FEMALE
    }
    

    thrift 支持异常类型

    exception RequestException {
        1:i32 code;
        2:string reason;
    }
    

    thrift 定义 Service. 格式如下:

    service HelloWorldService {
        // service中可以定义若干个服务,相当于Java Interface中定义的方法
        string doAction(1:string name, 2:i32 age);
    }
    

    thrift 支持给类型定义别名

    typedef i32 int
    typedef i64 long
    

    thrift. 支持常量的定义

    const i32 MAX_RETRIES_TIME = 10;
    const string MY_WEBSITE = "http://facebook.com";
    

    thrift 支持命名空间,相当于 Java 中的package.

    namespace java com.test.thrift.demo
    

    #、//、/**/都可以作为thrift文件中的注释。

    thrift提供两个关键字required和optional,分别用于表示对应的字段是必填的还是可选的(推荐尽量使用optional),如下

    struct People {
        1:required string name;
        2:optional i32 age;
    }
    

    thrift也支持文件包含,相当于CPP中的include,Java中的import,使用关键字include:

    include "global.thrift"
    

    thrift IDL 例子

    // data.thrift
    namespace java thrift.generated
    namespace py py.thrift.generated
    
    typedef i16 short
    typedef i32 int
    typedef i64 long
    typedef bool boolean
    typedef string String
    
    // struct关键字用于定义结构体,相当于面向对象编程语言中的类
    struct Person {
        // 相当于定义类中的成员,并生成相应的get和set方法,optional表示username这个成员可以没有
        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 data),
        void savePerson(1: required Person person)
    }
    

    执行 thrift --gen java src/thrift/data.thrift 生成代码.

    thrift 如何安装,可参考 https://wangxiaoming.blog.csdn.net/article/details/114317905

    客户端可以向调用本地的方法一样调用服务端的方法

    生成代码结构如下:
    在这里插入图片描述

    欢迎关注公众号:程序员开发者社区

    在这里插入图片描述

    参考资料

    • https://www.cnblogs.com/jpfss/p/10881220.html
    展开全文
  • thrift原理分析

    2018-07-16 09:19:46
    简介Thrift是一款Facebook开发的rpc框架( remote procedure call),并且已经加入到Apache项目。Thrift是采用二进制编码协议,...
        

    简介

    • Thrift是一款Facebook开发的rpc框架( remote procedure call),并且已经加入到Apache项目。

    • Thrift是采用二进制编码协议,使用TCP/IP传输协议的一种RPC实现,而XML-RPC/JSON-RPC/SOAPWSDL协议栈采用文本协议WSDL的实现WebService采用HTTP作为传输协议,对于网络数据传输,TCP/IP协议的性能要高于HTTP协议,不仅因为HTTP协议是应用层协议,HTTP协议传输内容除了应用数据本身之外,还有响应状态码、Header信息等。

    RPC介绍

    可以用一张图体现:

    640?wx_fmt=png

    Thrift工作流程

    1. 设计所需要的服务

    2. 根据设计的服务,编写Thrift IDL服务描述文件

    3. 根据编写的Thrift IDL服务描述文件使用Thrift提供的代码生成工具生成服务端与客户端的代码

    4. 实现服务端业务逻辑的编写,同时实现客户端调用代码的编写

    5. 运行服务端与客户端

    Thrift内部运行

    Thrift运行时的网络堆栈包括TransportProtocolProcessorServer四个部分。如下图所示:

    640?wx_fmt=png

    Transport

    • Transport:提供了通过网络读写数据的方法;

    • Thrift 源码中,则是通过将 socket 包装成各种 Transport 来使用

    • java实现方式:

      a、TSocketTIOStreamTransport基于阻塞I/O模型;

      b、TnonblockingTransortTNonblockingSocket基于非阻塞模型;

      c、TMemoryInputTransportTMemoryBuffer基于字节数组作为输入输出流的封装;

      d、TFastFramedTransport是内存利用率更高的一个内存读写缓存区,它使用自动增长的byte[](长度不够才新建)而不是每次都新建一个byte[],提高了内存使用率;

    Protocol

    • Transport:提供了对网络传输数据进行序列化/反序列化的具体实现

    • java实现方式:

      a、TbinaryProtocol:二进制格式传输协议

      b、TCompactProtocol:压缩二进制格式传输协议

      c、TJSONProtocol:JSON格式传输协议

      d、TSimpleJSONProtocol:简单的JSON格式数据传输协议

      e、TDebugProtocol:调试时使用的文本传输协议

    •  protocol 就是 transport 的上一层。 transport 负责数据传输, 但是要使得程序知道传输的数据具体是什么, 还得靠 protocol 这个组件来对数据进行解析, 解析成对应的结构代码供程序直接调用。

    Processor

    • Thrift通过使用编写的Thrift IDL描述文件来自动生成Processor,它从负责输入的Protocol读取数据,将其传递给处理程序,并将结果发送到负责输出的Protocol

    • Processor:通过 transport protocol 这两层之后, 程序已经可以获得对应的数据结构,但是数据结构需要被使用才有价值。 Thrift 里面,就是被 processor调用。

    Server

    • ServerTransportProtocolProcessor组合在一起,将服务运行起来,在指定的端口等待调用端的请求

    • java实现方式:

      a、TnonblockingServer:基于多线程非阻塞I/O模型实现,适用于连接数较多的高并发环境

      b、TthreadPoolServer:基于多线程阻塞I/O模型实现,比TNonblockingServer需要耗费更多的系统资源

      c、ThsHaServer:半同步、异步服务器

      d、TsimpleServer:基于单线程的阻塞I/O模型实现,主要用于测试,不推荐在生产环境中使用

    Client

    • 一个同步调用的客户端Client,一个异步调用的客户端AsyncClient

    640?wx_fmt=png

    640?wx_fmt=jpeg640?wx_fmt=jpeg

    640?wx_fmt=png

    Thrift数据类型

    640?wx_fmt=png

    640?wx_fmt=png

    640?wx_fmt=png

    640?wx_fmt=png

    640?wx_fmt=png

    640?wx_fmt=png

    Thrift实现方式

    1. IDL描述性语言:当数据结构发生变化时,必须重新编辑IDL文件并生成相应的代码

    2. 基于注解的方式

    • service <-> @ThriftService注解service @ThriftMethod注解该类中的方法

    • struct <-> @ThriftStruct 注解model @ThriftField注解该类中的getter方法

    • enum <-> @ThriftEnumValue 注解enum

    总结

    本文只是简单的介绍了thrift的原理以及基本语法,后续文章会以案例的形式给出详细的分析!

    展开全文
  • Thrift原理简析

    千次阅读 2017-01-24 11:19:30
    Apache Thrift是一个跨语言的服务框架,本质上为RPC,同时具有序列化、反序列化机制;当我们开发的service需要开放出去的时候,就会遇到跨语言调用的问题,JAVA语言开发了一个UserService用来提供获取用户信息的服务,...
  • Thrift原理及过程

    千次阅读 2018-09-28 15:33:48
    Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, ...
  • thrift原理介绍

    2016-08-11 15:28:00
    http://houjixin.blog.163.com/blog/static/35628410201501655134919/ 转载于:https://www.cnblogs.com/lee-mj/p/5761116.html
  • Thrift原理学习-服务端

    2019-09-14 22:13:58
        thrift是我所在公司使用的一款广泛的RPC框架,为了在之后的使用过程中,能够在遇到问题能够快速响应,解决。对了解其原理是很有必要的。今天先从服务端代码逻辑学起。 服务端实例 使用实例:开始之前首先看一...
  • Thrift 原理与使用实例

    2016-10-07 23:00:23
    一、Thrift 框架介绍 ...Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入...Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言
  • Apache Thrift原理(一)

    2017-09-29 22:25:06
    Apache Thrift1、 主要特点: 支持多语言、并发性能高为了支持多种语言,thrift有一套自己的接口定义语言,并且通过thrift代码生成程序,能够生成各种编码语言的代码2、 使用步骤: a. 安装thrift代码生成器 b. ...
  • Thrift原理与使用实例

    2015-04-27 11:10:00
    Thrift框架介绍 1 前言 Thrift是一个跨语言的服务部署框架,最初由Faceboo开发并进入Apache开源项目。 Thrift特征如下: 1)Thrift有自己的跨机器通信框架,并提供一套库 2)Thrift是一个代码生成器,按照它...
  • 很多公司使用Thrift作为基础通信组件,相当一部分的RPC服务基于Thrift框架。公司的日UV在千万级别,Thrift很好地支持了高并发访问,并且Thrift相对简单地编程模型也提高了服务地开发效率。 Thrift源于Facebook, 目前...
  • Thrift原理简析(JAVA)

    2017-10-24 15:04:22
    Apache Thrift是一个跨语言的服务框架,本质上为RPC,同时具有序列化、反序列化机制;当我们开发的service需要开放出去的时候,就会遇到跨语言调用的问题,JAVA语言开发了一个UserService用来提供获取用户信息的服务,...
  • 本文旨在全面的介绍thrift的使用流程, 使用的例子为一个简单的加法服务程序,从客户端发送请求及操作数,服务器端返回加法结果 安装篇: windows: 直接下载windows版本的thrift编译器,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 543
精华内容 217
关键字:

thrift原理