为什么需要Thrift?
Imagine the situation, where you have lots of applications written in different languages. In most popular scenario these are internal applications that perform various tasks and were written by separate development teams. How you enable those applications to talk to each other? Sure, you may add some REST APIs. But in many cases – especially when you transfer binary data – this solution doesn’t provide acceptable performance or maintainability.
Thrift的定义:
Apache Thrift is an open source cross language serialization and remote procedure call (RPC) framework. With support for over 20 programming languages, Apache Thrift can play an important role in many distributed application solutions. As a serialization platform Apache Thrift enables efficient cross language storage and retrieval of a wide range of data structures. As an RPC framework, Apache Thrift enables rapid development of complete cross language services with little more than a few lines of code.
IDL的定义:
An interface description language or interface definition language(IDL), is a specification language used to describe a software component's application programming interface(API). IDLs describe an interface in a language-independent way, enabling communication between software components that do not share one language. For example, between those written in C++and those written in Java. IDLs are commonly used in remote procedure call software. In these cases the machines at either end of the link may be using different operating systems and computer languages. IDLs offer a bridge between the two different systems.
Thrift的原理:
First, let's have a look at Apache Thrift from developer's point of view. Main concept of this framework is a service, which resembles classes that you know from object-oriented programming languages. Every service has methods, which are defined in a familiar way, using various data typesimplemented in Apache Thrift. The data types are mapped to their native counterparts in every language, so in case of simple ones, like int, they are mapped to integer in every language, but more complex, like set becomes, for example, array in PHP or HashSet in Java. The services are defined in so called Apache Thrift document, in which you use Interface Description Language (IDL) syntax (if you want to learn details about this syntax head to theofficial documentation).
Then, from this file – using Apache Thrift compiler – you generate server and client stubs. These pieces of code are calling Apache Thrift library and you use them to implement server and clients – it's like filling the blank spaces with the relevant code (i.e. creating objects, calling methods, etc.) to allow cross-communication between your applications. The code that you generate for both client and server is embedded in your application. It is illustrated in the following image:
Figure 1. Source: "Learning Apache Thrift", Krzysztof Rakowski, Packt Publishing, December 2015
Before we get to the example code, which will explain this concept, let's have a quick look at the architecture of Apache Thrift. It is illustrated with the following simple image:
Figure 2. Source: "Learning Apache Thrift", Krzysztof Rakowski, Packt Publishing, December 2015
Transport provides a way to read and write payload from and to the medium you use (most commonly – a network or a socket). Protocol is mostly independent of the transport used and is responsible for encoding and decoding the data, so it can be transmitted. Most popular protocols are: binary, compact (Thrift's own) or JSON. Processor is generated automatically by the Apache Thrift compiler. These three layers are combined in server and client codes. When you want two applications to communicate with each other, you need to use the same set of transport and protocol for encoding and decoding the information.
Thrift例子:
1. Describing services with Apache Thrift IDL
Service interfaces are the basis for communications between clients and servers in Apache Thrift. Apache Thrift services are defined using an Interface Definition Language
(IDL) similar to C in its notation. IDL code is saved in plain text files with a “.thrift” extension.
/************** hello.thrift ******************/
service HelloSvc { #A
string hello_func() #B
}
/************** hello.thrift ******************/
This IDL file declares a single service interface called HelloSvc #A. HelloSvc has onefunction, hello_func(), which accepts no parameters and returns a string #B. To use this
interface in an RPC application we can compile it with the Apache Thrift IDL Compiler.The IDLCompiler will generate stub code for both clients using the interface and
servers implementingthe interface. In this example we will begin by using the compiler to generate Python stubs forthe HelloSvc.
/**************************************/
thrift --gen py hello.thrift
/*************************************/
2. Building a Python Server
/****************************** hello_server.py **************************/
import sys
sys.path.append("gen-py")
from hello import HelloSvc
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
class HelloHandler:
def hello_func(self):
print("[Server] Handling client request")
return "Hello from the python server"
handler = HelloHandler()
proc = HelloSvc.Processor(handler)
trans_ep = TSocket.TServerSocket(port=9095)
trans_fac = TTransport.TBufferedTransportFactory()
proto_fac = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TSimpleServer(proc, trans_ep, trans_fac, proto_fac)
server.serve()
/****************************** hello_server.py **************************/
open service:
/************************************/
python hello_server.py
/************************************/
3.Building a Python Client
/*********************************** hello_client.py *********************/
import sys
sys.path.append("gen-py")
from hello import HelloSvc
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
trans_ep = TSocket.TSocket("localhost", 9095)
trans_buf = TTransport.TBufferedTransport(trans_ep)
proto = TBinaryProtocol.TBinaryProtocol(trans_buf)
client = HelloSvc.Client(proto)
trans_ep.open()
msg = client.hello_func()
print("[Client] received: %s" % msg)
/*********************************** hello_client.py *********************/
open client:
/*********************************/
python hello_client.py
/*********************************/
4. Building a Java Client
As a final example let’s put together a Java client for our service. Our first step is to generate
Java stubs for the service.
/****************************************/
thrift --gen java hello.thrift
/****************************************/
/*************************** HelloClient.java *********************/
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.TException;
public class HelloClient {
public static void main(String[] args) throws TException {
TSocket trans_ep = new TSocket("localhost", 9095);
TBinaryProtocol protocol = new TBinaryProtocol(trans_ep);
HelloSvc.Client client = new HelloSvc.Client(protocol);
trans_ep.open();
String str = client.hello_func();
System.out.println("[Client] received: " + str);
}
}
/*************************** HelloClient.java *********************/
complie and open client:
/******************************************************************/
javac -cp /usr/local/lib/libthrift-1.0.0.jar: /usr/local/lib/slf4j-api-1.7.2.jar: /usr/local/lib/slf4j-nop-1.7.2.jar HelloClient.java gen-java/HelloSvc.java
java -cp /usr/local/lib/libthrift-1.0.0.jar:/usr/local/lib/slf4j-api-1.7.2.jar:/usr/local/lib/slf4j-nop-1.7.2.jar:./gen-java:. HelloClient
/******************************************************************/
参考文献:
1.http://www.thrift.pl/
2.http://thrift-tutorial.readthedocs.io/en/latest/intro.html
3.《THE PROGRAMMER'S GUIDE TO Apache Thrift》第一章