An overview of the

The thrift network stack is divided into four layers, as shown in the following diagram:

  +-------------------------------------------+
  | Server                                    |
  | (single-threaded, event-driven etc)       |
  +-------------------------------------------+
  | Processor                                 |
  | (compiler generated)                      |
  +-------------------------------------------+
  | Protocol                                  |
  | (JSON, compact etc)                       |
  +-------------------------------------------+
  | Transport                                 |
  | (raw TCP, HTTP etc)                       |
  +-------------------------------------------+
Copy the code

Transport Layer

The transport layer is a simple abstraction of the read and write of the network transport process, decoupling the Thrift underlying transport from other functional logic (such as serialization and deserialization). Network connections are also established at the transport layer. The Transport layer is divided into TTransport (client) and TServerTransport(server). With the decorator pattern, various Transport implementations are distinguished by the concepts of node flow and wrapper flow.

  • Client Transport Layer (TTransport)
    • TIOStreamTransport: the most common transport layer implementation based on the blocking I/O model, with one input stream and one output stream for all transport operations; Perfect compatibility with Java for various I/O stream operations; Is the TSocket and TZlibTransport base class;
    • TSocket: TTransport is implemented through Socket, which is blocking and focuses on establishing connections.
    • TZlibTransport: compression of input and output streams based on InflaterInputStream and DeflaterOutputStream(java.util.zip).
    • TNonblockingSocket: Non-blocking transport via SocketChannel in NIO package, serving asynchronous client implementation;
    • TFramedTransport: Using TByteBuffer of NIO package to read and write cache, TTransport decorator is implemented in stack frame transfer unit; Frame header uses 4 padding bytes to store the length of data stream and ensure the integrity of data.
    • TFileTransport: Used to write data to a file. JAVA supports only read operations but not write operations.
  • Server transport layer (TServerTransport)
    • TServerSocket: server-side blocking transport layer, based on ServerSocket implementation;
    • TNonblockingServerSocket: server side non-blocking transport layer, based on NIO ServerSocketChannel implementation;

Protocol Layer

Protocol abstraction, which defines a mechanism for mapping in-memory data structures to wired formats, is a wrapper over Transport; Simply speaking, it is the realization of serialization/deserialization of network transmission data stream.

  • TBinaryProtocol: data transmission protocol in binary encoding format;
  • TCompactProtocol: an efficient, dense, compressed binary data transfer protocol;
  • TJSONProtocol: Uses THE JSON encoding format to transmit the protocol, and the captured packet format is visible.
  • TSimpleJSONProtocol: simple JSON format data transfer protocol; Write only, for scripting language output, be careful not to be confused with the full-featured TJSONProtocol;
