热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

thrift学习笔记(一)thrift简介及第一个helloword程序

简介facebook开源的RPC框架,秉承了Facebook一贯的只管拉屎不管擦屁股的作风.Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件

简介

facebook开源的RPC框架,秉承了Facebook一贯的只管拉屎不管擦屁股的作风.
Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Javascript, Node.js, Smalltalk, and OCaml 等等编程语言间无缝结合的、高效的服务。
Thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。

Windows下安装thrift
  1. 到官网下载Windows版本的编译器(thrift-0.9.3.exe):http://thrift.apache.org/download
  2. 下载完成后放到【C:\Program Files\Thrift】目录下,并将名字改为【thrift.exe】。注:这里改名只是为了敲命令行方便
  3. 将目录【C:\Program Files\Thrift】添加到环境变量即可

到此thrift安装完成,简单吧,我们来验证一下。
编写helloword服务接口描述文件代码:

Hello.thrift

namespace java service.demo
service Hello{
    string helloString(1:string para)
    i32 helloInt(1:i32 para)
    bool helloBoolean(1:bool para)
    void helloVoid()
    string helloNull()
}

命名为【Hello.thrift】放到【D:\workSpaceIdea\thrift】目录下,执行命令【thrift –gen java Hello.thrift】生成java文件:
技术分享

创建第一个thrift程序

创建一个maven项目

目录结构:
技术分享

pom 文件:

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.lblgroupId>
    <artifactId>thrift.demoartifactId>
    <version>1.0-SNAPSHOTversion>

    <dependencies>
        <dependency>
            <groupId>org.apache.thriftgroupId>
            <artifactId>libthriftartifactId>
            <version>0.9.3version>
        dependency>
        
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>1.7.12version>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.11version>
            <scope>testscope>
        dependency>
    dependencies>

project>

注:Hello.java是通过thrift自动生成的

HelloServiceImpl.java是实现类:

package service.demo;

import org.apache.thrift.TException;
 public class HelloServiceImpl implements Hello.Iface {
    @Override
 public boolean helloBoolean(boolean para) throws TException {
        return para;
  }
    @Override
 public int helloInt(int para) throws TException {
        try {
            Thread.sleep(20000);
 } catch (InterruptedException e) {
            e.printStackTrace();
 }
        return para;
 }
    @Override
 public String helloNull() throws TException {
        return null;
 }
    @Override
 public String helloString(String para) throws TException {
        System.out.println("入参:" + para);
 return "hello  " + para;
  }
    @Override
 public void helloVoid() throws TException {
        System.out.println("Hello World");
 }
 }
 ```
使用线程池模式的server

HelloServiceServer.java  
```java
package server;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import service.demo.Hello;
import service.demo.HelloServiceImpl;

public class HelloServiceServer {
    /**
     * 启动 Thrift 服务器
 * @param args
 */
 public static void main(String[] args) {
        try {
            // 设置服务端口为 7911
  TServerSocket serverTransport = new TServerSocket(7911);
  // 设置协议工厂为 TBinaryProtocol.Factory
  TBinaryProtocol.Factory proFactory = new TBinaryProtocol.Factory();
  // 关联处理器与 Hello 服务的实现
  TProcessor processor = new Hello.Processor(new HelloServiceImpl());
  TThreadPoolServer.Args args1 = new TThreadPoolServer.Args(serverTransport);
  args1.processor(processor);
  args1.protocolFactory(proFactory);

  TServer server = new TThreadPoolServer(args1);
  System.out.println("Start server on port 7911...");
  server.serve();
  } catch (TTransportException e) {
            e.printStackTrace();
  }
    }
 }




"se-preview-section-delimiter">

HelloServiceClient.java

运行
运行server以后,运行client,会在server的console控制台看到输出内容

注意:
客户端和服务端要使用同一中 Protocol 和 Transport,否则会抛出异常
TNonblockingServer 服务模型 的 server
HelloServiceServer1.java 展开原码
HelloServiceClient1.java 展开原码

我在开发中遇到的错误及解决办法
java.lang.NoSuchMethodError: org.apache.thrift.EncodingUtils.setBit(BIZ)B
出现这个问题的原因是dubbox本身集成的thrift版本是0.8.0,我添加的版本是0.9.3导致的,解决方法:去掉对0.8.0版本的依赖

