Работаем с Google Protocol Buffer в РНР

PHP*
pb4php_logoВ проекте, который я сейчас разрабатываю, возникла необходимость смены протокола, который используется для обмена данными между частями приложения. Сейчас, на уровне внутренних сервисов, обмен происходит через передачу сериализированных массивов РНР поверх TCP сокетов. Так как по обе стороны находятся приложения на РНР, проблем не возникает, формат пакета данных также стандартный, поэтому особых сложностей нет. Разве что часто меня не удовлетворяет скорость обработки, а также то, что мы сильно завязаны на язык и платформу. Если придется стыковать с другой системой или же переписать что-либо, будут сложности — ведь сериализированный формат поймет лишь родной язык, а писать парсер мне не очень хочется. Первоначальный выбор был более чем оправданным — скорость разработки и отладки были приоритетными, сейчас есть немного времени и желания посмотреть на архитектуру с высока и другим взглядом.

Следует сказать, что данные передаются самые простые — строки (различной длины, на практике длинее килобайта или десятка почти нет, обычно это сотни байт), целые числа (в том числе и unix timestamp), некоторый набор констант, true/false флаги, только в одном случае передаются значения с плавающей точкой. В принципе, все сводится к трем типам данных — строка, целое число, число с плавающей точкой. Если хотеть, можно выделить еще поле кода команды, которое можно отнести к перечисляемому виду (количество команд ограничено и конечно, хоть и растет с ростом системы). В сериализированном виде такой пакет занимает достаточно много места, и хоть передаются данные по сокетах в пределах локальной машины, это все равно не выход — изначально система такая, что должна допускать динамическое расширение на несколько узлов кластера.



Навскидку приходит мысль использовать вместо PHP-массива сразу JSON, этим мы решим вопрос понимания протокола другими языками. Но здесь есть подводный камень в виде, насколько я понимаю, кодирования символов строковых, особенно кириллицы, которая преобразуется в UTF и представлена в виде \u3490, что значительно увеличивает объем передаваемых данных.

Так что я начал (в который раз, эх) исследовать различные форматы для взаимодействия между сервисами приложения, которые бы позволили обмениваться в будущем и между разными платформами, прозрачно передаваться по сети и быть, по возможности, максимально компактными. Очень приглянулся мне протокол Hessian (по тестам, его вторая реализация просто отличная), но слишком он замкнутый и очень мало документации. Поэтому в основном я рассматривал Facebook/Apache Thrift и Google Protocol Buffer.

Thrift теперь открытый и передан Apache Fundation, но его реализация достаточно сложна и запутана, вместе с минимумом документации и примеров (чтобы не сказать отсутствием), он отпал сразу, к тому же заставить работать вариант для РНР мне так и не удалось.

А вот Google Protocol Buffer (далее, для сокращения — PB) оказался очень даже приятным и интересным. Однако сложности начались сразу, так как моя задача была работать с ним в РНР, а не Python или Java, как предлагают нам разработчики. Так как материалов по этой теме нет, решил описать свои шаги, на случай, если кому придется такое же делать. Сразу оговорюсь, что сам протокол я не буду описывать, если вы не знакомы с ним — хорошее введение есть на сайте проекта (например: Developer Guide ).

И так, первое, что радует — для работы с PB нет необходимости устанавливать дополнительное ПО или компилировать расширение для РНР, а значит вы сможете провести эксперименты и на домашней машине и на виртуальном хостинге. Пока единственным средством работы в РНР является проект pb4php, который находится в ранней стадии разработки (судя по номеру версии, 0.25, при этом разработка ведется одним человеком и начала больше года назад, хотя коммиты время от времени появляются, но активности очень небольшая). Его мы и будем использовать, но советую трезво оценить свои потребности — если вам достаточно основных возможностей формата и операций создания/чтения/записи/сериализации, то все хорошо, более продвинутые операции не поддерживаются.

