I’ve recently seen some job descriptions that have requirements for thrift:
As a resume-oriented programmer who has used HTTP calls from SpringMVC for many years, I was a little curious about thrift, so the study of thrift was put on the agenda.
Basic concept of Thrift
The definition of Baidu Encyclopedia is as follows:
Thrift is an interface description language and binary communication protocol that is used to define and create cross-language services. It is used as a remote procedure call (RPC) framework developed by Facebook for “large-scale cross-language service development.”
There are no more general concepts in this article, so let’s dive right into thfrit.
Data type of Thrift
The Thrift scripts can define the following types of data:
-
Basic types:
- Boolean: the Boolean value
- Byte: an 8-bit signed integer
- I16: a 16-bit signed integer
- I32:32-bit signed integer
- I64:64-bit signed integer
- Double: 64-bit floating point number
- String: utF-8 encoded character string
- Binary: a binary string
-
Structure type:
- Struct: structure object defined
-
Container type:
- List: a list of ordered elements
- Set: Unordered collection of non-repeating elements
- Map: an ordered set of keys and values
-
Exception type:
- Exception: indicates the exception type
-
Service type:
- Service: service class
The agreement of Thrift
Thrift allows the user to select a type of communication protocol between the client and server. It is generally divided into text and binary transport protocols. To save bandwidth and improve transmission efficiency, binary transmission protocols are generally used, and text-based protocols are sometimes used based on the actual requirements of the project or product. Common protocols are as follows:
TBinaryProtocol
: Data is transmitted in binary encoding formatTCompactProtocol
: Efficient, dense binary encoding format for data transmissionTJSONProtocol
: Uses the JSON text data encoding protocol for data transmissionTSimpleJSONProtocol
: Provides only JSON write-only protocol, suitable for parsing through scripting languages
Thrift’s transport layer
The following transport layers are commonly used:
TSocket
: Using blocking I/O for transmission is the most common modeTNonblockingTransport
: Uses a non-blocking mode for building asynchronous clientsTFramedTransport
: Transfers by block size in a non-blocking manner, similar to NIO in Java
The server type of Thrift
TSimpleServer
: single-threaded server side, using standard blocking I/OTThreadPoolServer
: Multithreaded server side, using standard blocking I/OTNonblockingServer
: single-threaded server side, using non-blocking I/OTHsHaServer
: semi-synchronous and semi-asynchronous server side, based on non-blocking IO read and write and multi-threaded work task processingTThreadedSelectorServer
: Multithreaded selector server side, yesTHsHaServer
Enhancements on asynchronous IO models
With a brief overview of the above concepts, we will use an example to demonstrate the use of thrift.
The installation
Before using Thrift, you need to install the Thrift command-line utility, which compiles the thfirt files you write into the specified source file.
Install it on a Mac using the following command:
$ brew install thrift
Copy the code
After the installation is successful, view the version:
$thrift -v thrift version 0.14.1Copy the code
Install other operating systems on your own.
Writing thrift files
Here we write two services.
HelloService.thrift
namespace java com.attempt.thrift02.gen.service
service HelloService {
string hello(1: string text);
}
Copy the code
Here we define a HelloService with only a Hello (String) method inside
QueryResult.thrift
namespace java com.attempt.thrift02.gen.vo
struct QueryResult {
1: required i32 code; // The requested code is mandatory
2: optional string msg; // Request to return information, optional
}
Copy the code
Here we define an object entity with two attributes, code and MSG, to receive the return parameters.
QueryService.thrift
namespace java com.attempt.thrift02.gen.service
// Import another file
include "QueryResult.thrift"
service QueryService {
// QueryResult is in another file, using the filename. Object name
QueryResult.QueryResult query(1: i32 code);
}
Copy the code
Here’s another Service: QueryService, which has only one method: Query (…) This method returns an object as QueryResult. Since this object is in the QueryResult.thrift file, you need to include it, and when referencing it, you need to use the file name. Object name.
generate
On the command line, run the following command (specifying that the source file is Java) :
$ thrift -r --gen java QueryService.thrift
$ thrift -r --gen java HelloService.thrift
Copy the code
The QueryService.thrift file is referenced in queryService. thrift, so you just need to generate QueryService.thrift, and queryResult. thrift is automatically generated.
The generated file is as follows:
implementation
We copy the Java code generated in the previous step to SRC /main/ Java with the following directory structure:
Importing the Thrift JAR package
In addition to copying the generated files, we also need to introduce the thrift JAR package into the project. The GAV of the JAR package is as follows:
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.141.</version>
</dependency>
Copy the code
Implementation of HelloService: HelloServiceImpl
package com.attempt.thrift02.serviceImpl;
import com.attempt.thrift02.gen.service.HelloService;
import org.apache.thrift.TException;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:50 上午
*/
public class HelloServiceImpl implements HelloService.Iface {
@Override
public String hello(String text) throws TException {
return "hello, " + text + "!"; }}Copy the code
HelloServiceImpl is our own class that implements HelloService.Iface, writing our own business logic in the corresponding method, and HelloService.Iface is a class generated by thrift.
QueryService implementation: QueryServiceImpl
package com.attempt.thrift02.serviceImpl;
import com.attempt.thrift02.gen.service.QueryService;
import com.attempt.thrift02.gen.vo.QueryResult;
import org.apache.thrift.TException;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:51 上午
*/
public class QueryServiceImpl implements QueryService.Iface {
@Override
public QueryResult query(int code) throws TException {
QueryResult result = new QueryResult();
if (code == 1) {
result.code = 1;
result.msg = "success";
} else {
result.code = 0;
result.msg = "fail";
}
returnresult; }}Copy the code
Similarly, QueryServiceImpl is a class we wrote ourselves that implements QueryService.Iface, writing our own business logic in the corresponding method, whereas QueryService.Iface is a class generated by thrift.
Client and server
The next step is to implement the corresponding client for each service.
HelloService
server:
package com.attempt.thrift02.server;
import com.attempt.thrift02.gen.service.HelloService;
import com.attempt.thrift02.serviceImpl.HelloServiceImpl;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:53 上午
*/
public class HelloServer {
private static final int SERVER_PORT = 8090;
public static void main(String[] args) {
try {
HelloService.Processor processor = new HelloService.Processor<>(
new HelloServiceImpl());
TServerTransport transport = new TServerSocket(SERVER_PORT);
TServer server = new TSimpleServer(new TServer.Args(transport)
.processor(processor));
System.out.println("Starting the simple server...");
server.serve();
} catch(Exception e) { e.printStackTrace(); }}}Copy the code
client:
package com.attempt.thrift02.client;
import com.attempt.thrift02.gen.service.HelloService;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:52 上午
*/
public class HelloClient {
private static final int SERVER_PORT = 8090;
public static void main(String[] args) {
TTransport transport = null;
try {
transport = new TSocket("localhost", SERVER_PORT);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
HelloService.Client client = new HelloService.Client(protocol);
String result = client.hello("thrift world");
System.out.println("result=" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null! = transport) { transport.close(); }}}}Copy the code
Start the server:
Running the client.
QueryService
Server:
package com.attempt.thrift02.server;
import com.attempt.thrift02.gen.service.QueryService;
import com.attempt.thrift02.serviceImpl.QueryServiceImpl;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:53 上午
*/
public class QueryServer {
private static final int SERVER_PORT = 8091;
public static void main(String[] args) {
try {
QueryService.Processor processor = new QueryService.Processor<>(
new QueryServiceImpl());
TServerTransport transport = new TServerSocket(SERVER_PORT);
TServer server = new TSimpleServer(new TServer.Args(transport)
.processor(processor));
System.out.println("Starting the simple server...");
server.serve();
} catch(Exception e) { e.printStackTrace(); }}}Copy the code
Client:
package com.attempt.thrift02.client;
import com.attempt.thrift02.gen.service.QueryService;
import com.attempt.thrift02.gen.vo.QueryResult;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
/** * {add description here} **@author chengyan
* @date 2021-05-06 11:53 上午
*/
public class QueryClient {
private static final int SERVER_PORT = 8091;
public static void main(String[] args) {
TTransport transport = null;
try {
transport = new TSocket("localhost", SERVER_PORT);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
QueryService.Client client = new QueryService.Client(protocol);
QueryResult result = client.query(1);
System.out.println("query result=" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null! = transport) { transport.close(); }}}}Copy the code
Start the server:
Running the client.
The composite service
There are two thrift services in the same project. We open two ports to provide services. In actual production environment, there may be more thrift services. Thrift provides TMultiplexedProcessor to solve this problem, using the following method:
Server:
package com.attempt.thrift02.server;
import com.attempt.thrift02.gen.service.HelloService;
import com.attempt.thrift02.gen.service.QueryService;
import com.attempt.thrift02.serviceImpl.HelloServiceImpl;
import com.attempt.thrift02.serviceImpl.QueryServiceImpl;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessor;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportException;
/** * {add description here} **@author chengyan
* @date 2021-05-06 12:45 下午
*/
public class MultipleServer {
private static final int SERVER_PORT = 8093;
public static void main(String[] args) {
try {
TMultiplexedProcessor processor = new TMultiplexedProcessor();
/ / helloService registration
processor.registerProcessor("helloService".new HelloService.Processor<>(new HelloServiceImpl()));
/ / register queryService
processor.registerProcessor("queryService".new QueryService.Processor<>(new QueryServiceImpl()));
TServer server = getSimpleServer(SERVER_PORT, processor);
System.out.println("Starting the simple server...");
server.serve();
} catch(Exception e) { e.printStackTrace(); }}/** Simple single-threaded service model, generally used for testing */
public static TServer getSimpleServer(int port, TProcessor processor)
throws TTransportException {
TServerTransport transport = new TServerSocket(port);
TServer server = new TSimpleServer(new TServer.Args(transport)
.processor(processor));
returnserver; }}Copy the code
Client:
Multiplexed server uses TMultiplexedProcessor, client also needs to use:
package com.attempt.thrift02.client;
import com.attempt.thrift02.gen.service.HelloService;
import com.attempt.thrift02.gen.service.QueryService;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
/** * {add description here} **@author chengyan
* @date 2021-05-06 12:46 下午
*/
public class MultipleClient {
private static final int SERVER_PORT = 8093;
public static void main(String[] args) {
TTransport transport = null;
try {
transport = new TSocket("localhost", SERVER_PORT);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
// helloService
TMultiplexedProtocol helloService = new TMultiplexedProtocol(
protocol, "helloService");
HelloService.Client client = new HelloService.Client(helloService);
System.out.println(client.hello("thrift world"));
// queryService
TMultiplexedProtocol helloProtocol = new TMultiplexedProtocol(
protocol, "queryService");
QueryService.Client queryClient = new QueryService.Client(helloProtocol);
System.out.println(queryClient.query(1));
} catch (TException e) {
e.printStackTrace();
} finally{ transport.close(); }}}Copy the code
Start the server:
Start the client:
So much for the use of Thrift, next we’ll look at the source code implementation.
Reference:
- Apache Thrift – Overview and Introduction: juejin.cn/post/684490…
Limited to the author’s personal level, there are inevitable mistakes in the article, welcome to correct! Original is not easy, commercial reprint please contact the author to obtain authorization, non-commercial reprint please indicate the source.
This article was first published in the wechat public number Java technology exploration, if you like this article, welcome to pay attention to the public number, let us explore together in the world of technology!