Thrift — это межъязыковая RPC-инфраструктура, изначально разработанная на Facebook, теперь открытая как проект Apache. В этом посте будет описано, как написать сервис и клиент в различных режимах, таких как блокирование, неблокирование и асинхронность.
(Я чувствовал, что последние два режима менее документированы и нуждаются в некотором введении типа учебника, отсюда и мотивация этого поста). Чтобы легко следовать руководству, полезно иметь базовое представление об архитектуре Thrift, состоящей из транспортов, протоколов и процессоров. (Хорошую статью можно найти в [1]). Здесь я буду использовать бережливости версии 0.7 и Java бережливости в связывании.
Комиссионная установка
Инструкции по установке можно найти по адресу http://wiki.apache.org/thrift/ThriftInstallation .
Подводя итог этапам установки Ubuntu.
1. Установите необходимые зависимости.
$ sudo apt-get install libboost-dev libboost-test-dev libboost-опции-программы-dev libevent-dev automake libtool flex bison pkg-config g ++ libssl-dev
2. Перейдите в корневой каталог установки.
3. $ ./configure
4. $ make
5. Станьте супер-пользователем и
$ make install
Теперь давайте приступим к созданию сервиса и его использованию.
Определение сервиса
Здесь определяется сервис с простыми арифметическими операциями. Обратите внимание на использование директивы typedef для объявления альтернативных имен для базовых типов i64 и i32. Добавьте следующее в файл с именем ‘arithmetic.thrift’ .
namespace java tutorial.arithmetic.gen // define namespace for java code
typedef i64 long
typedef i32 int
service ArithmeticService { // defines simple arithmetic service
long add(1:int num1, 2:int num2),
long multiply(1:int num1, 2:int num2),
}
Код будет сгенерирован в пакете tutorial.arithmetic.gen .
Теперь сгенерируйте Java-код, используя следующую командную строку.
$ thrift –gen java arithmetic.thrift
Будет создан исходный файл tutorial.arithmetic.gen.ArithmeticService.java .
Режим блокировки
Давайте создадим сервер режима блокировки и клиент для использования сервиса.
Сначала нам нужно реализовать сервис с использованием сгенерированного каркаса сервиса. Интерфейс для реализации — ArithmeticService.Iface.
public class ArithmeticServiceImpl implements ArithmeticService.Iface {
public long add(int num1, int num2) throws TException {
return num1 + num2;
}
public long multiply(int num1, int num2) throws TException {
return num1 * num2;
}
}
Теперь, когда это сделано, давайте создадим сервер Thrift, который будет запрашивать сервер для этого сервиса. Помните, что это блокирующий сервер, поэтому потоки сервера, выполняющие ввод / вывод, будут ждать.
public class Server {
private void start() {
try {
TServerSocket serverTransport = new TServerSocket(7911);
ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).
processor(processor));
System.out.println("Starting server on port 7911 ...");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server srv = new Server();
srv.start();
}
}
Здесь используется реализация TThreadPoolServer, которая будет использовать пул потоков для обслуживания входящих запросов.
Теперь давайте напишем клиент.
public class ArithmeticClient {
private void invoke() {
TTransport transport;
try {
transport = new TSocket("localhost", 7911);
TProtocol protocol = new TBinaryProtocol(transport);
ArithmeticService.Client client = new ArithmeticService.Client(protocol);
transport.open();
long addResult = client.add(100, 200);
System.out.println("Add result: " + addResult);
long multiplyResult = client.multiply(20, 40);
System.out.println("Multiply result: " + multiplyResult);
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ArithmeticClient c = new ArithmeticClient();
c.invoke();
}
}
TBinaryProtocol используется для кодирования данных, передаваемых между сервером и клиентом. Теперь запустите сервер и вызовите сервис, используя клиент для результатов.
Неблокирующий режим
Теперь давайте создадим неблокирующий сервер, который использует Java неблокирующий ввод / вывод. Мы можем использовать ту же реализацию сервиса, что и раньше (ArithmeticServiceImpl).
public class NonblockingServer {
private void start() {
try {
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);
ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport).
processor(processor));
System.out.println("Starting server on port 7911 ...");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NonblockingServer srv = new NonblockingServer();
srv.start();
}
}
Здесь используется TNonblockingServerSocket, который инкапсулирует ServerSocketChannel.
Код для неблокирующего клиента выглядит следующим образом.
public class NonblockingClient {
private void invoke() {
TTransport transport;
try {
transport = new TFramedTransport(new TSocket("localhost", 7911));
TProtocol protocol = new TBinaryProtocol(transport);
ArithmeticService.Client client = new ArithmeticService.Client(protocol);
transport.open();
long addResult = client.add(100, 200);
System.out.println("Add result: " + addResult);
long multiplyResult = client.multiply(20, 40);
System.out.println("Multiply result: " + multiplyResult);
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NonblockingClient c = new NonblockingClient();
c.invoke();
}
}
Обратите внимание на использование TFramedTransport для переноса обычного транспорта TSocket. Неблокирующий сервер требует, чтобы клиент использовал TFramedTransport, который бы формировал данные, передаваемые по проводам. Запустите сервер и отправьте запрос с помощью клиента. Вы увидите те же результаты, что и раньше, на этот раз в режиме без блокировки.
Асинхронный режим
Мы можем написать асинхронные клиенты для вызова службы Thrift. Необходимо зарегистрировать обратный вызов, который будет вызван при успешном завершении запроса. Сервер в режиме блокировки не работает (вызов метода возвращается с пустым ответом) с асинхронным клиентом (возможно, это потому, что мы используем TNonblockingSocket на стороне клиента. См. Конструкцию ArithmeticService.AsyncClient . Так что это может быть правильным поведением). Сервер без блокировки режима, кажется, работает без проблем. Таким образом, вы можете использовать неблокирующий сервер с клиентом, показанным ниже.
public class AsyncClient {
private void invoke() {
try {
ArithmeticService.AsyncClient client = new ArithmeticService.
AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(),
new TNonblockingSocket("localhost", 7911));
client.add(200, 400, new AddMethodCallback());
client = new ArithmeticService.
AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(),
new TNonblockingSocket("localhost", 7911));
client.multiply(20, 50, new MultiplyMethodCallback());
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
AsyncClient c = new AsyncClient();
c.invoke();
}
class AddMethodCallback
implements AsyncMethodCallback<ArithmeticService.AsyncClient.add_call> {
public void onComplete(ArithmeticService.AsyncClient.add_call add_call) {
try {
long result = add_call.getResult();
System.out.println("Add from server: " + result);
} catch (TException e) {
e.printStackTrace();
}
}
public void onError(Exception e) {
System.out.println("Error : ");
e.printStackTrace();
}
}
class MultiplyMethodCallback
implements AsyncMethodCallback<ArithmeticService.AsyncClient.multiply_call> {
public void onComplete(ArithmeticService.AsyncClient.multiply_call multiply_call) {
try {
long result = multiply_call.getResult();
System.out.println("Multiply from server: " + result);
} catch (TException e) {
e.printStackTrace();
}
}
public void onError(Exception e) {
System.out.println("Error : ");
e.printStackTrace();
}
}
}
Два обратных вызова были определены в соответствии с каждой операцией службы. Обратите внимание на использование двух клиентских экземпляров для двух вызовов. Каждый вызов требует отдельного экземпляра клиента, иначе клиент потерпит неудачу со следующим исключением
« Исключение в потоке« main »java.lang.IllegalStateException: клиент в настоящее время выполняет другой метод: tutorial.arithmetic.gen.ArithmeticService $ AsyncClient $ add_call »
Так что это завершает мой быстрый старт на Thrift с различными режимами работы. Надеюсь, кто-нибудь может найти это полезным. Любые предложения или исправления не стесняйтесь комментировать.
[1] http://thrift.apache.org/static/thrift-20070401.pdf
Источник: http://chamibuddhika.wordpress.com/2011/10/02/apache-thrift-quickstart-tutorial/