Для примера представим самый простой вариант — у нас есть некоторый сервис, который получает новости, например, извлекает из RSS-лент, и есть сервер, который рассылает новости подписчикам. Мы хотим свести обмен данными между обоими сервисами к обмену данными через Protocol Buffer, при этом один из сервисов, или оба, у нас на РНР. Что и как делать?

Сначала необходимо согласовать формат сообщения, пусть это будет самый простой вариант:

  1. message News {
  2.   required int32 id = 1;
  3.   optional string source = 2;
  4.   optional string dsign = 3;
  5.   optional string news_msg = 4;
  6.   optional int32 n_timestamp = 5;
  7. }
* This source code was highlighted with Source Code Highlighter.


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

Указанный файл сохраняем в виде обычного текстового файла в формате *.proto. Далее, используя компилятор (загрузить можно здесь для различных платформ) мы компилируем сообщение в бинарный формат, по сути, шаблон для последующего использования.

Стандартный компилятор сразу генерирует враппер для сообщения, объекты и служебные методы для поддерживаемых языков — Java, C++, Python. Однако мы же работает с РНР, которого пока нет в списке.

В пакете pb4php есть скрипт (лежит в директории example/protoc.php), который делает то же самое (хоть и коряво, честно) для РНР — загружает указанный proto файл и генерирует структуру РНР-класса для работы с сообщением (да-да, код на РНР). Обратите внимание, этот компилятор работает с текстовым описанием сообщения, тем самым файлом *.proto, что вы создали выше.

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

Класс-обертка наследуется от общего класса PBMessage, добавляя описания конкретных полей вашего сообщения, устанавливает геттеры/сеттеры для полей. Судя по коду, внутри они хранятся как обычный ассоциативный массив, лишь при сериализации кодируясь в двоичный формат PB.

Наш класс очень простой и будет хранится в файле pb_news_interface.php:

  1. class News extends PBMessage
  2. {
  3.  var $wired_type = PBMessage::WIRED_LENGTH_DELIMITED;
  4.  
  5.  public function __construct($reader=null)
  6.  {
  7.   parent::__construct($reader);
  8.  
  9.   $this->fields["1"] = "PBInt";
  10.   $this->values["1"] = 0;
  11.  
  12.   $this->fields["2"] = "PBString";
  13.   $this->values["2"] = '';
  14.  
  15.   $this->fields["3"] = "PBString";
  16.   $this->values["3"] = '';
  17.  
  18.   $this->fields["4"] = "PBString";
  19.   $this->values["4"] = '';
  20.  
  21.   $this->fields["5"] = "PBInt";
  22.   $this->values["5"] = 0;
  23.  }
  24.  
  25.  function id()
  26.  {
  27.   return $this->_get_value('1');
  28.  }
  29.  
  30.  function set_id($value)
  31.  {
  32.   return $this->_set_value('1', $value);
  33.  } 
  34.  
  35.  function source()
  36.  {
  37.   return $this->_get_value('2');
  38.  }
  39.  
  40.  function set_source($value)
  41.  {
  42.   return $this->_set_value('2', $value);
  43.  } 
  44.  
  45.  function dsign()
  46.  {
  47.   return $this->_get_value('3');
  48.  }
  49.  
  50.  function set_dsign($value)
  51.  {
  52.   return $this->_set_value('3', $value);
  53.  }
  54.  
  55.  function news_msg()
  56.  {
  57.   return $this->_get_value('4');
  58.  }
  59.  
  60.  function set_news_msg($value)
  61.  {
  62.   return $this->_set_value('4', $value);
  63.  }
  64.  
  65.  function n_timestamp()
  66.  {
  67.   return $this->_get_value('5');
  68.  }
  69.  
  70.  function set_n_timestamp($value)
  71.  {
  72.   return $this->_set_value('5', $value);
  73.  }
  74.  
  75. }
* This source code was highlighted with Source Code Highlighter.


