Sacrifice the official website first.

A former colleague came to see me yesterday. He said that he was a new employee of a big factory and used thrift request. As thrift was encapsulated inside the company, he could not see the whole process clearly. He hoped that I could tell him what thrift request should look like. All of a sudden I wonder, what makes Meituan, Toutiao and so on join the thrift camp now?

The characteristics of

So let’s talk a little bit about thrift. There are a lot of articles on thrift that mention the following. Let me just give you my personal understanding.

  • Binary – based high – performance codec framework

Binary: The binary protocol sends a smaller amount of data and is more efficient than the text protocol.

Codec framework: as RPC framework, it generally encapsulates method names, method parameters and other methods to call. The client sends the message. The server receives the message from the client, decodes the message, and then invokes the actual server-side business method through the method invocation model.

In fact, the key point in this sentence should be high performance. There are also many performance tests on the web that show thrift performs much better than HTTP. Like this article. This is partly because of the non-blocking I/O mechanism, and partly because HTTP is connectionless and stateless. Thrift allows clients to establish connections ahead of time, which is an inherent advantage in this kind of test.

  • Underlying communication based on NIO

NIO stands for NoneBlocking IO, as opposed to BIO (Blocking IO). The specific explanation and implementation mechanism is not the focus of this article. Those who are interested can directly read this article to understand.

A non-blocking IO is a Blocking IO. So what does this block mean? Write is blocked. Write is blocked until the client accepts the message. Write is blocked until the client accepts the message. So a traditional multithreaded server is BlockingIO, where all threads are blocked from beginning to end. These threads just sit there, taking up the operating system’s scheduling resources, and doing nothing is a waste. So how does NIO do that? It uses the event mechanism. It allows a single thread to dry up the logic for Accept, read and write operations, and request processing. If there is nothing to do, it does not loop, it will sleep until the next event comes, such a thread is called a NIO thread.

  • Relatively simple service invocation model

Since it’s relatively easy to compare it to. Thrift requires a protocol design compared to HTTP, but compared to XXX,

  • Use IDL to support cross-platform invocation

Generate corresponding code for different platforms. The e use of these languages is currently supported.

But the way annotations are used in Java. Generating IDL is possible (?) It’s just another workload. (I’ve actually seen more than one Java engineering lion write code and then spell idL by hand.)

Other RPC Frameworks

grpc

Chinese version document.

There is no protocol layer, server side TBinaryProtocal, TNonBlockingServer concepts to understand. The transport layer uses http2 protocol.

So the whole thing works a lot like thrift. Idl, protobuf files as well. You also need to start the client server. The code generated by GPRC is much simpler and easier to read, but this doesn’t seem to be useful.

It also supports multiple languages, but is relatively less comprehensive than thrift support. The main application is better support for the client side. Currently available in C Series, Java, Go and Node languages.

The main advantage is support for streaming processing. OAuth authentication is supported. Efficient serialization and deserialization of Protobuf. Then there are protocols that support HTTP 2.0 standardization. Oh yeah, and the documentation is relatively sound.

In contrast, the disadvantages mainly focus on the support language is not too much, performance is not thrift good. This performance test strikes me as more comprehensive and relevant.

dubbo

Chinese official website.

It was donated to Apache by Ali’s father, which means it has the largest language community directly, with its own service registration and service governance. At that time, many people chose Dubbo for this reason.

If we have to compare thrift to thrift. Let’s just say they have different priorities. Thrift worked on multilingual support, and Dubbo focused on Java for more than a decade. So there is no IDL mechanism and you interact directly through the Java Service Object interface.

Contrast and HTTP

Are based on TCP protocol implementation. The main difference is that HTTP is a connectionless, stateless protocol, whereas thrift is inefficient on each connection and shutdown. In addition, the client actively closes the Socket and enters the TIME_WAIT state, and the TIME_WAIT state lasts for 1-4 minutes.

Thrift is said to save traffic and good performance, but I don’t think it can be reflected. As a front end, the thrift interface is called. Although the browser can also make thrift requests directly, most of them are forwarded through Node for the sake of establishing connections, which feels more cumbersome than HTTP. And thrift saves traffic and good performance is not really reflected. Because the browser is still sending HTTP to Node.

Thrift also has the disadvantage of being completely static. All data structures used must be defined in advance and cannot be changed halfway through. If the data structure changes, it must be redefined, a new IDL generated, and recompiled.

See this article for details.

Anyway, choose carefully according to your needs. There is no better, only more appropriate.

Future development of Thrift?

I’m curious about that, too. Thrift is definitely not the latest technology, is it going to be a flash in the pan or is it going to be permanent I’m really curious about that.

But any new technology takes time to land. Thrift is supported by many open source projects. Hbase provides thrift service, Hive, Spark SQL, Cassandra and a series of external standard service interfaces to support multiple languages.

Thrift has its advantages but it also has its limitations, such as complete statics is its advantages and limitations. Also, thrift does not support streaming of large amounts of data.


So let’s talk about the use of thrift, and the overall process that some factories have right now.

The process of using thrift

Let’s start with the core composition of thrift. This will be covered in any tutorial, so I’ll just list it.

  • TProtocol protocol and codec components
  • TTransport Transport component
  • TProcessor service invoke component
  • TServer, Client Server and Client components
  • IDL interface definition

By the way. I’d like to compare this article if I want a more detailed look at thrift’s use, or if I’m not a front-end developer with a different focus. You can also check out the official website for type definitions.

The installation

brew install thrift
Copy the code

There are many more specific tutorials available online.

The idl file

namespace java hello.test

enum THelloType {
  HI = 1,
  HELLO = 2,
  WELCOME = 3,}struct Error {
  1:  i64 code,
  2:  string message,
}

struct THelloMessage {
  1:  string msg,
  2:  THelloType helloMsg,
}

struct TSayHelloResponse {
  1:  bool success,
  2:  Error error,
  3:  THelloMessage data
}

struct TSayHelloRequest {
  1:  string name,
  2:  list<string> friends,
}

service TSayHelloService {
  TSayHelloResponse sayHello(1: TSayHelloRequest arg0),
  map<string, set<i32>> searchWhateverByDate(1:string startDate, 2:string endDate, 3:i32 offset, 4:i32 limit)
}

Copy the code

Generating JS files

thrift --gen js:node thrift_file
Copy the code

Used in koA projects

First install the dependencies.

yarn add thrift 
Copy the code

Then start a Client server. Let’s take the idL above as an example. This step is usually performed once the project is started. TProtocol and TTransport select their own.

import thrift from 'thrift';

import HelloService from './gen-nodejs/TSayHelloService.js';
 
const connection = thrift.createConnection('127.0.0.1'.9527, {
        transport : thrift.TBufferedTransport,
        protocol : thrift.TBinaryProtocol
    });
const client = thrift.createClient(HelloService, connection);
 
connection.on('error'.function(e) {
    console.log(e);
});
Copy the code

What if you need to connect multiple services in a project? Just make a connection pool.

const configs = [{
    serviceName: 'hello'.service: require('./gen-nodejs/TSayHelloService.js'),
    types: require('./gen-nodejs/hello_types'),
    port: 9527,}];const pools = {};

configs.forEach(item= > {
    let connection = thrift.createConnection('127.0.0.1', item.port, {
        transport : thrift.TBufferedTransport,
        protocol : thrift.TBinaryProtocol
    });
    pools[item.serviceName] = thrift.createClient(item.service, connection);
});
Copy the code

Send the request.

const HELLOTYPES = require('./gen-nodejs/hello_types')

pools[hello].sayHello(new HELLOTYPES.TSayHelloRequest({
    name: 'kikooo'.friends: ['xiaoa'.'xiaob'],}).function(err, res) {
    console.log('say hello success');
});
Copy the code

This is just using the native thrift package. Of course, each factory may have its own special package.

Common packaging

In general, the following points in the process of sending a thrift request may be encapsulated. The classmate that uses for the first time can refer to the circumstance of his factory to compare look.

The connection establishment phase: Encapsulates createConnection without exposing the creation process. Such as:

new ConnectionPool({
    serviceList: config,
    retry: {
      retries: 0./ / not retry
      minTimeout: 3 * 1000.maxTimeout: 10 * 1000.randomize: false}});Copy the code

Configuration and service discovery phase: Most companies build their own service discovery. Some companies may not even expose thrift files and directly obtain them during service discovery. The configuration might look like this:

const services = {
    Hello: {
        filename: 'hello.thrift',}};// Or so
const services = [{
    remoteKey: 'xxxxx'.service: HelloService,
    serviceName: 'blablabla'
}];
// If there is no local configuration, remote configuration of the current service corresponding to the service list, etc., from the service discovery to pull all services, call when directly.
Copy the code

Send request phase: this can be packaged as middleware in various forms, such as:

app.use(thriftrequest({
    config,
}));

const res = await ctx.thriftrequest.functionService.function(req);

// Or so.
const HelloRequest = serviceExecuter({
  remoteKey: 'global.hello'.service: HelloService,
});

const res = await HelloRequest(methodName, params);
Copy the code

No matter what kind of encapsulation do not panic, anyway, the essence is still the essence.

AD time

Finally, some time ago (September 2020 as I write this. I procrastinate too much and cry. Egg-thrift mock is a mock interface that supports a variety of uses, including a link to the mock interface. Egg-thrift mock is a mock interface that can be used only in eggs. Welcome to download, trial, exchange, demand, bug~~~

I know that many large factories probably have their own thrift-mock servers. But emmm. What if there isn’t

reference

  • Why Thrift, Why not HTTP RPC(JSON+gzip)
  • Thrift RPC framework analysis
  • Moving From Apache Thrift to gRPC: A Perspective From Alluxio
  • Introduction to Thrift | RPC based && Thrift concept
  • NIO related basics
  • RPC vs Thrift
  • Understand Thrift (II) — The working principle of Thrift

I want to share with you some of the better information I found recently. Welcome to discuss ~~