1. Overview
Through the introduction of the previous article, "Architecture Design: The basic concept of inter-system communication (--RPC)", I believe the reader has understood the basic RPC concept. In order to deepen this understanding, I will explain in detail a typical RPC specification implementation of Apache Thrift in the following articles. Apache Thrift's introduction is divided into three articles, on the basic use of Apache thrift, Medium explain how Apache thrift works (mainly around the Apache thrift use the message format encapsulation, Supported network IO model and its client request processing method); The following article analyzes the shortcomings of Apache thrift and implements a management scheme of RPC service governance based on Apache thrift. This will be helpful for us to understand the Dubbo of service governance in the following way. 2. Basic Knowledge
Thrift was originally developed by Facebook to be used as an RPC framework between languages within the system. 2007 was contributed by Facebook to the Apache fund, which entered the Apache incubator in May 08, known as Apache Thrift. Compared to other RPC implementations, Apache Thrift is primarily a bit of support for multiple languages (c + +, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C #, Cocoa, Smalltalk, etc.), concurrency Can be high (remember the last article, we mentioned several key points that affect RPC performance.) )。
To support multiple languages, Apache Thrift has its own interface definition language and can generate code for various programming languages through the Apache Thrift Code Generation program. This is a prerequisite for ensuring communication in all languages. To be able to implement a simple Apache thrift instance, first we need to explain the Apache thrift IDL. 2-1. Thrift Code Generation program installation
If you are running an Apache thrift experiment in a Windows environment, you do not need to install any tools to download the Apache Thrift Code generator under Windows directly http://www.apache.org/dyn/ Closer.cgi?path=/thrift/0.9.3/thrift-0.9.3.exe (This article was written using the Apache Thrift version 0.9.3); If you are running under Linux, download http:// Www.apache.org/dyn/closer.cgi?path=/thrift/0.9.3/thrift-0.9.3.tar.gz, and compile, install (the process is very simple, here will not repeat it). Remember to add the run location to the environment variable after installation. 2-2. Overview of IDL format
The following is a simple IDL file definition:
# namespace definition note ' Java ' keyword
namespace java testthrift.iface
# struct defines
struct Request {
1:required string Paramjson;
2:required string serviceName;
}
# another struct defines
struct reponse {
1:required rescode responecode;
2:required string Responsejson;
}
# exception Description Definition
exception serviceexception {
1:required exccode exceptioncode;
2:required string exceptionmess;
}
# enum Definition
enum Rescode {
_200=200;
_500=500;
_400=400;
}
# another enum
enum Exccode {
paramnotfound = 2001;
Servicenotfound = 2002;
}
# Services Definition Service
helloworldservice {
reponse send (1:request Request) throws (1:serviceexception e);
}
The above IDL files are code that can be used directly to generate various languages. The following is a common code generation command for various languages:
# build Java
thrift-0.9.3-gen java./demohello.thrift
# Generate C + +
Thrift-0.9.3-gen cpp./demohello.thrift
# Build php
thrift-0.9.3-gen php./demohello.thrift
# Generate node
. js Thrift-0.9.3-gen js:node./demohello.thrift
# Generate C #
Thrift-0.9.3-gen CSharp./demohello.thrift
# You can view the format of the build command by using the following command
Thrift-0.9.3-help
2-2-1, Basic type
The basic type is: In any language, the data form is supported. The following basic types are supported in Apache Thrift: bool: Boolean value (True or false), one byte byte: signed byte i16:16 bit signed integer i32:32 bit signed integer i64:64 bit signed integer double : 64-bit floating-point string: string/character array binary: binary data (shown as Java.nio.ByteBuffer in Java) 2-2-2, struct structure
In object-oriented language, the expression is "class definition", and in weakly typed language, dynamic language, it is represented as "structure/structure body". The definition format is as follows:
struct < struct name > {
< ordinal >:[Field property] < field type > < field name > [= < default;] [; |,]
}
Instance:
struct Request {
1:required binary Paramjson;
2:required string serviceName
3:optional i32 field1 = 0;
4:optional i64 field2,
5:list<map<string, string>> fields3
}
struct Name: can be given a different name (case sensitive) according to your business needs. Note, however, that struct names in a set of IDL definition files cannot be duplicated and cannot use keywords that IDL already occupies (such as required, struct, and so on).
Serial number: The serial number is very important. Positive integers, which are used in order. This property is used when the Apache thrift is serialized.
Field properties: Includes two keywords: required and optional, if you do not specify, the system defaults to required. Required indicates that the field must have a value and that the field will be serialized when Apache Thrift is serialized, optional indicates that the field does not necessarily have a value, and Apache thrift is serialized. This field is serialized only if it has a value.
Field type: In a struct, the field type can be either an underlying type, a struct that was previously defined, or a container (set, map, list) that is supported by an Apache thrift, or a well-defined enumeration. The type of the field must be specified.
Field name: Field names are case-sensitive, cannot be duplicated, and cannot use keywords that IDL already occupies (such as required, struct, and so on).
Default value: You can specify a default value for a field (or you can not specify it).
Terminator: In a struct, two terminators are supported, you can use ";" or ",". Of course you can also not use the Terminator (Apache Thrift Code Generator, will identify itself) 2-2-3, Containers collection/Container
Apache Thrift supports three types of containers, which are ubiquitous in a variety of programming languages:
list<: There is a sequence table (shown in Java as ArrayList), T can be an underlying type or a struct that was previously defined, or it could be a container (set, map, list) that is supported by an Apache thrift. It can also be a well-defined enumeration. There are elements in the sequence table that allow repetition.
set<: A set of unordered elements (shown in Java as HashSet), t can be an underlying type or a struct that was previously defined, or it could be a container (set, map, list) that is supported by an Apache thrift. It can also be a well-defined enumeration. Elements in the unordered elements collection are not allowed to be duplicated, and once repeated, an element overwrites the previous element.
Map 2-2-4, ENMU enumeration
Enum < enum name > {
< enum field name > = < enumeration value >[;|,]
}
Examples are as follows:
Enum Rescode {
_200=200;
_500=500;
_400=400;
}
2-2-5, constant definition
Apache Thrift allows you to define constants. The keyword for a constant is "const", and the type of the constant can be either the underlying type of Apache thrift, a struct that was previously defined, or a container (set, map, list) supported by an Apache thrift, or a well-defined enumeration. Examples are as follows:
Const I32 my_int_const = 111111;
Const I64 my_long_const = 11111122222222333333334444444;
Const Rescode My_rescode = rescode._200;
2-2-6, exception anomalies
Apache Thrift's exception, which is primarily used when defining a service interface. It is defined in a manner similar to a struct (which you can understand to replace the struct keyword with the exception keyword), as in the following example:
Exception serviceexception {
1:required exccode exceptioncode;
2:required string exceptionmess;
}
2-2-7, Service interface
One of the most important IDL definitions in Apache Thrift. In the subsequent code generation phase, these services defined through IDL will constitute the basic remote process of the Apache Thrift client invoking the Apache thrift Server. The service interface definition is as follows:
Service < services name > {
<void | return reference type > < service method name > ([< parameter number >:[required | optional] < argument type > < parameter name & Gt ...]) [Throws ([< exception ordinal >:[required | optional] < exception type > < exception parameter name; ...])
}
Service Name: The service name can be set in accordance with your business needs, note that the service name is case-sensitive. There are only two restrictions on the service name in IDL, that is, you cannot reuse the same name, and you cannot use the keywords that IDL already occupies (such as required, struct, and so on).
Return value type: If the calling method has no return type, then the keyword "void" can be used; This can be the underlying type of Apache thrift, a struct that was previously defined, a container (set, map, list) supported by Apache Thrift, or a well-defined enumeration.
Service method Name: The service method name can be customized according to your business needs, with attention to case sensitivity. In the same service, you cannot reuse a service method name for multiple methods (be awareof this), and you cannot use the keywords that IDL already occupies.
Service method Parameters:< parameter >:[required | optional] < parameter type > < parameter name >. Note Similar to field definitions in a struct, you can specify required or optional, or the system defaults to required if not specified. If there is more than one parameter name in a service method, these parameter names cannot be duplicated.
Service method Exception: throws ([< exception ordinal >:[required | optional] < exception type > < exception parameter name >. The throws keyword is the starting point for the service method exception definition. After the throws keyword, you can define 1 or more different exception types.
An example of the Apache Thrift Service definition is as follows:
Service HelloWorldService {
reponse send (1:request Request) throws (1:serviceexception e);
}
2-2-8, namespace namespaces
Apache Thrift supports the development of different namespaces for different languages:
namespace Java testthrift.iface
namespace php testthrift.iface
namespace CPP Testthrift.iface
2-2-9, Notes
Apache Thrift supports multiple styles of annotations. This is for developers who want to adapt to different language backgrounds:
/* * Comment Method 1:
**/
//notation 2
# Note Way 3
2-2-10, include keywords
If you have more than one IDL definition file in your entire project (the file name of the IDL definition file can be arbitrarily taken). Then you can use the Include keyword to introduce an additional IDL file in the IDL definition file a:
Include "Other.thrift"
Note that you must use double quotation marks (do not use double quotes in Chinese), and do not use ";" Or a "," Terminator.
The above is the basic syntax of IDL, because of the length of the reason it is impossible to each grammar, every detail, but the above grammar points are enough for you to edit a business-adapted, flexible IDL definition. If you need to know more about the thrift IDL syntax, you can refer to the official documentation: HTTP://THRIFT.APACHE.ORG/DOCS/IDL 2-3, the simplest thrift code Defines the implementation of the business interface Helloworldservice.iface in thrift:
Package Testthrift.impl;
Import Org.apache.commons.logging.Log;
Import Org.apache.commons.logging.LogFactory;
Import org.apache.thrift.TException;
Import TestThrift.iface.HelloWorldService.Iface;
Import TestThrift.iface.RESCODE;
Import TestThrift.iface.Reponse;
Import TestThrift.iface.Request; /** * We define a specific implementation of a Helloworldservice.iface interface. <br> * Note that this parent interface: Helloworldservice.iface, is generated by the Thrift Code generation tool <br> * To run this code, please import maven-log4j support.
Otherwise modify the Logger.info method * @author Yinwenjie */public class Helloworldserviceimpl implements Iface {/** * log * *
private static final Log LOGGER = Logfactory.getlog (Helloworldserviceimpl.class); /** * In the interface definition, there is only one method that needs to be implemented. <br> * Helloworldserviceimpl.send (Request request) throws Texception <br> * You can understand that the method of this interface accepts a req of the client
Uest object, and returns a Reponse object to the client after processing is complete <br> * The Request object and the Reponse object are all structures defined by IDL and generate the appropriate Java code through the Code generation tool. */@Override public reponse Send (Request request) throws Texception{/* * Here is the specific business process.
* */String JSON = Request.getparamjson ();
String serviceName = Request.getservicename ();
HelloWorldServiceImpl.LOGGER.info ("Get JSON:" + JSON + "; Get the ServiceName:" + serviceName);
Constructs the return information reponse response = new reponse ();
Response.setresponecode (rescode._200);
Response.setresponsejson ("{\" user\ ": \" Yinwenjie\ "}");
return response; }
}
You can see that there is no difference between the specific business and the process and the normal business code in the previous code. even the implementation of this code is unaware that it will be called by the client in the Apache Thrift Framework . Then we started writing the server-side code for Apache Thrift:
Package Testthrift.man;
Import java.util.concurrent.Executors;
Import Org.apache.commons.logging.Log;
Import Org.apache.commons.logging.LogFactory;
Import Org.apache.log4j.BasicConfigurator;
Import Org.apache.thrift.TProcessor;
Import Org.apache.thrift.protocol.TBinaryProtocol;
Import Org.apache.thrift.server.TThreadPoolServer;
Import Org.apache.thrift.server.TThreadPoolServer.Args;
Import Org.apache.thrift.transport.TServerSocket;
Import TestThrift.iface.HelloWorldService;
Import TestThrift.iface.HelloWorldService.Iface;
Import TestThrift.impl.HelloWorldServiceImpl;
public class Helloboserverdemo {static {basicconfigurator.configure ();
}/** * * log */private static final log LOGGER =logfactory.getlog (helloboserverdemo.class);
public static final int server_port = 9111;
public void StartServer () {try {HelloBoServerDemo.LOGGER.info ("see this sentence to indicate Thrift server readiness ...");
Service execution controller (as long as the specific implementation of the dispatch service is running) Tprocessor tprocessor = new helloworldservice.processor<iface> (new Helloworldserviceimpl ()); Thrift service based on the blocking synchronous IO model, the formal production environment is not recommended with this tserversocket Servertransport = new Tserversocket (helloboserverdemo.serve
R_port);
Set the corresponding IO network model for this server, set the message format used to encapsulate, set the thread pool parameter args Targs = new args (servertransport);
Targs.processor (Tprocessor);
Targs.protocolfactory (New Tbinaryprotocol.factory ());
Targs.executorservice (Executors.newfixedthreadpool (100));
Start this thrift service Tthreadpoolserver server = new Tthreadpoolserver (Targs);
Server.serve ();
} catch (Exception e) {HelloBoServerDemo.LOGGER.error (e); }}/** * @param args */public static void main (string[] args) {Helloboserverdemo server
= new Helloboserverdemo ();
Server.startserver (); }
}
The above code has several points to explain:
Tbinaryprotocol: This class of code Apache thrift a unique binary description format. It is characterized by less transmission of unit data. Apache Thrift also supports a variety of data formats, such as our familiar JSON format. Later in this article we will detail the data formats in Apache thrift.
Targs.executorservice (): Do you think this executorservice is familiar, yes this is Java JDK 1.5+ After the Java.util.concurrent package provides an asynchronous Task Scheduler service interface, the Java standard thread pool threadpoolexecutor is one of its implementations.
Server.serve (), because it is the synchronous blocking network IO model used, the main thread of the application will remain blocked after the execution of this statement. However, there is no error in the underlying network state and this thread will remain here.
In addition, with the code in the Helloworldserviceimpl class, use log4j. If you do not have log4j in your test project, use System.out instead. Next we'll write the simplest Apache Thrift client code:
Package testthrift.client;
Import Org.apache.commons.logging.Log;
Import Org.apache.commons.logging.LogFactory;
Import Org.apache.log4j.BasicConfigurator;
Import Org.apache.thrift.protocol.TBinaryProtocol;
Import Org.apache.thrift.protocol.TProtocol;
Import Org.apache.thrift.transport.TSocket;
Import TestThrift.iface.HelloWorldService;
Import TestThrift.iface.Reponse;
Import TestThrift.iface.Request;
/** * is also a thrift client based on the synchronous blocking model.
* @author Yinwenjie */public class Helloclient {static {basicconfigurator.configure ();
}/** * * log */private static final Log LOGGER = Logfactory.getlog (Helloclient.class); public static final void main (string[] args) throws Exception {//server IP and port tsocket transport = new TSo
Cket ("127.0.0.1", 9111);
Tprotocol protocol = new Tbinaryprotocol (transport);
Prepare to invoke the parameter request request = new request ("{\" param\ ": \" field1\ "}", "\\mySerivce\\queryService"); HelloworldsErvice.
Client client = new Helloworldservice.client (protocol);
Prepare to transmit transport.open ();
Formal call interface Reponse reponse = client.send (request);
Be sure to remember to close transport.close ();
HelloClient.LOGGER.info ("response =" + reponse); }
}
The network IO model used by the thrift client must be consistent with the network IO model used by the thrift server side. That is, if the server side uses a blocking synchronous IO model, then the client must use the blocking synchronous IO model.
The message encapsulation format used by the thrift client must be formatted with the message encapsulation format used by the thrift server side. In other words, if the server side uses the binary stream message format Tbinaryprotocol, then the client must also use the binary Liu message format tbinaryprotocol.
Other code is either defined by IDL and generated by the Thrift Code generation tool, or it is not an important code, so there is no need to post it in order to save space. The following is the effect of the operation.
Server-side Run effect
After a client request is received from the server side, the thread in the thread pool is removed to run
Notice how the server side runs after receiving a client request: Take out a thread in the thread pool and run the specific implementation of the service interface. Next we'll introduce the details of the Apache thrift work.
(next)