В конструкторе мы описываем формат данных, используя предопределенные имена для типов данных, pb4php отображает их на классы основных типами данных протокола — PBInt, PBBool (наследуется от PBInt), PBSignedInt, PBEnum (перечисления), PBString и PBBytes. Такая обертка нужна, так как далеко не все типы данных протокола можно напрямую отобразить на встроенные типы данных языка, а другие просто дублируются, например sint32/int32 в C++ отображаются на один и тот же тип int32 (хотя вообще вопрос типов данных непростой и таблица отображения из документации не дает исчерпывающего ответа). pb4php реализует лишь несколько базовых типов, так что вам придется выбирать самые общие типы для описания своего формата.

Кстати, сам код обертки далеко не оптимален, его вполне можно заменить более простым и коротким, используя магические методы __get/__set, видимо код писался еще и для совместимости с устаревшими версиями РНР и ООП-возможности там используются далеко не в полную силу.

Ок, давайте дальше. Для использования протокола в программе необходимо подключить два служебных файла — основной класс для работы с сообщениями ( /message/pb_message.php ) и наш сгенерированный класс-обертку для сообщений (pb_news_interface.php). После этого мы работает далее как с обычным РНР-классом.

  1. // Создаем экземпляр класса:
  2.  
  3. $new_news = new News();
  4.  
  5. // Заполняем поля:
  6.  
  7. $new_news->set_id(1); //установим идентификатор в 1
  8.  
  9. $new_news->set_n_timestamp(time()); //добавим метку времени
  10.  
  11. $new_news->set_news_msg('Тестовая новость'); //тело сообщения
  12.  
  13. // остальные поля не заполняем, они будут иницилизированы дефолтными значениями
* This source code was highlighted with Source Code Highlighter.


Для дальнейшей работы нам необходимо получить сериализированное значение нашего сообщения, например, для дальнейшей передачи через сеть. Для этого есть встроенный метод SerializeToString, который кодирует сообщение в строку (в HEX).

Кстати, автор позаботился даже о встроенном методе передачи объектов по сети — просто вызовите метод Send и передайте ему URL и экземпляр сообщения, далее через cURL будет сделан POST-запрос с параметром message, который содержит сериализированное PB-сообщение. Хотя в реальности я бы не стал использовать встроенный механизм передачи данных, скорее просто для тестирования возможностей.

Еще есть интересная константа MODUS, которая отвечает за формат хранения — в двоичном виде или строковом. Двоичный эффективней для передачи по сети и экономит трафик, строковый удобный для тестирования и чтения разработчиком.

  1. // Отправляем сообщение встроенным методом:
  2.  
  3. $new_news->Send('http://domain.com/pb-service/server.php');
  4.  
  5. //получение сериализированной строки
  6.  
  7. $res = $new_news->SerializeToString(); //странный параметр передается еще, не разобрался к чему он
* This source code was highlighted with Source Code Highlighter.


Проводя исследование, я взял типовый набор данных, которые гоняются в моем приложении, и попробовал сравнить вариант с родной сериализацией РНР и Protocol Buffer в варианте pb4php. Выигрыш на размере данных получился около 30% (127 байт против 186 в обычном виде), хотя это никак не претендует на серьезное исследование, просто было интересно сравнить эффективность на моем реальном наборе данных.

Полученную строку можно записать в файл или передать любым другим способом, для восстановления первоначальной формы объекта достаточно создать экземпляр и вызвать метод ParseFromString.

  1. $tmp = $new_news->SerializeToString(); //сериализируем
  2.  
  3. $test = new News(); // создаем экземпляр сообщения
  4.  
  5. $test->ParseFromString($test); //восстанавливаем сообщение
  6.  
  7. //проверим
  8.  
  9. echo 'ID: ' . $test->get_id(); // вернет: ID: 1
* This source code was highlighted with Source Code Highlighter.


Кстати, о некоторых расширенных возможностях PB, которые поддерживаются в библиотеке — посмотрите в директории /examples/nested_mess/, там есть пример работы как раз с преобразованием RSS в Protocol Buffer с использованием сообщений, которые содержат внутри себя, кроме полей с обычными типами, так же и вложенные классы.

