Блог им. fininja

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера

    • 08 февраля 2024, 14:51
    • |
    • Fininja
  • Еще
No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис.1: Ответ gRPC сервера на любой вопрос.

Краткое содержание для непрограммистов: gRPC круто и быстро и знать об этом незачем. Всего хорошего!

При написании коннектора к любой бирже на 99% везде используется два основных вида способа передачи запросов и получения данных — это через отдельные REST-вызовы (например, «биржа, дай мне список инструментов») и через веб-сокеты (например, «биржа, дай мне поток обезличенных сделок по Газпромнефти»).

В этих «обычных» случаях всё общение происходит через JSON-запросы, то есть, говоря по-русски, в текстовом виде.

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 2: пример запроса списка продуктов и ответа рептилоидов с сервера BitGet

Запросы нужно отсылать по заранее известным адресам API.


Но время от времени появляются необычные протоколы и вот у Тинькофф инвестиций попался gRPC.

Лезем в гугл разбираться что это за зверь и выясняем:

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 3: мой стек длиннее твоего.

* gRPC работает быстрее за счет более нового и производительного стандарта http/2 (обновления данных станут более риалтаймные)
* в отличие от REST/WebSockets, у gRPC все данные передаются в бинарном виде, что быстрее и экономнее в плане размера
* gRPC работает с четкой типизацией, что означает, что сериализация/десериализация происходят «автоматически» и не надо гадать как преобразовывать данные в текст и обратно
* gRPC это все еще RPC, удаленный вызов процедур, то есть используется все так, будто ты не к удаленному серверу обращаешься, а делаешь вызов на локальной машине.

Много непонятных букв, но давайте приведу один практический пример.

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 4: меняем пару буковок в строчке, которую отравляем на сервер.

Например, нам нужно получить информацию о доступных бумагах на сервере.

REST-запрос на Битгете будет выглядеть примерно так: GET запрос на адрес api.bitget.com/api/spot/v1/public/products

или в коде:

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 5: Запрос доступных бумаг в OsEngine (коннектор Битгет)

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

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 6
: разбор из строки в объект.

Чтобы разобрать при помощи библиотеки JSON, нам понадобится вручную создать класс, соответствующий ответу сервера:
No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 7: Разработчик сделал класс, где строки ответа разложены по полочкам.

Но при этом приходится в коде приводить все к правильным типам данных.

А теперь посмотрим как все делается в gRPC?

What is gRPC?. Part 1: Authentication and… | by MD Mobin | Stackademic
Рис. 8: перерыв на обед.

В gRPC всё известно заранее благодаря .proto файлам, в которых описаны методы, предоставляемые сервером:


No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 9: методы получения данных по инструментам из instruments.proto Тинькофф инвестиций.

Эти прото-файлы скачиваются с сайта брокера и подключаются в проект.
А дальше происходит небольшая магия.

Из этих прото-файлов компилятор Protobuf генерит файлы с нужными функциями и объявлениями классов. Всё, что нужно, чтобы пользоваться API.
В отличие от REST, тут эти функции/типы не нужно писать самому.

Просто начинаем их использовать:

No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис. 10: получаем список акций.

То есть тип SharesResponse, InstrumentsRequest, метод Shares — все это было сгенерировано автоматически из прото-файлов.

В результате мы получаем ответ с набором объектов, у которых уже объявлены типы данных:
No REST for the Wicked - Первые впечатления от gRPC с точки зрения алготрейдера
Рис
. 11: Заполняем новый объект бумаги в коннекторе OsEngine/Tinkoff

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

