03-05-2023
Тип |
RPC framework |
---|---|
Разработчик | |
Написана на | |
Операционная система | |
Последняя версия |
0.8.0 (29.11.2011) |
Лицензия | |
Сайт |
thrift.apache.org/ |
Thrift (англ. Бережливость, произносится как Трифт) — язык описания интерфейсов, который используется для определения и создания служб под разные языки программирования. Является фреймворком к удаленному вызову процедур (RPC). Разработан компанией Facebook в качестве масштабируемого кросс-языкового сервиса по разработке. Сочетает в себе программный конвейер с движком генерации кода для разработки служб, в той или иной степени эффективно и легко работающих между такими языками как C#, C++, Cappuccino, Cocoa, Delphi, Erlang, Go, Haskell, Java, OCaml, Perl, PHP, Python, Ruby и Smalltalk. Проще говоря, Thrift является двоичным протоколом связи. С апреля 2007 разрабатывается как open source проект компанией Apache Software Foundation.
Содержание |
Thrift включает в себя готовый программный конвейер, состоящей из шести уровней, для работы с клиентской и серверной частью. Верхний уровень составляет сгенерированный код описания Thrift. Службы генерируют из него клиентский и серверный код. В отличие от встроенных типов, созданная структура данных возвращается как результат в сгенерированном коде. Уровни протокола и транспортировки являются частью runtime-библиотеки. В Thrift возможно выбрать службы и изменить протокол и транспортировку без перекомпиляции кода. Помимо клиентской части Thrift включает в себя серверную инфраструктуру для связи протокола и транспортировки в blocking
, non-blocking
и multi-threaded
серверах. Основа уровня Ввода/Вывода по-разному реализована для различных языков.
ByteArrayOutputStream
.
zlib
. Используется в сочетании с другим транспортом. Отсутствует в реализации Java.
multi-threaded
сервер, использующий non-blocking
ввод / вывод (Java реализация использует NIO channels
). На этих серверах должен использоваться TFramedTransport.
single-threaded
, использующий std blocking
ввод / вывод. Полезен для тестирования.
multi-threaded
сервер, использующий std blocking
ввод / вывод.
ArrayList<String>
. C++ использует std::vector<std::string>.
Apache Thrift | Protocol Buffers | |
---|---|---|
Разработчик | Facebook, Apache | |
Поддерживаемые языки | C++, Java, Python, PHP, XSD, Ruby, C#, Perl, Objective C, Erlang, Smalltalk, OCaml, and Haskell | C++, Java, Python (Perl, Ruby, and C# under discussion) |
Исходящие форматы | Binary, JSON | Binary |
Простые типы | bool byte 16/32/64-bit integers double string byte sequence map<t1,t2> list<t> set<t> |
bool 32/64-bit integers float double string byte sequence "repeated" properties act like lists |
Константы | Да | Нет |
Составной тип | struct | message |
Исключения | Да | Нет |
Документация | Проблематично | Хорошая |
Лицензия | Apache | BSD-style |
Композитные расширения типов | Нет | Да |
Thrift написан на C++, однако код может быть написан на нескольких языках. Для создания Thrift службы для начала надо написать Thrift файлы, которые описывают его, затем сгенерировать код на выходном языке и указать команды запуска сервер, вызвав после чего их в клиенте. Вот пример файла описания:
enum PhoneType { HOME, WORK, MOBILE, OTHER } struct Phone { 1: i32 id, 2: string number, 3: PhoneType type }
Thrift сгенерирует код из этого файла описания, например, в Java. PhoneType
будет простым перечислением (enum)
внутри POJO для класса Phone.
Напишем простое приложение на Apache Thrift. Мы будем определять объект User
. Этот объект будет создан в PHP и располагаться в списке языка Python. Можно было бы также получить объект из Python и передать его в PHP или очистить список. Хотя этот пример очень примитивный, это даст вам некоторое представление о том, как работает Thrift Apache. Для начала мы должны определить методы и объекты, которые будут взаимодействовать с обоими приложениями. Эти определения мы поместим в файл с именем "hello.thrift"
. У этого файла C-подобный синтаксис, со специфическими модификаторами Thrift’a, как будет показано позже.
Thrift файл может содержать другие файлы. В нашем примере мы не будем вкладывать никакие другие файлы. Однако в официальном руководстве проекта вы можете заметить, что требуется файл "shared.thrift"
. Этот файл объявляет класс, от которого наследуется основной класс Calculator
.
Для начала давайте зададим пространство имен.
namespace php hello
Пространства имен определяются для каждого языка — в данном примере, только объекты в файле PHP будут с префиксом «hello_».
Объект User
содержит поля firstname
и lastname
строкового типа, user_id
типа integer
, active
типа boolean
и sex
нашего собственного типа перечисления (enum)
.
Описание такого объекта является очень простым. Для начала опишем наш собственный тип enum
.
enum SexType { MALE = 1, FEMALE = 2 }
После чего опишем объект User.
struct User { 1: string firstname, 2: string lastname, 3: i32 user_id = 0, 4: SexType sex, 5: bool active = false, 6: optional string description }
Как вы, наверное, уже заметили, мы пронумеровали параметры, поскольку того требует синтаксис Thrift. По умолчанию все параметры являются обязательными, но вы можете сделать их необязательными (с помощью ключевого слова optional
), а также установить их значения по умолчанию.
Нам так же надо объявить исключение. Оно будет вызываться, когда передается неправильной параметр (в нашем примере это может произойти, если, например, user_id
будет отрицательным).
exception InvalidValueException { 1: i32 error_code, 2: string error_msg }
Теперь пришло время объявить службу. Службы — это основная вещь, проводящая сериализацию объектов для их доступа в различных программах. Объявим нашу простую службу с помощью ключевого слова service
service UserExchange { void ping(), i32 add_user(1:User u) throws (1: InvalidValueException e), User get_user(1:i32 uid) throws (1: InvalidValueException e), oneway void clear_list() }
При объявлении метода правила нумерации параметров сохраняются. Как вы можете видеть, объявление метода очень похоже на C.
ping-pong
метод. Если мы отправляем сообщение "are you there?"
и получаем ответ "yes, I am here"
, то, конечно же, все идет правильно.
user
(это объект, поэтому он должен быть создан в PHP-приложении). В ответ мы получаем user_id
. Если что-то не так, нам возвращается ошибка.
user_id
и получаем объект user
(oneway)
— это значит, запрос будет отправлен, но наше PHP-приложение не будет ждать результата (так как там может не быть ни одного). Очевидно, что значения такой функции должны считаться недействительными.
Теперь мы можем сгенерировать PHP и Python файлы, который будут использоваться на клиентской стороне и на сервере, соответственно. Это довольно просто:
thrift -r --gen php hello.thrift thrift -r --gen py hello.thrift
В директориях gen-php
и gen-py
мы получили PHP и Python файлы, соответственно. Теперь давайте создадим сервер. Создаем файл, назовем его, например, python_server.py
. Не забудьте сделать его исполняемым, с помощью команды:
chmod +x ./python_server.py
В этот файл мы запихнем все необходимые библиотеки, определим класс для обработки запросов с такими же именами методов, как и определенный в thrift-файлах. Так как код говорит сам за себя, приведем его ниже.
#!/usr/bin/env python import sys sys.path.append('./gen-py') from hello import UserManager from hello.ttypes import * from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer users = [] class UserManagerHandler: def __init__(self): pass #self.log = {} def ping(self): print 'ping()' def add_user(self, user): if user.firstname == None: raise InvalidValueException(1,'no firstname exception') if user.lastname == None: raise InvalidValueException(2, 'no lastname exception') if user.user_id <= 0: raise InvalidValueException(3, 'wrong user_id') if user.sex != SexType.MALE and user.sex != SexType.FEMALE: raise InvalidValueException(4, 'wrong sex id') print 'Processing user '+user.firstname+' '+user.lastname users.append(user) print users return True def get_user(self, user_id): if user_id < 0: raise InvalidValueException(5, 'wrong id') return users[user_id] def clear_list(self): print 'Clearing list' print users del users [:] print users handler = UserManagerHandler() processor = UserManager.Processor(handler) transport = TSocket.TServerSocket(port=9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) # You could do one of these for a multithreaded server #server = TServer.TThreadedServer(processor, transport, tfactory, pfactory) #server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) print 'Starting the server...' server.serve() print 'done.'
Как вы видите, этот скрипт сохраняет пользователей в список users
. Методы позволяют проводить нам некоторые манипуляции с содержимым списка.
Следующую строку обязательно надо принять во внимание:
sys.path.append('./gen-py')
Это путь к директории gen-py
, относительно того места, откуда будет запущен скрипт (по сути, лучшим решением является указать здесь абсолютный путь).
Вы можете запустить ваш скрипт командой:
./python_server.py
Однако, вы можете столкнуться со следующей ошибкой:
ImportError: No module named Thrift
Чтобы это исправить, вам надо перейти в директорию lib/py
и запустить команду установки thrift модуля в вашу python библиотеку:
sudo python setup.py install
Перед тем, как создать PHP скрипт подготовим структуру файлов. Для начала выберем директорию, которая доступна из вашего Apache или любого другого http-сервера. Затем создадим директорию src
и поместим туда все файлы и директории из директории lib/php/src
в пакете Thrift. Создадим так же директорию src/packages
и поместим туда директорию hello
из директории gen-php
(созданную Thrift’ом). В корневую директорию поместите ваш PHP-файл (то есть «hello.php»). В этот скрипт необходимо вставить Thrift-библиотеки, ваш автоматически сгенерированный файл с классом UserManager
, установить соединения с сервером и выполнить обмен объектами.
<?php $GLOBALS['THRIFT_ROOT'] = 'src'; require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php'; require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/THttpClient.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php'; require_once $GLOBALS['THRIFT_ROOT'].'/packages/hello/UserManager.php'; try { $socket = new TSocket('localhost', 9090); $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = new UserManagerClient($protocol); $transport->open(); $client->ping(); $u = new hello_User(); $u->user_id = 1; $u->firstname = 'John'; $u->lastname = 'Smith'; $u->sex = hello_SexType::MALE; if ($client->add_user($u)) { echo 'user added succesfully</br>'; } var_dump($client->get_user(0)); $client->clear_list(); $u2 = new hello_User(); $client->add_user($u2); } catch (hello_InvalidValueException $e) { echo $e->error_msg.'<br/>'; } ?>
Теперь запустите свой сервер (если, конечно, вы уже его не запустили) и откройте ваш PHP-файл в браузере. Вы должны получить следующий результат:
user added succesfully object(hello_User)[7] public 'firstname' => string 'John' (length=3) public 'lastname' => string 'Smith' (length=8) public 'user_id' => int 1 public 'active' => boolean true public 'sex' => int 1 public 'description' => null no firstname exception
Результат var_dump'а
может отличаться, если у вас не установлен xdebug
Когда вы будете анализировать содержимое сценария PHP, вы заметите, что первый пользователь был добавлен успешно, а на второй попытке с различными данными будет поймано исключение (exception)
.
В консоле это будет выглядеть так:
home-debian:~/www/thrift-test/server# ./python_server.py Starting the server... ping() Processing user John Smith [User(user_id=1, description=None, firstname='John', lastname='Smith', sex=1, active=True)] Clearing list [User(user_id=1, description=None, firstname='John', lastname='Smith', sex=1, active=True)] []
Facebook — социальная сеть и первый разработчик Thrift.
facebook.com
last.fm — веб-анализатор музыки.
last.fm
reCaptcha — самая популярная каптча.
recaptcha.com
RapLeaf
rapleaf.com
Evernote — онлайн-сервис и ряд приложений для различных платформ, предназначенные для сохранения, синхронизации и поиска заметок.
evernote.com
OpenX
openx.com
Mendeley — бесплатный онлайн-сервис для управления библиографической информацией, позволяющая хранить и просматривать исследовательские труды в формате PDF.
mendeley.com
ONEsite
onesite.com
api.2gis.ru
api.2gis.ru
Обзор | История · Хронология · Поглощения · Критика · Use in investigations | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Вебсайт | Beacon · Features · Platform | ||||||||||||||||
Люди |
| ||||||||||||||||
Программное обеспечение | HipHop for PHP · Apache Cassandra · Apache Thrift · Scribe (сервер журналирования) · Apache Hive · FQL | ||||||||||||||||
Связанные статьи | Activity stream · f8 conference · Social graph · The Facebook Effect · The Accidental Billionaires · Социальная сеть (фильм) · Wirehog |
Thrift.