天天看點

Thrift 小試牛刀

Thrift 官網位址:https://thrift.apache.org/   使用版本 0.9.3

Thrift  0.9.3 下載下傳位址:https://thrift.apache.org/download   下載下傳thrift-0.9.3.tar.gz 和  thrift-0.9.3.exe

Thrift allows developers to define datatypes and service interfaces in a single language-neutral file and generate all the necessary code to build RPC clients and servers.

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() 
 }
           

切換到thrift-0.9.3.exe 所在目錄。執行如下指令:

thrift-0.9.3 --gen java Hello.thrift

會在gen-java 目錄下面生成Hello.java檔案。

建立maven項目,添加libthrift 依賴。

<dependency>

  <groupId>org.apache.thrift</groupId>

  <artifactId>libthrift</artifactId>

  <version>0.9.3</version>

</dependency>

HelloServiceImpl 類來實作在Hello.thrift定義的方法。

public class HelloServiceImpl implements Hello.Iface {
	@Override
	public String helloString(String 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 boolean helloBoolean(boolean para) throws TException {
		return para; 
	}
	@Override
	public void helloVoid() throws TException {
		 System.out.println("Hello World"); 
		
	}
	@Override
	public String helloNull() throws TException {
		// TODO Auto-generated method stub
		return null;
	}
}
           

Thrift RPC 伺服器端代碼:JavaServer

public class JavaServer {
  public static Hello.Processor<HelloServiceImpl> processor;
  public static void main(String [] args) {
    try {
    processor = new Hello.Processor<HelloServiceImpl>(new HelloServiceImpl());

      Runnable simple = new Runnable() {
        public void run() {
          simple(processor);
        }
      };      
      new Thread(simple).start();
 
    } catch (Exception x) {
      x.printStackTrace();
    }
  }
  public static void simple(Processor<HelloServiceImpl> processor) {
    try {
      TServerTransport serverTransport = new TServerSocket(9090);
      TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

      // Use this for a multithreaded server
      // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
      System.out.println("Starting the simple server...");
      server.serve();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
           

Thrift 用戶端調用代碼:JavaClient.java

public class JavaClient {
	public static void main(String[] args) {
		 try { 
	         // 設定調用的服務位址為本地,端口為 9090 
	         TTransport transport = new TSocket("localhost", 9090); 
	         transport.open(); 
	         // 設定傳輸協定為 TBinaryProtocol 
	         TProtocol protocol = new TBinaryProtocol(transport); 
	         Hello.Client client = new Hello.Client(protocol); 
	         // 調用服務的 helloVoid 方法
	         client.helloVoid(); 
	         try {
				client.helloNull();
			} catch (Exception e) {
				// TODO: handle exception
			}
			String helloString = client.helloString("hello world");
	         System.out.println("helloString:"+helloString);
	         int helloInt = client.helloInt(111);
	         System.out.println("helloInt:"+helloInt);
	         transport.close(); 
	     } catch (TTransportException e) { 
	         e.printStackTrace(); 
	     } catch (TException e) { 
	         e.printStackTrace(); 
	     } 
	}
}
           

Apache Thrift goal is to make reliable, performant communication and data serialization across languages as efficient and seamless as possible. Originally developed at Facebook, Thrift was open sourced in April 2007 and entered the Apache Incubator in May, 2008. Thrift became an Apache TLP in October, 2010.

Transport

The Transport layer provides a simple abstraction for reading/writing from/to the network. This enables Thrift to decouple the underlying transport from the rest of the system (serialization/deserialization, for instance).

While the above protocols describe "what" is transmitted, Thrift's transports are the "how". Here are a number of transports that Thrift supports:

TSocket - Uses blocking socket I/O for transport.

TFramedTransport - Sends data in frames, where each frame is preceded by a length. This transport is required when using a non-blocking server.

TFileTransport - This transport writes to a file. While this transport is not included with the Java implementation, it should be simple enough to implement.

TMemoryTransport - Uses memory for I/O. The Java implementation uses a simple ByteArrayOutputStream internally.

TZlibTransport - Performs compression using zlib. Used in conjunction with another transport. Not available in the Java implementation.

Here are some of the methods exposed by the Transport interface:

  • open
  • close
  • read
  • write
  • flush

In addition to the  Transport  interface above, Thrift also uses a  ServerTransport  interface used to accept or create primitive transport objects. As the name suggest,  ServerTransport  is used mainly on the server side to create new Transport objects for incoming connections.

  • open
  • listen
  • accept
  • close

Here are some of the transports available for majority of the Thrift-supported languages:

  • file: read/write to/from a file on disk
  • http: as the name suggests

Protocol

The Protocol abstraction defines a mechanism to map in-memory data structures to a wire-format. In other words, a protocol specifies how datatypes use the underlying Transport to encode/decode themselves. Thus the protocol implementation governs the encoding scheme and is responsible for (de)serialization. Some examples of protocols in this sense include JSON, XML, plain text, compact binary etc.

Thrift supports both text and binary protocols. The binary protocols outperform the text protocols, but there are times when the text protocols may be useful (such as in debugging). Some of the protocols Thrift supports:

TBinaryProtocol - A straight-forward binary format encoding numeric values as binary, rather than converting to text.

TCompactProtocol - Very efficient, dense encoding of data (See details below).

TDenseProtocol - Similar to TCompactProtocol but strips off the meta information from what is transmitted, and adds it back in at the receiver. TDenseProtocol is still experimental and not yet available in the Java implementation.

TJSONProtocol - Uses JSON for encoding of data.

TSimpleJSONProtocol - A write-only protocol using JSON. Suitable for parsing by scripting languages

TDebugProtocol - Uses a human-readable text format to aid in debugging.

interface TProcessor {

    bool process(TProtocol in, TProtocol out) throws TException

}

Service-specific processor implementations are generated by the compiler. The Processor essentially reads data from the wire (using the input protocol), delegates processing to the handler (implemented by the user) and writes the response over the wire (using the output protocol).

Server

A Server pulls together all of the various features described above:

  • Create a transport
  • Create input/output protocols for the transport
  • Create a processor based on the input/output protocols
  • Wait for incoming connections and hand them off to the processor

Lastly, Thrift provides a number of servers:

TSimpleServer - A single-threaded server using std blocking io. Useful for testing.

TThreadPoolServer - A multi-threaded server using std blocking io.

TNonblockingServer - A multi-threaded server using non-blocking io (Java implementation uses NIO channels). TFramedTransport must be used with this server.

Creating A Thrift Service

Creating a Thrift service first requires creating a Thrift file describing a service, generating the code for the service, and finally writing some supporting code to start the service and client code to call it.