И так, в итоге. Используя возможности pb4php мы можем:

  • По исходной спецификации Protocol Buffer сообщения генерировать PHP-класс обертку (хоть и неоптимальной структуры);
    Работать в РНР-скрипте с классами сообщений как с обычными РНР-классами, заполнять поля данными;
    Сериализировать сообщение в шестнадцатеричную строку для последующей записи в файл или передачи по сети (включая встроенный метод HTTP-POST). Итоговое сообщение обычно занимает на 10 — 30% меньше, чем обычный сериализированный массив или JSON (хотя не уверен, с JSON не тестировал еще, но подозреваю, что это так);
    Восстанавливать сообщение в РНР-класс из его сериализированного вида.
    В сообщения допускается использование базовых типов данных, а также вложенных сообщений.


    Конечно, сериализация отнимает ресурсы и она обычно всегда дольше обычной нативной, хотя на простых сообщениях (где несколько полей) это почти никак не заметно. Основной выиграш происходит из-за сокращения объема данных (особенно критично при передаче по сети и большом потоке сообщений), а также легкой возможности строить сервисы, которые не зависят от языка реализации и особенностей платформы. Единственное, что не радует, это практически замороженное развитие проекта (имеется ввиду pb4php, а не сам Protocol Buffer) и его уникальность — для многих языков есть по несколько реализаций. Интересно было бы иметь также вариант с С-расширением для РНР, это бы значительно ускорило операции сериализации/восстановления, а также хотелось бы поддержки от основных фреймворков, вроде Zend Framework.

    Но даже в таком виде проектом можно пользоваться и если перед вами стоит задача быстро научиться обрабатывать сообщения в формате Google Protocol Buffer на РНР — используйте pb4php!
    _________
    Текст подготовлен в ХабраРедакторе
+19
7 ноября 2009, 17:01
46

комментарии (83)

0
stigger #
это pb4php float/double не поддерживает нихрена.
0
aleks_raiden #
в РНР с этим легко благодаря отсутствии жесткой типизации — передаем как строку, потом приводим в к необходимому типу, благо все делается во враппере.
0
stigger #
ага. а если на другой стороне не PHP а java?
0
Starrow #
На другой стороне можно навесить Адаптер перед записью данных в модель (ну или куда там кто пишет), и использовать parseInt и т.д.
0
stigger #
крутые у вас подходы.
я бы дописал недостающий кусок. и сделал по-человечески.
0
aleks_raiden #
да, дописать простые типы данных там достаточно легко. Но в принципе, надо бы переписать и сам компилятор, можно также немного оптимизировать, переделав под себя все :)
+1
Pavel_Osipov #
Почему-бы не пользоваться XML? А для экономии трафика использовать gz-потоки? На мой взгляд, самое универсальное решение в плане отсутствия проблем с передачей данных между интерфейсами реализованными с использованием различных технологий.
0
Pavel_Osipov #
Gz упаковка в настоящее время отлично оптимизирована и практически не требует ресурсов
0
stigger #
у xml просто фееричный оверхед. плюс идея того что «данные должны быть читаемы не только для парсера, но и для человека» лично мне кажется немного странной. парсеры xml'я не шибко торопятся. вот например:

code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

ps. юзаю protobuf в своих проектах, очень доволен. про pb4php речь конечно не идёт, это недоразумение какое-то.
0
Pavel_Osipov #
Если нужно гонять данные между действительно большим количеством различных технологий, то IMHO XML всё же выигрышней в плане его всесторонней поддержки.
Однако всё конечно зависит от специфики проекта, о protobuf слышу первый раз из этой статьи, за это спасибо
0
stigger #
да, только вот редко когда бывает ДЕЙСТВИТЕЛЬНО нужно поддерживать всё подряд. а у protobuf'а достаточно много реализаций и под официально не поддерживаемые платформы, а если очень припрёт — то и своё написать можно. так что вобщем-то много где его можно юзать без особых проблем.
0
Pavel_Osipov #
Согласен, с виду формат простой, написать для новой платформы интерфейс к ней должно быть не сложно.
Однако мне всё же XML больше нравится. Не в последнюю очередь тем, что нет проблем с тем, чтобы разобраться с форматом передачи данных, новому в проекте человеку. Ну и привык я как-то к XML, привязался что-ли… Это как использовать UTF вместо 1251, вроде и менее эффективно зато проблем потенциально меньше
+1
aleks_raiden #
XML это хорошо для внешнего интерфейса. Если мне надо внутри закрытой системы передавать между двумя сервисами, то выбор или самописный протокол (соглашение о формате) или равнозначное или лучше решение, к тому же промышленное (но там где другие промышленные слишком тяжелые — ICE, SOAP)
0
Pavel_Osipov #
Не так давно реализовывали довольно серьёзный проект, для интранета, большинством голосов решили всё делать на XML. Смысл плодить протоколы, когда ограничений по нагрузке не предвидеться, а удобство поддержки и расширения на лицо
+1
aleks_raiden #
не вижу. На 200 байт данных при обмене внутри системы между сервисами сколько оверхеда? а разбор структуры? А есть удобный парсер сразу в ассоциативный массив или StdObject (да есть вроде, но не то, что на виду).

Вопрос — зачем мне между двумя внутренними сервисами XML? И почему крупные компании, где эти сервисы основа бизнеса, применяют свои оптимизированные протоколы?
0
Pavel_Osipov #
Не спорю, что если в перспективе есть highload, то всё несколько меняется. Ещё раз повторюсь, всё от задачи зависит.
Сам в случае возникновения в будущем потенциально загруженного проекта, рассмотрю возможность использования protobuf
0
aleks_raiden #
да, на мой взгляд, как раз область где высокие нагрузки, требования к минимальному оверхеду на всех стадиях, структурированные данные, автоматическая верификация, внутренний протокол системный — это области применения таких решений.
+1
googol #
Недавно конвертировали приложение c XML на Apache Thrift. Вывод:
1) Код отвчечающий за посылку сообщений в 4 раза меньше и он стал намного читабельнее
2) Thrift *очень* приятно использовать
3) Скорость обработки сообщений возросла, мы правда не меряли ее
0
aleks_raiden #
почему же РНР не должен иметь его поддержки?
0
stigger #
пусть имеет, мне не жалко. я про конкретную реализацию говорю.
–1
egorinsk #
Как человек, могу заявить, что читать XML практически нвозможно!
0
stigger #
бинарные данные читать невозможно в принципе. в отличии от.
0
1amer #
читать можно всё. другой вопрос на сколько удобно
0
stigger #
человеку читать xml в бесконечное количество раз удобнее чем бинарные данные. на этом, считаю, дискуссию можно свернуть.
0
1amer #
я тоже так считаю
0
ruzzz #
А с подсветкой? )
0
egorinsk #
Все ранво, тяжело, много лишних элементов.
0
1amer #
есть ещё JSON
0
HEDO #
Если это проект одного человека, может и сойдет.
Если в какой-то момент времени потребуется подключить 20 индусов — они себе головы сломают, а потом все окончательно запутают.