这个问题是因为我thrift的IDL描述文件多了个逗号,在thrift生产java文件的时候没有报错,但是在dubbox运行的时候就出错了。

IDL文件简介
基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:utf-8编码的字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:
service:对应服务的类
数据传输协议
注:不同版本稍有区别

TBinaryProtocol : 二进制格式.
TCompactProtocol : 压缩格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析

数据传输格式 类型 优点 缺点
Xml 文本
1、良好的可读性
2、序列化的数据包含完整的结构
3、调整不同属性的顺序对序列化/反序列化不影响
1、数据传输量大
2、不支持二进制数据类型
Json 文本
1、良好的可读性
2、调整不同属性的顺序对序列化/反序列化不影响
1、丢弃了类型信息, 比如”price”:100, 对price类型是int/double解析有二义性
2、不支持二进制数据类型
Thrift 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制,采用id递增的方式标识并以optional修饰来添加
Google Protobuf 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制
服务模型

Thrif 提供网络模型:单线程、多线程、事件驱动。从另一个角度划分为:阻塞服务模型、非阻塞服务模型。
阻塞服务
TSimpleServer
TThreadPoolServer
非阻塞服务模型
TNonblockingServer
THsHaServer
TThreadedSelectorServer

1、TSimpleServer
TSimpleServer实现是非常的简单,循环监听新请求的到来并完成对请求的处理,是个单线程阻塞模型。由于是一次只能接收和处理一个socket连接,效率比较低,在实际开发过程中很少用到它。
2、TThreadPoolServer
ThreadPoolServer为解决了TSimpleServer不支持并发和多连接的问题, 引入了线程池。但仍然是多线程阻塞模式即实现的模型是One Thread Per Connection。
线程池采用能线程数可伸缩的模式,线程池中的队列采用同步队列(SynchronousQueue)。
ThreadPoolServer拆分了监听线程(accept)和处理客户端连接的工作线程(worker), 监听线程每接到一个客户端, 就投给线程池去处理。
TThreadPoolServer模式优点:
线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
TThreadPoolServer模式缺点:
线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
3、TNonblockingServer
TNonblockingServer采用单线程非阻塞(NIO)的模式, 借助Channel/Selector机制, 采用IO事件模型来处理。所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket,每次selector结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送,对于监听socket则产生一个新业务socket并将其注册到selector中。
select代码里对accept/read/write等IO事件进行监控和处理, 唯一可惜的这个单线程处理. 当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
4、THsHaServer
THsHaServer类是TNonblockingServer类的子类,为解决TNonblockingServer的缺点, THsHa引入了线程池去处理, 其模型把读写任务放到线程池去处理即多线程非阻塞模式。HsHa是: Half-sync/Half-async的处理模式, Half-aysnc是在处理IO事件上(accept/read/write io), Half-sync用于handler对rpc的同步处理上。因此可以认为THsHaServer半同步半异步。
THsHaServer的优点:
与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升;
THsHaServer的缺点:
主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。
5、TThreadedSelectorServer
TThreadedSelectorServer是大家广泛采用的服务模型,其多线程服务器端使用非堵塞式I/O模型,是对TNonblockingServer的扩充, 其分离了Accept和Read/Write的Selector线程, 同时引入Worker工作线程池。
(1)一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
(2)若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是有这些线程来完成;
(3)一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
(4)一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交个ExecutorService线程池中的线程完成此次调用的具体执行

