Fininja
Fininja личный блог
08 февраля 2024, 14:51

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

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 есть потоковая передача, которая по обещаниям должна работать лучше и быстрее вебсокетов. Но для начального знакомства это уже слишком (:

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


16 Комментариев
  • dt0wer
    08 февраля 2024, 16:21
    Делал работу с ними на swift'е. Подписка/отписка на события (котировки, статусы) через асинхронный bidir streaming у тинька очень неудобно сделана, на мой взгляд. Если отправить запрос на подписку на список А, потом отписку от Б, потом подписку на В, в ответах непонятно на какой из трёх запросов этот ответ пришёл. Неужели так сложно было какой-нибудь id прицеплять и к запросу, и к ответу? И тем более непонятно, нахрена вообще такого рода запросы сделали через стриминг.
      • dt0wer
        08 февраля 2024, 15:50
        Fininja, напишите, если найдёте способ сделать красивее, чем я. У меня в итоге вышло что-то вида «отправить запрос -> блокировать -> дожидаться ответа -> разблокировать». И технически криво и неудобно.
  • xezdx
    08 февраля 2024, 16:14
    Вам не надо «думать» как распаковывать или конвертировать данные в вебсокетах, это делают готовые библиотеки.

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

    П.С. И да, типизированным языкам неудобно работать с JSON. Какой-нибудь PHP съест любой json и не сломается.
    • dt0wer
      08 февраля 2024, 16:40
      xezdx, на protobuf'е не JSON-ы катаются. «Точно также» не будет.
      • xezdx
        08 февраля 2024, 16:52
        dt0wer, не знаю что вы понимаете под «точно так же». Я имел ввиду «приложение перестанет правильно работать». Суть в том, что при правильной разработке ничего случайно не меняется и нормальные разработчики не делают изменений, накладывающих дополнительные обязательства на другую сторону (типа изменения формата данных). Если такое произошло, то точно так же они сломают и любое другое приложение какие бы данные там не гонялись, хоть xml, хоть байты. Если на стороне сервера изменился протокол, а у вас нет, то ошибка так или иначе возникнет.
        • dt0wer
          08 февраля 2024, 17:12
          xezdx, если формат поменялся, изменившиеся данные вы нормально не получите, но и не «крашнитесь» (e.g. в эксепшон при десереализации не упадёте).
          • Aleksandr Chernikov
            08 февраля 2024, 17:34
            dt0wer, упадёт что то в эксепшн или нет — это вопрос конкретной реализации, а не протокола. И большой вопрос что хуже — кинуть ошибку или выплюнуть заведомо неправильные данные
  • Sprite
    08 февраля 2024, 16:29
    СмартХабр-лаб 2.0
  • Aleksandr Chernikov
    08 февраля 2024, 16:40
    Весьма странное сравнение.
    gRPC работает быстрее за счет более нового и производительного стандарта http/2 (обновления данных станут более риалтаймные)

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

    Чтобы разобрать при помощи библиотеки JSON, нам понадобится вручную создать класс, соответствующий ответу сервера:
    У вас кровь из глаз от такого не течет? Зачем разбирать сначала в строки, а потом героически их парсить? Почему бы не разобрать сразу в нужные типы?
  • Андрей К
    08 февраля 2024, 17:21
    мосбиржа все таки потехнологичней будет. все подобные штуки давно в прошлом
  • Roman Ivanov
    08 февраля 2024, 18:44
    болеемодно flatbuffers, тоже от гугла

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн