Работа с Apache Thrift

Работа с Apache Thrift

1. обзор

В этой статье мы узнаем, как разрабатывать кроссплатформенные клиент-серверные приложения с помощью инфраструктуры RPC под названиемApache Thrift.

Мы покроем:

  • Определение типов данных и сервисных интерфейсов с IDL

  • Установка библиотеки и генерация исходников для разных языков

  • Реализация определенных интерфейсов на определенном языке

  • Внедрение клиент / серверного программного обеспечения

Если вы хотите перейти непосредственно к примерам, перейдите прямо к разделу 5.

2. Apache Thrift

Apache Thrift был первоначально разработан командой разработчиков Facebook и в настоящее время поддерживается Apache.

По сравнению сProtocol Buffers, который управляет процессами сериализации / десериализации кроссплатформенных объектов,Thrift mainly focuses on the communication layer between components of your system.

Thrift использует специальный язык описания интерфейса (IDL) для определения типов данных и сервисных интерфейсов, которые хранятся в виде файлов.thrift и используются позже в качестве входных данных компилятором для генерации исходного кода клиентского и серверного программного обеспечения, которые обмениваются данными с помощью различных программ. языков.

Чтобы использовать Apache Thrift в своем проекте, добавьте эту зависимость Maven:


    org.apache.thrift
    libthrift
    0.10.0

Вы можете найти последнюю версию в папкеMaven repository.

3. Язык описания интерфейса

Как уже было описано,IDL позволяет определять коммуникационные интерфейсы на нейтральном языке. Ниже вы найдете поддерживаемые типы.

3.1. Базовые типы

  • bool - логическое значение (истина или ложь)

  • byte - 8-битное целое число со знаком

  • i16 - 16-битное целое число со знаком

  • i32 - 32-битное целое число со знаком

  • i64 - 64-битное целое число со знаком

  • double - 64-битное число с плавающей запятой

  • string - текстовая строка в кодировке UTF-8

3.2. Особые типы

  • binary - последовательность незакодированных байтов

  • optional - типOptional в Java 8

3.3. Структуры

Thriftstructs эквивалентны классам в языках ООП, но без наследования. struct имеет набор строго типизированных полей, каждое из которых имеет уникальное имя в качестве идентификатора. Поля могут иметь различные аннотации (числовые идентификаторы полей, необязательные значения по умолчанию и т. Д.).

3.4. Контейнеры

Комиссионные контейнеры - это строго типизированные контейнеры:

  • list - упорядоченный список элементов

  • set - неупорядоченный набор уникальных элементов

  • map<type1,type2> - карта строго уникальных ключей к значениям

Контейнерные элементы могут быть любого допустимого типа Thrift.

3.5. Исключения

Исключения функционально эквивалентныstructs, за исключением того, что они наследуются от собственных исключений.

3.6. Сервисы

Сервисы - это коммуникационные интерфейсы, определенные с использованием типов Thrift. Они состоят из набора именованных функций, каждая из которых содержит список параметров и тип возвращаемого значения.

4. Генерация исходного кода

4.1. Языковая поддержка

Вот длинный список поддерживаемых в настоящее время языков:

  • C++

  • C#

  • Go

  • Haskell

  • Java

  • Javascript

  • Node.js

  • Perl

  • PHP

  • питон

  • Ruby

Вы можете проверить полный списокhere.

4.2. Использование исполняемого файла библиотеки

Просто загрузитеlatest version, соберите и установите его, если необходимо, и используйте следующий синтаксис:

cd path/to/thrift
thrift -r --gen [LANGUAGE] [FILENAME]

В приведенных выше командах[LANGUAGE] - один из поддерживаемых языков, а[FILENAME] - файл с определением IDL.

Обратите внимание на флаг-r. Он сообщает Thrift о необходимости рекурсивно сгенерировать код, как только он замечает включение в данный файл.thrift.

4.3. Использование плагина Maven

Добавьте плагин в свой файлpom.xml:


   org.apache.thrift.tools
   maven-thrift-plugin
   0.1.11
   
      path/to/thrift
   
   
      
         thrift-sources
         generate-sources
         
            compile
         
      
   

После этого просто выполните следующую команду:

mvn clean install

Обратите внимание, что этот плагин больше не будет обслуживаться. Посетитеthis page для получения дополнительной информации.

5. Пример клиент-серверного приложения

5.1. Определение файла сбережений

Напишем простой сервис с исключениями и структурами:

namespace cpp com.example.thrift.impl
namespace java com.example.thrift.impl

exception InvalidOperationException {
    1: i32 code,
    2: string description
}

struct CrossPlatformResource {
    1: i32 id,
    2: string name,
    3: optional string salutation
}

service CrossPlatformService {

    CrossPlatformResource get(1:i32 id) throws (1:InvalidOperationException e),

    void save(1:CrossPlatformResource resource) throws (1:InvalidOperationException e),

    list  getList() throws (1:InvalidOperationException e),

    bool ping() throws (1:InvalidOperationException e)
}

Как видите, синтаксис довольно прост и не требует пояснений. Мы определяем набор пространств имен (для каждого языка реализации), тип исключения, структуру и, наконец, интерфейс службы, который будет совместно использоваться различными компонентами.

Затем просто сохраните его как файлservice.thrift.

5.2. Компиляция и генерация кода

Пришло время запустить компилятор, который сгенерирует для нас код:

thrift -r -out generated --gen java /path/to/service.thrift

Как видите, мы добавили специальный флаг-out, чтобы указать выходной каталог для сгенерированных файлов. Если вы не получили ошибок, каталогgenerated будет содержать 3 файла:

  • CrossPlatformResource.java

  • CrossPlatformService.java

  • InvalidOperationException.java

Давайте создадим версию службы на C ++, запустив:

thrift -r -out generated --gen cpp /path/to/service.thrift

Теперь мы получаем 2 разных допустимых реализации (Java и C ++) одного и того же интерфейса службы.

5.3. Добавление реализации службы

Хотя Thrift проделал за нас большую часть работы, нам все еще нужно написать собственные реализацииCrossPlatformService. Для этого нам просто нужно реализовать интерфейсCrossPlatformService.Iface:

public class CrossPlatformServiceImpl implements CrossPlatformService.Iface {

    @Override
    public CrossPlatformResource get(int id)
      throws InvalidOperationException, TException {
        return new CrossPlatformResource();
    }

    @Override
    public void save(CrossPlatformResource resource)
      throws InvalidOperationException, TException {
        saveResource();
    }

    @Override
    public List getList()
      throws InvalidOperationException, TException {
        return Collections.emptyList();
    }

    @Override
    public boolean ping() throws InvalidOperationException, TException {
        return true;
    }
}

5.4. Написание сервера

Как мы уже говорили, мы хотим создать кроссплатформенное клиент-серверное приложение, поэтому нам нужен сервер для него. Отличительной особенностью Apache Thrift является то, что он имеет свою собственную инфраструктуру взаимодействия клиент-сервер, которая делает общение простым делом:

public class CrossPlatformServiceServer {
    public void start() throws TTransportException {
        TServerTransport serverTransport = new TServerSocket(9090);
        server = new TSimpleServer(new TServer.Args(serverTransport)
          .processor(new CrossPlatformService.Processor<>(new CrossPlatformServiceImpl())));

        System.out.print("Starting the server... ");

        server.serve();

        System.out.println("done.");
    }

    public void stop() {
        if (server != null && server.isServing()) {
            System.out.print("Stopping the server... ");

            server.stop();

            System.out.println("done.");
        }
    }
}

Прежде всего, необходимо определить транспортный уровень с реализацией интерфейсаTServerTransport (точнее, абстрактного класса). Поскольку мы говорим о сервере, нам нужно предоставить порт для прослушивания. Затем нам нужно определить экземплярTServer и выбрать одну из доступных реализаций:

  • TSimpleServer - для простого сервера

  • TThreadPoolServer - для многопоточного сервера

  • TNonblockingServer - для неблокирующего многопоточного сервера

И, наконец, предоставьте реализацию процессора для выбранного сервера, которая уже была сгенерирована для нас компанией Thrift, т.е. CrossPlatofformService.Processor класс.

5.5. Написание клиента

А вот и реализация клиента:

TTransport transport = new TSocket("localhost", 9090);
transport.open();

TProtocol protocol = new TBinaryProtocol(transport);
CrossPlatformService.Client client = new CrossPlatformService.Client(protocol);

boolean result = client.ping();

transport.close();

С точки зрения клиента действия очень похожи.

Прежде всего, определите транспорт и укажите его для нашего экземпляра сервера, затем выберите подходящий протокол. Единственное отличие состоит в том, что здесь мы инициализируем экземпляр клиента, который снова был сгенерирован Thrift, т.е. CrossPlatformService.Client класс.

Поскольку он основан на определениях файла.thrift, мы можем напрямую вызывать описанные там методы. В этом конкретном примереclient.ping() сделает удаленный вызов серверу, который ответитtrue.

6. Заключение

В этой статье мы показали вам основные концепции и шаги по работе с Apache Thrift, а также показали, как создать рабочий пример, использующий библиотеку Thrift.

Как обычно, все примеры всегда можно найти вthe GitHub repository.