XML — без вопросов. Программы должны быть как кубики Lego.
0
aleks_raiden #
слава богу, обойдемся без индусов. Формат достаточно самодокументируемый — и враппер и сам прото-файл хорошо описывают внутренности себя же
0
aleks_raiden #
а где в XML поддержка каких-либо типов данных, типизации?
0
Pavel_Osipov #
Чем не вариант?
5.65
0
Pavel_Osipov #
Порезал парсер, было написано:
<float>5.65</float>
0
aleks_raiden #
парсер должен это понимать. напомню — XML это описательный стандарт, у него нет типов данных никаких. у самого по себе.
0
Pavel_Osipov #
Ну так и я о чём, XML, просто средство, типов нет, так ведь и не надо, используй его как тебе нужно. А парсер поймёт, его-то под проект и пишем
–1
aleks_raiden #
предлагаете еще и парсер писать самому? толку тогда от промышленных решений? я предпочитаю писать продукт, а не то, что сотни гораздо более умных людей написали давно :)
+1
alexshelkov #
DTD, Schema.
+1
almazik #
А чем XSD не типизация? В своих проектах от всех девелоперов требую к каждому новому виду XML в обязательном порядке прикладывать XSD.
0
max_m #
это сильно замедлит парсинг сообщений.
XSD/DTD нельзя использовать в системе, которая претендует на highload.
Потому что каждое входящее сообщения перед использованием нужно проверить с помощью XSD/DTD.
0
RiderSx #
Спасибо! Не знал про это решение.
–1
standov #
А можете рассказать когда это нужно? я не могу представить сценарий когда может понадобится СИНХРОННАЯ схема взаимодействия узлов в хайлоаде… на реализации в «больших» проектах не показывайте, в курсе, но они так и не написали нигде (ну или я не нашел) зачем и почему именно так?

Просто мне имхо гараздо понятнее в плане масштабируемости и прозрачности АСИНХРОННЫЕ схемы аля MemcacheQ (или что-то похожее) и клиенты к нему/ней веером, ну а формат хранения вы уже сами определяете — хоть тот-же json, быстро, понятно, типа кросплатформенно.

что дает Google Protocol Buffer лично для вас кроме сексуального удовлетворения?
0
aleks_raiden #
я объяснил — передачу данных, это формат сериализации кроссплатформенный. Что мешает хранить сообщение в очереди?

Если вы не знаете, зачем и когда это нужно — значит вам это просто не надо. Столкнетесь — увидите.

P.S. Асинхронность и вообще событийная модель архитектуры не имеет отношения к формату передачи данных, коим и является Protocol Buffer
0
standov #
вы меня не поняли, я про это «который используется для обмена данными между частями приложения. Сейчас, на уровне внутренних сервисов, обмен происходит через передачу сериализированных массивов РНР поверх TCP сокетов.»

т.е. у вас идет обмен точка-точка, я правильно понимаю? вот я и спрашиваю какая задача может этого требовать… за многие годы не сталкивался поэтому и пытаюсь понять
0
standov #
даже не так, я понимаю задачи но там не стоит вопрос формата — работает и ладно, когда поднимается вопрос формата я так понимаю важна переносимость решения, вот тут мне и становится непонятно о каком взаимодействии точка-точка идет речь для которого может быть важна реализация и переносимость?
0
aleks_raiden #
например, я перепишу сервис на Java. остальные части на РНР останутся. Или добавиться компонент на Python.

Вот лучше расскажите мне, как, имея MemceachedQ (который хорош, конечно, протоколом, но это все, недостатотков и некрасивостей у него полно), и РНР реализовать ту самую подписку. То есть выполнение скриптом действий, если появилось сообщение в его очереди. Кроме постоянного опроса, конечно :)

P.S. Мой сервис (один из) как раз, по сути, и есть тот самый роутер/хранилище сообщений, который доставляет их в очереди для клиентов. Сама архитектура проекта интересна, но это тема другой статьи совсем.
0
max_m #
выполнение скриптом действий, если появилось сообщение в его очереди
gearman.org/?
0
aleks_raiden #
оно да не совсем. Это job-сервис скорее, никак не MQ (хоть в составе там есть). Для данной задачи расточительно да и требует а) стороннего компонента, который еще попробуй собери и настрой, б) компиляции модуля к РНР. Хотя сама разработка интереснейшая.
0
pgrishin #
MemcacheQ знатная кака, как и memcachedb. В хайлоаде без патчей их использовать нельзя.
+1
pgrishin #
Есть еще bson (binary json), который в основе mongodb используется.
0
aleks_raiden #
да, кстати, ка кто упустил, хоть давно знаком с разработкой. Но применяется ли где-то еще и есть ли средства работы с форматом?
0
pgrishin #
в драйверах для монгодб у них функции decode_bson encode_bson публичные, т.е. в принципе вполне можно использовать. Все ок.
0
vladsm #
Так зачем всё это нужно при «В принципе, все сводится к трем типам данных — строка, целое число, число с плавающей точкой. » и «передаются данные по сокетах в пределах локальной машины»?

