- Apache Thrift
-
Apache Thrift Тип RPC framework
Разработчик Написана на Операционная система Последняя версия 0.8.0 (29.11.2011)
Лицензия Сайт 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
серверах. Основа уровня Ввода/Вывода по-разному реализована для различных языков.Поддерживаемые протоколы
- TBinaryProtocol — Несложный двоичный формат, простой, но не оптимизированный для экономии пространства.
- TCompactProtocol — Более компактный двоичный формат, как правило более эффективен.
- TDebugProtocol — Человечески понятный формат текста, помогающий в отладке.
- TDenseProtocol — Как и в TCompactProtocol, получение мета информации из того, что было передано.
- TJSONProtocol — Использование JSON’a для раскодировки данных.
- TSimpleJSONProtocol — Протокол «только для записи», использующий JSON. Подходит для парсинга на скриптовых языках.
Поддерживаемые транспортивки
- TFileTransport — Этот транспортировщик записывает в файл.
- TFramedTransport — Этот транспортировщик используется, когда применяются non-blocking сервера. Он отправляет данные во фреймах, где каждому фрейму предшествует длина информации.
- TMemoryTransport — Использование памяти для ввода / вывода. Резализация Java использует простой встроенный
ByteArrayOutputStream
. - TSocket — Использует blocking socket ввода / вывода для транспортировки.
- TZlibTransport — Выполняет сжатие с помощью
zlib
. Используется в сочетании с другим транспортом. Отсутствует в реализации Java.
Поддерживаемые сервера
- TNonblockingServer —
multi-threaded
сервер, использующийnon-blocking
ввод / вывод (Java реализация используетNIO channels
). На этих серверах должен использоваться TFramedTransport. - TSimpleServer —
single-threaded
, использующийstd blocking
ввод / вывод. Полезен для тестирования. - TThreadPoolServer —
multi-threaded
сервер, использующийstd blocking
ввод / вывод.
Преимущества
- Кросс-языковая сериализация с более низкими накладными расходами, в отличие от таких альтернатив как SOAP, за счет использования двоичного формата.
- Простая и чистая библиотека. Не нуждается в фреймворке для кода. Не использует XML-конфигурацию.
- Языковые привязки ощущаются естественными. Например, Java использует
ArrayList<String>
. C++ используетstd::vector<std::string>.
- Формат связи уровня приложений и формат связи уровня сериализации строго разделены. Они могут быть изменены независимо друг от друга.
- Встроенные типы сериализации включают в себя: двоичный, дружественный к HTTP и компактный двоичный.
- Складывается, как кросс-языковой сериализованный файл.
- Мягкие версии протокола. Thrift не требует централизованной и явный механизм, как major-version/minor-version. Слабосвязанные группы могут свободно переходить в RPC вызовы.
- Не зависим от архитектуры или от нестандартного ПО. Нет несовместимых лицензий на ПО.
Сравнение с Protocol Buffers
Apache Thrift Protocol Buffers Разработчик Facebook, Apache Google Поддерживаемые языки C++, Java, JavaScript, 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 службы
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 UserManager { 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 — простой
ping-pong
метод. Если мы отправляем сообщение"are you there?"
и получаем ответ"yes, I am here"
, то, конечно же, все идет правильно. - add_user — отправляем объект
user
(это объект, поэтому он должен быть создан в PHP-приложении). В ответ мы получаемuser_id
. Если что-то не так, нам возвращается ошибка. - get_user — то же, что и выше, но здесь мы отправляем
user_id
и получаем объектuser
- clear_list — эта функция объявлена как односторонняя
(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)] []
Вот собственно и всё.Сайты, использующие Thrift
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Ссылки
- thrift.apache.org/ — официальный сайт Apache Thrift
- Thrift: The Missing Guide
- Thrift Ant task
- Thrift tutorial
- Thrift Installation Tutorial Spanish-Español
Apache Software Foundation Проекты верхнего уровня ActiveMQ • Ant • Apache HTTP Server • APR • Beehive • Cassandra • Cayenne • Camel • Commons • Cocoon • CouchDB • DB • Directory • Excalibur • Forrest • Geronimo • Gump • Hadoop • Harmony • HBase • HiveMind • HttpComponents • iBATIS • Jackrabbit • James • JMeter • Lenya • Maven • Mina • mod perl • MyFaces • Nutch • OFBiz • OpenOffice.org • POI • Portals • Santuario • ServiceMix • Shale • Shiro • SpamAssassin • Struts • Subversion • Tapestry • Tcl • Tomcat • Turbine • Velocity • WebWork 2 • Wicket • Xalan • Xerces • XMLBeans Подпроекты Apache Commons BCEL • BSF • JCS Apache Lucene Lucene Java • Lucene4c • Lucy• Solr Apache DB Derby • Torque • DdlUtils • OJB • JDO Apache Web Services Axis • Axis2 • CXF • WS-Commons • EWS • JaxMe • jUDDI • Kandula • Mirae • Muse • Pubscribe • Sandesha • Scout • SOAP • Synapse • TSIK • Tuscany • Woden • WSIF • WSRF • WSS4J • XML-RPC Другие проекты Batik • FOP •Log4j Развивающиеся проекты (Incubator) XAP • River • OpenEJB • OpenJPA • Graffito • Tuscany • Log4Net • Roller • Felix • Abdera • CeltiXfire • FtpServer • Heraldry • Ivy • JuiCE • Kabuki • Lokahi • Lucene.Net • mod_ftp • NMaven • Ode • stdcxx • Woden • WSRP4J • Yoko • WADI • Qpid • stdcxx • TripleSoup • UIMA• Adobe Flex Списанные проекты (Attic) AxKit • Cactus • ECS • Jakarta • ORO • Regexp • Slide • Taglibs Лицензия: Лицензия Apache • Сайт: apache.org Facebook Обзор История · Хронология · Поглощения · Критика · Use in investigations Вебсайт Beacon · Features · Platform Люди Основатели Марк Цукерберг (24% капитала) · Крис Хьюз (1%) · Дастин Московиц (6%) · Эдуардо Саверин (5%) Board Марк Цукерберг · Marc Andreessen · Джим Брейер · Дон Грэм · Peter Thiel Руководство Текущее Марк Цукерберг (Генеральный директор) · Крис Кокс (Вице-президент по продуктам) · Шерил Сэндберг (COO) · Elliot Schrage (Вице-президент по глобальным коммуникациям, маркетингу и публичной политики) · Mike Schroepfer (Вице-президент по разработкам) · Bret Taylor (CTO) · Ted Ullyot (Вице-президент и генеральный советник) Бывшее Шон Паркер (Президент) · Owen Van Natta (COO) · Gideon Yu (Финансовый директор) · Adam D'Angelo (CTO) · Крис Келли (Chief Privacy Officer) · Matt Cohler (Вице-президент по управлению продуктами) Известные
сотрудникиТекущие Андрей Александреску (научный сотрудник) · Рэнди Цукерберг (директор по маркетингу) Бывшие Charlie Cheever (программист) · Andrew McCollum (graphic artist) Программное обеспечение HipHop for PHP · Apache Cassandra · Apache Thrift · Scribe (сервер журналирования) · Apache Hive · FQL Связанные статьи Activity stream · f8 conference · Social graph · The Facebook Effect · The Accidental Billionaires · Социальная сеть (фильм) · Wirehog Категории:- Программное обеспечение по алфавиту
- Application layer protocols
- Data serialization formats
- Inter-process communication
- Remote procedure call
Wikimedia Foundation. 2010.