MainReactor就是Accept线程, 用于监听客户端连接, SubReactor采用IO事件线程(多个), 主要负责对所有客户端的IO读写事件进行处理. 而Worker工作线程主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。因此其也是Half-Sync/Half-Async(半异步-半同步)的 。
TThreadedSelectorServer模式对于大部分应用场景性能都不会差,因为其有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况。
HelloServiceClient.java 
```java
package client;

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;
import org.apache.thrift.transport.TTransportException;
import service.demo.Hello;

 public class HelloServiceClient {
 /**
     * 调用 Hello 服务
 * @param args
 */
 public static void main(String[] args) {
        try {
            // 设置调用的服务地址为本地,端口为 7911
 TTransport transport = new TSocket("localhost", 7911);
 transport.open();
 // 设置传输协议为 TBinaryProtocol
 TProtocol protocol = new TBinaryProtocol(transport);
 Hello.Client client = new Hello.Client(protocol);
 // 调用服务的 helloVoid 方法
//            client.helloVoid();
  String resp = client.helloString("wertyuiopsdfghjkl;");
  System.out.println(resp);
  transport.close();
 } catch (TTransportException e) {
            e.printStackTrace();
 } catch (TException e) {
            e.printStackTrace();
 }
    }
 }




"se-preview-section-delimiter">

运行

运行server以后,运行client,会在server的console控制台看到输出内容
技术分享
技术分享
注意:
客户端和服务端要使用同一中 Protocol 和 Transport,否则会抛出异常
TNonblockingServer 服务模型 的 server
HelloServiceServer1.java
“`java

HelloServiceClient1.java 展开原码

我在开发中遇到的错误及解决办法
java.lang.NoSuchMethodError: org.apache.thrift.EncodingUtils.setBit(BIZ)B
出现这个问题的原因是dubbox本身集成的thrift版本是0.8.0,我添加的版本是0.9.3导致的,解决方法:去掉对0.8.0版本的依赖

这个问题是因为我thrift的IDL描述文件多了个逗号,在thrift生产java文件的时候没有报错,但是在dubbox运行的时候就出错了。

IDL文件简介
基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:utf-8编码的字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:
service:对应服务的类
数据传输协议
注:不同版本稍有区别

TBinaryProtocol : 二进制格式.
TCompactProtocol : 压缩格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析

数据传输格式 类型 优点 缺点
Xml 文本
1、良好的可读性
2、序列化的数据包含完整的结构
3、调整不同属性的顺序对序列化/反序列化不影响
1、数据传输量大
2、不支持二进制数据类型
Json 文本
1、良好的可读性
2、调整不同属性的顺序对序列化/反序列化不影响
1、丢弃了类型信息, 比如”price”:100, 对price类型是int/double解析有二义性
2、不支持二进制数据类型
Thrift 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制,采用id递增的方式标识并以optional修饰来添加
Google Protobuf 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制
服务模型

Thrif 提供网络模型:单线程、多线程、事件驱动。从另一个角度划分为:阻塞服务模型、非阻塞服务模型。
阻塞服务
TSimpleServer
TThreadPoolServer
非阻塞服务模型
TNonblockingServer
THsHaServer
TThreadedSelectorServer

1、TSimpleServer
TSimpleServer实现是非常的简单,循环监听新请求的到来并完成对请求的处理,是个单线程阻塞模型。由于是一次只能接收和处理一个socket连接,效率比较低,在实际开发过程中很少用到它。
2、TThreadPoolServer
ThreadPoolServer为解决了TSimpleServer不支持并发和多连接的问题, 引入了线程池。但仍然是多线程阻塞模式即实现的模型是One Thread Per Connection。
线程池采用能线程数可伸缩的模式,线程池中的队列采用同步队列(SynchronousQueue)。
ThreadPoolServer拆分了监听线程(accept)和处理客户端连接的工作线程(worker), 监听线程每接到一个客户端, 就投给线程池去处理。
TThreadPoolServer模式优点:
线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
TThreadPoolServer模式缺点:
线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
3、TNonblockingServer
TNonblockingServer采用单线程非阻塞(NIO)的模式, 借助Channel/Selector机制, 采用IO事件模型来处理。所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket,每次selector结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送,对于监听socket则产生一个新业务socket并将其注册到selector中。
select代码里对accept/read/write等IO事件进行监控和处理, 唯一可惜的这个单线程处理. 当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
4、THsHaServer
THsHaServer类是TNonblockingServer类的子类,为解决TNonblockingServer的缺点, THsHa引入了线程池去处理, 其模型把读写任务放到线程池去处理即多线程非阻塞模式。HsHa是: Half-sync/Half-async的处理模式, Half-aysnc是在处理IO事件上(accept/read/write io), Half-sync用于handler对rpc的同步处理上。因此可以认为THsHaServer半同步半异步。
THsHaServer的优点:
与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升;
THsHaServer的缺点:
主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。
5、TThreadedSelectorServer
TThreadedSelectorServer是大家广泛采用的服务模型,其多线程服务器端使用非堵塞式I/O模型,是对TNonblockingServer的扩充, 其分离了Accept和Read/Write的Selector线程, 同时引入Worker工作线程池。
(1)一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
(2)若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是有这些线程来完成;
(3)一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
(4)一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交个ExecutorService线程池中的线程完成此次调用的具体执行