Технологии ради технологии?
Обычного name1=value1&name2=value2&... не хватило? :)
–1
aleks_raiden #
и писать от проекта к проекту свой формат и парсер?
+1
vladsm #
Да-да, гораздо продуктивнее прикручивать от проекта к проекту сторонние либы вместо стандартных средств языка и иметь при этом проигрыш в скорости.

В каком-то из проектов нет аналогов urlencode/urldecode? Какой-то из проектов не умеет работать с парами ключ=значение?

Технологии ради технологий…
–1
stigger #
а по ссылке моей ходили? protobuf почти всё рвёт. откуда проигрыш в скорости-то?
0
vladsm #
1. По какой вашей ссылке?
2. Вы и aleks_raiden — это один персонаж? Сам шучу, сам смеюсь?
3. «Конечно, сериализация отнимает ресурсы и она обычно всегда дольше обычной нативной, хотя на простых сообщениях (где несколько полей) это почти никак не заметно»

0
stigger #
1) code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking
2) нет
3) сходите по ссылке.
0
aleks_raiden #
там, к сожалению, нет сравнения с serialize из PHP. Кроме того, обратите внимание на раздел Object Creation Time.

Вопрос в скоростях PHP: serialize, json, protocol buffer — остается открытым (уточню — именно в РНР). может стоит потестировать.
0
max_m #
> нет сравнения с serialize из PHP
потому что serialize есть только в пхп. Его нет в других языках. А protobuf нужен для взаимодействия между разными языками.

Поэтому если и сравнивать — то с json.
Наверняка json_encode/decode быстрее чем pb4php.

Но формат protobuf более компактный и строгий. Если вы раскодировали message News — и не произошло ошибки, вы можете быть уверены что сообщение было корректным. А если вы расскодировали json, нужно еще убедиться что вам пришел правильный массив, со всеми полями, которое ожидает приложение.
А php-экстеншен для protobuf — это всего лишь вопрос времени. Рано или поздно появится :)
0
stigger #
>потому что serialize есть только в пхп. Его нет в других языках. А protobuf нужен для взаимодействия между разными языками