А еще в gRPC есть потоковая передача, которая по обещаниям должна работать лучше и быстрее вебсокетов. Но для начального знакомства это уже слишком (:

До встречи в следующем эпизоде!


★6
16 комментариев
Делал работу с ними на swift'е. Подписка/отписка на события (котировки, статусы) через асинхронный bidir streaming у тинька очень неудобно сделана, на мой взгляд. Если отправить запрос на подписку на список А, потом отписку от Б, потом подписку на В, в ответах непонятно на какой из трёх запросов этот ответ пришёл. Неужели так сложно было какой-нибудь id прицеплять и к запросу, и к ответу? И тем более непонятно, нахрена вообще такого рода запросы сделали через стриминг.
avatar
dt0wer, да, я чувствую скоро с этим столкнусь. Меня еще зацепили лимиты — всего 300 подписок на стрим, но с другой стороны «нормальным» алгашам больше и не нужно.
avatar
Fininja, напишите, если найдёте способ сделать красивее, чем я. У меня в итоге вышло что-то вида «отправить запрос -> блокировать -> дожидаться ответа -> разблокировать». И технически криво и неудобно.
avatar
Вам не надо «думать» как распаковывать или конвертировать данные в вебсокетах, это делают готовые библиотеки.

gRPC не спасает от глупых изменений. То есть если у вас в JSON пришедшему по веб-сокету что-то изменилось и ваше приложение крашнулось, то оно точно так же даст сбой при gRPC. Единственное удобство gRPC это то что там единый формат файлов с настройками из которых потом генерится нативный код в нужном языке и вам не надо делать свои конвертации.

П.С. И да, типизированным языкам неудобно работать с JSON. Какой-нибудь PHP съест любой json и не сломается.
avatar
xezdx, согласен. Просто как-то уже привык эти классы для распаковки писать, а тут хопа — и всё само сгенерилось.

В целом понятно, что это лишь удобство, а вовсе не гарантия защиты от ошибок когда.
avatar
xezdx, на protobuf'е не JSON-ы катаются. «Точно также» не будет.
avatar
dt0wer, не знаю что вы понимаете под «точно так же». Я имел ввиду «приложение перестанет правильно работать». Суть в том, что при правильной разработке ничего случайно не меняется и нормальные разработчики не делают изменений, накладывающих дополнительные обязательства на другую сторону (типа изменения формата данных). Если такое произошло, то точно так же они сломают и любое другое приложение какие бы данные там не гонялись, хоть xml, хоть байты. Если на стороне сервера изменился протокол, а у вас нет, то ошибка так или иначе возникнет.
avatar
xezdx, если формат поменялся, изменившиеся данные вы нормально не получите, но и не «крашнитесь» (e.g. в эксепшон при десереализации не упадёте).
avatar
dt0wer, упадёт что то в эксепшн или нет — это вопрос конкретной реализации, а не протокола. И большой вопрос что хуже — кинуть ошибку или выплюнуть заведомо неправильные данные
avatar
СмартХабр-лаб 2.0
avatar
Sprite, алгаши везде о своём (:
avatar
Весьма странное сравнение.
gRPC работает быстрее за счет более нового и производительного стандарта http/2 (обновления данных станут более риалтаймные)

REST вполне себе может работать через http/2
в отличие от REST/WebSockets, у gRPC все данные передаются в бинарном виде, что быстрее и экономнее в плане размера
Вебсокеты поддерживают бинарные данные.
gRPC работает с четкой типизацией, что означает, что сериализация/десериализация происходят «автоматически» и не надо гадать как преобразовывать данные в текст и обратно
При нормальном дизайне rest коннектора — тоже ни о чем гадать не нужно — есть строго типизированный объект, где каждое поле можно однозначно разобрать. Да, писать придется руками (хотя если есть swagger — можно тоже автоматом все сгенерировать)
gRPC это все еще RPC, удаленный вызов процедур, то есть используется все так, будто ты не к удаленному серверу обращаешься, а делаешь вызов на локальной машине.
То что удаленный вызов спрятан ничего не меняет, ровно так же можно все спрятать и для реста
Рис. 6: разбор из строки в объект.

Чтобы разобрать при помощи библиотеки JSON, нам понадобится вручную создать класс, соответствующий ответу сервера:
У вас кровь из глаз от такого не течет? Зачем разбирать сначала в строки, а потом героически их парсить? Почему бы не разобрать сразу в нужные типы?
avatar
Aleksandr Chernikov, да, я скорее про типичную ситуацию с торговыми апи разных бирж. В целом конечно практически те же яйца, только в профиль.
 
avatar
мосбиржа все таки потехнологичней будет. все подобные штуки давно в прошлом
avatar
болеемодно flatbuffers, тоже от гугла
avatar
Roman Ivanov, ну если какой-нибудь модный брокер даст апишку на таких, то будем разбираться
avatar

теги блога Fininja

....все тэги



UPDONW
Новый дизайн