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/