//TSimpleJSONProtocol
public static void main(String[] args) {
    try{
        Player playerDemo = new Player().setName("Sky Brother.").setGender(GenderEnum.FEMALE).setRole(RoleEnum.MAGE);
        FileOutputStream fos = new FileOutputStream("person.txt");
        TIOStreamTransport transport = new TIOStreamTransport(fos);
        SimpleJSONProtocol simpleJSONProtocol = new TSimpleJSONProtocol(transport);
        simpleJSONProtocol.writeMessageBegin(new TMessage("player",TMessageType.CALL, 0)); 
        playerDemo.write(simpleJSONProtocol);
        simpleJSONProtocol.writeMessageEnd();
        simpleJSONProtocol.getTransport().flush();
        fos.close();
    } catch (Exception e){
        e.printStackTrace();
    }
// File contents
["player".1.0, {"id":0."name":"Sky Brother."."role":2."gender":2}]
Copy the code

Processor layer

Thrift is an abstraction of the ability to read data from an input stream and write data to an output stream, which is represented by an instance of TProtocol. Interface abstraction is very simple.

// Only when defining the Server, the client does not need to care; Sample code:
//PlayerServiceImpl is an implementation of playerService. Iface;
private PlayerServiceImpl playerService = new PlayerServiceImpl();
/ / Server definition
PlayerService.Processor<PlayerService.Iface> processor = new PlayerService.Processor<>(playerService);
TServerTransport transport = new TServerSocket(3041);
TServer server = new TSimpleServer(new TServer.Args(transport).processor(processor));
System.out.println("Starting the simple server...");
server.serve();
Copy the code

TMultiplexedProcessor

In the example above, a Server is bound to only one Service. In actual projects, there are often a large number of interface services. If all interface methods are written in a Service interface file, it will bring a lot of hidden dangers and inconvenience in code structure optimization, readability and subsequent maintenance. Fortunately, Thrift provides the TMultiplexedProcessor and TMultiplexedProtocol classes to help developers split and assemble business interface services.

API dependency package add service name enumeration class specification call:

// Define a service enumeration class ServiceEnum to constrain the service name;
public enum ServiceEnum {
    PLAYER("PlayerService"),
    GUILD("GuildService");

    private String serviceName;
    
    ServiceEnum(String service) {
        this.serviceName = service;
    }

    public String getServiceName(a) {
        return serviceName;
    }

    public ServiceEnum setServiceName(String serviceName) {
        this.serviceName = serviceName;
        return this; }}Copy the code

The server use TMultiplexedProcessor class register multiple interface of the service implementation class:

TMultiplexedProcessor multiplexedProcessor = new TMultiplexedProcessor();
multiplexedProcessor.registerProcessor(ServiceEnum.PLAYER.serviceName,
 new PlayerService.Processor<PlayerService.Iface>(new PlayerServiceImpl()));
multiplexedProcessor.registerProcessor(ServiceEnum.GUILD.serviceName,
 new GuildService.Processor<GuildService.Iface>(new GuildServiceImpl()));
Copy the code

The TMultiplexedProtocol class is used by the Client to create Client instances to help distinguish between the specific service interfaces to be invoked:

TProtocol protocol = new TBinaryProtocol(transport);
PlayerService.Client playerService = new PlayerService.Client(
    new TMultiplexedProtocol(protocol, ServiceEnum.PLAYER.serviceName));
GuildService.Client playerService = new GuildService.Client(
    new TMultiplexedProtocol(protocol, ServiceEnum.GUILD.serviceName));
Copy the code

Server Layer

The Server combines the aforementioned Thrift features such as TTransport, TProtocol, and TProcessor to create a Server example that provides interface services externally. The basic working process is as follows:

  1. Create a transport instance and set up the connection channel.
  2. Create input/output stream transport protocol protocols for Transport;
  3. Create a processor based on the transport protocol.
  4. Wait for the connection to be connected and forward it to the processor.

  • TSimpleServer:

    • In this mode, there is only one worker thread, receiving requests and processing data in one thread;
    • A simple blocking IO form that can only handle one request at a time;
    • Multiple client requests are processed sequentially, so they are mostly used for demos, not production environments;
    • The working mode is similar to the common socket sample code:
    while(true){
        serverSocket.accept();
        //process accept
        read();
        write();
        }
    Copy the code
  • TNonblockingServer:

    • This mode also has only one worker thread. Compared with TSimpleServer mode, this mode adopts IO multiplexing.
    • Based on IO multiplexing implementation, non-blocking IO, using selector can listen to multiple incoming connection requests at the same time;
    • Although multiple requests are monitored at the same time, the processing of the requests is still serial, which cannot make full use of the advantages of multi-core, and the blocking of a request processing will directly affect the processing of subsequent requests.
    • TFramedTransport must be used in this mode;
    • This model can be compared with the single-thread model of Reactor model.
  • TThreadPoolServer:

    • This mode is an optimization of TSimpleServer mode, also based on blocking IO implementation, can only listen to one request connection at a time;
    • The thread pool technology is adopted. After the request arrives, it is handed over to the worker thread for processing. Multithreading processes the READ and write of IO in parallel.
    • The processing of a single request does not affect the overall performance of the server, but the size of the connection pool determines the working ability of this mode.
  • THsHaServer:

    • This mode can be understood as the optimization of TNonblockingServer, semi-synchronous and semi-asynchronous working mode;
    • Based on IO multiplexing implementation, non-blocking IO;
    • Based on thread pool technology, IO read and write of multiple requests are handed to worker threads for parallel processing.
    • This mode must use TFramedTransport;
    • This model can be compared with the single Reactor model and multithreading model.
  • TThreadedSelectorServer:

    • This mode is the most advanced, complex, and efficient working mode currently provided by Thrift; It can be understood by analogy with the principal and slave Reactor model.
    • An AcceptThread, based on IO multiplexing, listens for and processes multiple incoming connections at the same time. And passes the new connection to the Selector thread pool for further processing;
    • A Selector thread pool object that maintains multiple selectors simultaneously to service new connections. Several other modes of non-blocking IO implementations work with only one Selector;
    • A load balancer SelectorThreadLoadBalancer object, namely the Dispather in Reactor; Responsible for deciding and forwarding new connections to a specific Selector;
    • An ExecutorService worker thread pool object, where Woker Thead does the logical processing for each request;

reference

  • [1] official concept introduction (https://thrift.apache.org/docs/concepts.html)
  • [2] the official JAVA tutorial (https://thrift.apache.org/tutorial/java.html)
  • [3] www.cnblogs.com/mikisakura/…