да ну? а в джаве и C# сериализация как же?
0
max_m #
словами "потому что serialize есть только в пхп" я имел ввиду что пхп-ная функция serialize(), на выходе дает строку в формате, в котором ее можно прочитать только в ПХП. В остальных языках (Java, C#,...) стандартными средствами ее прочитать нельзя — нужно писать парсеры.
Или вы и с этим не согласны?
0
stigger #
с этим — согласен. стандартная сериализация везде несовместима ни с чем…
0
vladsm #
Вы там где-нибудь php видите?
0
aleks_raiden #
нет. моя статья касалась именно РНР, вопрос вообще быстрее или нет чего-либо PB не затрагивался. Я упоминал только о сериализации РНР, потому и коментарии о скорости относились к этой части.
+1
vladsm #
О чём я и сказал — технология ради технологии…
0
stigger #
ладно, живите замкнувшись на своём php, не буду вам больше мешать.
0
vladsm #
Тематика блога и название статьи ни на какие мысли не наводит?
Потому как это уже клиника на уровне
«…
— Мужики, мне бы тут картошку с дачи привезти…
— Бери Ferrari 599 — она всех на круге порвёт!!!
— Чувак, ему картошку с дачи привезти!
— Ладно, живите замкнувшись на своей картошке, не буду вам больше мешать.
…»
0
stigger #
о нецелесообразности использования pb4php (о котором собственно статья) я написал первым же комментом к посту. дальше, как мне показалось, начали обсуждать protobuf в целом.
0
pgrishin #
а вложенный многомерный массив?
0
vladsm #
А не один фиг из чего его собирать на «другом проекте»?
0
gnomeby #
>> Если придется стыковать с другой системой или же переписать что-либо,
>> будут сложности — ведь сериализированный формат поймет лишь родной язык,
>> а писать парсер мне не очень хочется.
Конечно, куда лучше потратить больше времени и написать более громоздкую конструкцию + статью на хабр.

P.S. Ничего не имею против, но ваш отрывок меня улыбнул.
0
aleks_raiden #
я думаю, что написать парсер из РНР-сериализации на, допустим, Java, у меня заняло бы в пару десятков раз больше времени и гораздо меньше удовольствия и стратегического значения имела бы эта работа.
0
f33l #
хотел кинуть bert-rpc.org/ но php там пока не фигурирует
0
mihailt #
есть ещё AMF — изначально под флеш конечно, но в конце концов, это же просто протокол и очень компактный надо сказать.
0
aleks_raiden #
да, кстати, как раз подумал в его сторону, но там также надо екстеншин для ускорения обработки (хотя в зенде есть и нативные классы)
0
point #
Мне кажется, что использовать протобаф с PHP немного бессмысленно. Поясню.
Во-первых, PHP — динамический язык и при изменении исходных текстов проекта ничего перекомпилировать не надо. Изменяя .proto файл нужно каждый раз генерировать заглушки. Это несколько ломает идеологию. Такой подход оправдан, например, в Java где обязательно есть фаза компиляции.

Во-вторых, из предыдущего свойства также вытекает сложность поддержки протокола, если количество машин исчисляется сотнями, и количество ОС/языков тоже велико. Это всё дело нужно поддерживать и пристально следить.

И в-третьих, насколько я понял, разбор пакетов, приходящих в приложение выполняет та же генерируемая заглушка. А PHP для этого не самый лучший кандидат для работы с бинарными данными. Весь профит, получаемый от экономии на трафике будет уничтожен увеличением нагрузки на сервера. Пока не будет pecl-либы, написанной С, говорить о применении protobuf в PHP рано.
0
LDEV #
По-моему, тут получается тот же самый велосипед.

Для собственный решений использую HTTP-протоколы и php-обработчики за nginx. Обычный curl, post-данные и обычный приём данных. Сериализировать не обязательно — можно в голом виде, однако с единой кодировкой.

Например, из проекта: роботы отправляют результаты в буфер обработчика по server2/buffer.php, который складывает в memcachedb, а оттуда по расписанию данные забираются и обрабатываются. Нагрузки никакой нет — данные обрабатываются не по мере поступления, а по мере необходимости — получается, что при увеличении нагрузки на роботов — увеличивается только очередь, но не обработка.
0
aleks_raiden #
а если надо по мере поступления?
0
LDEV #
Тогда можно сразу вне очереди — заменить скрипт получения на скипт обработки.
0
aleks_raiden #
если это сетевой сервис? Открывать сокет и писать сообщение. Вот что, собственно, и делается.
0
LDEV #
Для голых сокетов нужен ещё свой протокол. Вполне можно обойтись обычным HTTP, тем более он ещё и балансируется железками.

В Яндексе внутренний обмен идёт именно на HTTP с минимальным набором заголовков.
–1
david_mz #
По-моему, использоваать генерацию классов в динамических языках — идиотизм.
0
symbix #
<irony>комментарии наглядно демонстрируют, почему в google на php пишут только страничку заказа пиццы</irony>

не, ну лениво генерить код, реализующий соответствующий .proto pack/unpack, не проблема же ваще, вывсечо. а с точки зрения производительности смотреть надо не со стороны php, а со стороны сишного сервиса на это все — ему то тяжелее, он один:)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.