MainReactor就是Accept线程, 用于监听客户端连接, SubReactor采用IO事件线程(多个), 主要负责对所有客户端的IO读写事件进行处理. 而Worker工作线程主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。因此其也是Half-Sync/Half-Async(半异步-半同步)的 。
TThreadedSelectorServer模式对于大部分应用场景性能都不会差,因为其有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况。

## 运行
运行server以后,运行client,会在server的console控制台看到输出内容
![这里写图片描述](http://img.blog.csdn.net/20170123111820299?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1YmVubG9uZzAwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![这里写图片描述](http://img.blog.csdn.net/20170123111829393?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1YmVubG9uZzAwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
注意:
**客户端和服务端要使用同一中 Protocol 和 Transport,否则会抛出异常**
TNonblockingServer 服务模型 的 server
HelloServiceServer1.java 
```java
package server;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;
import service.demo.Hello;
import service.demo.HelloServiceImpl;

public class HelloServiceServer1 {

    public static final int SERVER_PORT = 8090;

  /**
     * 启动 Thrift 服务器
 * @param args
 */
 public static void main(String[] args) {
        try {
            System.out.println("HelloWorld TNonblockingServer start ....");

  TProcessor tprocessor = new Hello.Processor(new HelloServiceImpl());

  TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(SERVER_PORT);
  TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(tnbSocketTransport);
  tnbArgs.processor(tprocessor);
  tnbArgs.transportFactory(new TFramedTransport.Factory());
  tnbArgs.protocolFactory(new TCompactProtocol.Factory());

  // 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式
  TServer server = new TNonblockingServer(tnbArgs);
  server.serve();
  } catch (TTransportException e) {
            e.printStackTrace();
  }
    }
 }




"se-preview-section-delimiter">

HelloServiceClient1.java
“`java

我在开发中遇到的错误及解决办法
java.lang.NoSuchMethodError: org.apache.thrift.EncodingUtils.setBit(BIZ)B
出现这个问题的原因是dubbox本身集成的thrift版本是0.8.0,我添加的版本是0.9.3导致的,解决方法:去掉对0.8.0版本的依赖

这个问题是因为我thrift的IDL描述文件多了个逗号,在thrift生产java文件的时候没有报错,但是在dubbox运行的时候就出错了。

IDL文件简介
基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:utf-8编码的字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:
service:对应服务的类
数据传输协议
注:不同版本稍有区别

TBinaryProtocol : 二进制格式.
TCompactProtocol : 压缩格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析

数据传输格式 类型 优点 缺点
Xml 文本
1、良好的可读性
2、序列化的数据包含完整的结构
3、调整不同属性的顺序对序列化/反序列化不影响
1、数据传输量大
2、不支持二进制数据类型
Json 文本
1、良好的可读性
2、调整不同属性的顺序对序列化/反序列化不影响
1、丢弃了类型信息, 比如”price”:100, 对price类型是int/double解析有二义性
2、不支持二进制数据类型
Thrift 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制,采用id递增的方式标识并以optional修饰来添加
Google Protobuf 二进制 高效
1、不宜读
2、向后兼容有一定的约定限制
服务模型

Thrif 提供网络模型:单线程、多线程、事件驱动。从另一个角度划分为:阻塞服务模型、非阻塞服务模型。
阻塞服务
TSimpleServer
TThreadPoolServer
非阻塞服务模型
TNonblockingServer
THsHaServer
TThreadedSelectorServer

1、TSimpleServer
TSimpleServer实现是非常的简单,循环监听新请求的到来并完成对请求的处理,是个单线程阻塞模型。由于是一次只能接收和处理一个socket连接,效率比较低,在实际开发过程中很少用到它。
2、TThreadPoolServer
ThreadPoolServer为解决了TSimpleServer不支持并发和多连接的问题, 引入了线程池。但仍然是多线程阻塞模式即实现的模型是One Thread Per Connection。
线程池采用能线程数可伸缩的模式,线程池中的队列采用同步队列(SynchronousQueue)。
ThreadPoolServer拆分了监听线程(accept)和处理客户端连接的工作线程(worker), 监听线程每接到一个客户端, 就投给线程池去处理。
TThreadPoolServer模式优点:
线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
TThreadPoolServer模式缺点:
线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
3、TNonblockingServer
TNonblockingServer采用单线程非阻塞(NIO)的模式, 借助Channel/Selector机制, 采用IO事件模型来处理。所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket,每次selector结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送,对于监听socket则产生一个新业务socket并将其注册到selector中。
select代码里对accept/read/write等IO事件进行监控和处理, 唯一可惜的这个单线程处理. 当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
4、THsHaServer
THsHaServer类是TNonblockingServer类的子类,为解决TNonblockingServer的缺点, THsHa引入了线程池去处理, 其模型把读写任务放到线程池去处理即多线程非阻塞模式。HsHa是: Half-sync/Half-async的处理模式, Half-aysnc是在处理IO事件上(accept/read/write io), Half-sync用于handler对rpc的同步处理上。因此可以认为THsHaServer半同步半异步。
THsHaServer的优点:
与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升;
THsHaServer的缺点:
主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。
5、TThreadedSelectorServer
TThreadedSelectorServer是大家广泛采用的服务模型,其多线程服务器端使用非堵塞式I/O模型,是对TNonblockingServer的扩充, 其分离了Accept和Read/Write的Selector线程, 同时引入Worker工作线程池。
(1)一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
(2)若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是有这些线程来完成;
(3)一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
(4)一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交个ExecutorService线程池中的线程完成此次调用的具体执行

MainReactor就是Accept线程, 用于监听客户端连接, SubReactor采用IO事件线程(多个), 主要负责对所有客户端的IO读写事件进行处理. 而Worker工作线程主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。因此其也是Half-Sync/Half-Async(半异步-半同步)的 。
TThreadedSelectorServer模式对于大部分应用场景性能都不会差,因为其有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况。
HelloServiceClient1.java 
```java
package client;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import service.demo.Hello;

public class HelloServiceClient1 {

    public static final String SERVER_IP = "localhost";
 public static final int SERVER_PORT = 8090;
 public static final int TIMEOUT = 30000;

/**
 * 调用 Hello 服务 * @param args
  */
  public static void main(String[] args) {
       TTransport transport = null;
 try {
           transport = new TFramedTransport(new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT));
  // 协议要和服务端一致
  TProtocol protocol = new TCompactProtocol(transport);
  Hello.Client client = new Hello.Client(protocol);
  transport.open();
  String result = client.helloString("hfjtydiyghfkjdhftgh");
  System.out.println("Thrify client result =: " + result);
  } catch (TTransportException e) {
           e.printStackTrace();
  } catch (TException e) {
           e.printStackTrace();
  } finally {
           if (null != transport) {
               transport.close();
  }
       }
   }
}

我在开发中遇到的错误及解决办法
  • java.lang.NoSuchMethodError: org.apache.thrift.EncodingUtils.setBit(BIZ)B

出现这个问题的原因是dubbox本身集成的thrift版本是0.8.0,我添加的版本是0.9.3导致的,解决方法:去掉对0.8.0版本的依赖
技术分享

这个问题是因为我thrift的IDL描述文件多了个逗号,在thrift生产java文件的时候没有报错,但是在dubbox运行的时候就出错了。

IDL文件简介
  • 基本类型
    • bool:布尔值,true 或 false,对应 Java 的 boolean
    • byte:8 位有符号整数,对应 Java 的 byte
    • i16:16 位有符号整数,对应 Java 的 short
    • i32:32 位有符号整数,对应 Java 的 int
    • i64:64 位有符号整数,对应 Java 的 long
    • double:64 位浮点数,对应 Java 的 double
    • string:utf-8编码的字符串,对应 Java 的 String
  • 结构体类型:
    • struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
  • 容器类型:
    • list:对应 Java 的 ArrayList
    • set:对应 Java 的 HashSet
    • map:对应 Java 的 HashMap
  • 异常类型:
    • exception:对应 Java 的 Exception
  • 服务类型:
    • service:对应服务的类

数据传输协议

不同版本稍有区别

技术分享

  • TBinaryProtocol : 二进制格式.
  • TCompactProtocol : 压缩格式
  • TJSONProtocol : JSON格式
  • TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析
数据传输格式 类型 优点 缺点
Xml 文本 1、良好的可读性。 2、序列化的数据包含完整的结构。3、调整不同属性的顺序对序列化/反序列化不影响 1、数据传输量大。2、不支持二进制数据类型
Json 文本 1、良好的可读性。2、调整不同属性的顺序对序列化/反序列化不影响 1、丢弃了类型信息, 比如”price”:100, 对price类型是int/double解析有二义性。2、不支持二进制数据类型
Thrift 二进制 高效 1、不宜读。2、向后兼容有一定的约定限制,采用id递增的方式标识并以optional修饰来添加
Google Protobuf 二进制 高效 1、不宜读。2、向后兼容有一定的约定限制

服务模型

技术分享

Thrif 提供网络模型:单线程、多线程、事件驱动。从另一个角度划分为:阻塞服务模型、非阻塞服务模型。

  • 阻塞服务
    • TSimpleServer
    • TThreadPoolServer
  • 非阻塞服务模型
    • TNonblockingServer
    • THsHaServer
    • TThreadedSelectorServer

TSimpleServer

TSimpleServer实现是非常的简单,循环监听新请求的到来并完成对请求的处理,是个单线程阻塞模型。由于是一次只能接收和处理一个socket连接,效率比较低,在实际开发过程中很少用到它。

TThreadPoolServer

ThreadPoolServer为解决了TSimpleServer不支持并发和多连接的问题, 引入了线程池。但仍然是多线程阻塞模式即实现的模型是One Thread Per Connection。
线程池采用能线程数可伸缩的模式,线程池中的队列采用同步队列(SynchronousQueue)。
ThreadPoolServer拆分了监听线程(accept)和处理客户端连接的工作线程(worker), 监听线程每接到一个客户端, 就投给线程池去处理。
TThreadPoolServer模式优点:
线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
TThreadPoolServer模式缺点:
线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。

TNonblockingServer

TNonblockingServer采用单线程非阻塞(NIO)的模式, 借助Channel/Selector机制, 采用IO事件模型来处理。所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket,每次selector结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送,对于监听socket则产生一个新业务socket并将其注册到selector中。
select代码里对accept/read/write等IO事件进行监控和处理, 唯一可惜的这个单线程处理. 当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。

THsHaServer

THsHaServer类是TNonblockingServer类的子类,为解决TNonblockingServer的缺点, THsHa引入了线程池去处理, 其模型把读写任务放到线程池去处理即多线程非阻塞模式。HsHa是: Half-sync/Half-async的处理模式, Half-aysnc是在处理IO事件上(accept/read/write io), Half-sync用于handler对rpc的同步处理上。因此可以认为THsHaServer半同步半异步。
THsHaServer的优点:
与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升;
THsHaServer的缺点:
主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。

TThreadedSelectorServer

TThreadedSelectorServer是大家广泛采用的服务模型,其多线程服务器端使用非堵塞式I/O模型,是对TNonblockingServer的扩充, 其分离了Accept和Read/Write的Selector线程, 同时引入Worker工作线程池。
(1)一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
(2)若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是有这些线程来完成;
(3)一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
(4)一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交个ExecutorService线程池中的线程完成此次调用的具体执行
技术分享

MainReactor就是Accept线程, 用于监听客户端连接, SubReactor采用IO事件线程(多个), 主要负责对所有客户端的IO读写事件进行处理. 而Worker工作线程主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。因此其也是Half-Sync/Half-Async(半异步-半同步)的 。
TThreadedSelectorServer模式对于大部分应用场景性能都不会差,因为其有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况。

thrift学习笔记(一) thrift简介及第一个helloword程序


推荐阅读
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
author-avatar
葉の鋼琴曲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有