Как стать автором
Обновить

Комментарии 25

Мне кажется что есть более простой вариант для "Распространение protobuf модели". Каждый сервис хранит модель у себя. Клиенты ее импортируют (тут конечно зависит от ЯП, ка реализовать импорт). И за использовать тулу чтобы не ломать бек совместимость proto. Монорепа в крупных компаниях делается не для этого и никто не хранит там все протофоайлы в одной директории.

Проблема в том, что из proto файла protoc генерирует исходный код для клиента и сервера. То есть, модель требуется во время компиляции клиента, а во время выполнения proto файл не нужен ни клиенту, ни серверу. Чтобы воспользоваться proto во время выполнения, клиент должен уметь перекомпилировать свой код. На C# в некоторых случаях мы так и делаем. Но это всё же скорее исключение, чем правило. Например, когда сервер, обнаружив изменение метаданных во внешнем источнике, обновляет свой proto файл, публикует его и перекомпилирует изменившиеся классы.

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

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

proto модели лежат в своём репо, который подключается git module'м к нужному проекту

grpc-web не поддерживает подписку на сообщения через websocket и выжидают пока все браузеры будут поддерживать webtransport. Есть какое то готовое решение для подписок через websocket или только придумывать свой протокол\реализацию обмена?

grpc-web нормально поддерживает service-side streams (нужно только с реконнектами разобраться, из коробки не работает и нужно самому накостылить обработчик).

Для задач веб-интерфейса этого обычно достаточно.

Через long polling?

Если fetch, не умирающий по таймауту, можно назвать long polling, то он.

Но long polling, емнип, подразумевает, что коннект через некоторое время рвется, а тут дисконнект только если со связью проблема.

Примерно вот такое. Мы раз в 2 минуты кидаем пустое сообщение на всякий случай. А так оно в принципе и без "пингов" висит и не отваливается. Но на nginx/envoy надо правильно таймауты накрутить.

Для js/ts и grpc-web в частности лучше использовать библиотеку https://github.com/timostamm/protobuf-ts

Она гораздо более удобна для работы и генерит натуральный ts код (а не js с тайпингами)

Про nginx и http2 чушь написана. Нормально он несекурный http2 переваривает.

Можно пример с connection upgrade, чтобы не получить "Received HTTP/0.9 when not allowed"?

location / {
    grpc_pass grpc://127.0.0.1:10011;
    grpc_set_header Host $server_name;
    grpc_set_header X-Real-IP $remote_addr;
    grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    grpc_read_timeout 7d;
    grpc_send_timeout 7d;
}

Например, в Postman все еще нельзя загрузить proto файл и получить предзаполненные поля. 
Сейчас это не так. В postman можно загрузить proto файл
https://learning.postman.com/docs/sending-requests/grpc/using-service-definition/

gRPC передает данные в бинарной форме, выигрыш по объему передаваемых данных 50-80% экономии трафика

Учтено ли здесь, что практически весь plaintext трафик rest/graphql/etc проходит через gzip? Сколько останется процентов, если его учесть?

А кто запрещает использовать компрессию и для HTTP/2 траффика? На gRPC не проверял, а на Kafka при lz4 компрессии protobuf выигрывает у JSON на небольших пакетах более чем в два раза. А вот если вломить пакет из 10 тыс. записей, то выигрыш сразу падает до 20%.

Никто не запрещает, но бинарные данные сжимаются сильно хуже текста, так что выигрыш в 50-80% из статьи это сравнение plaintext и сжатых данных. Выигрыш в объеме передаваемых данных у gRPC и аналогичных протоколов все же есть, но не такой драматический, как пишут в абсолютно всех статьях по gRPC при его сравнении с json

Вы точно прочитали, то что я написал? Или ограничились только первым предложением?

Прочитал, да, в принципе все верно, вопрос тут больше в типе пакета и объеме данных, когда мы говорим про выигрыш в 2+ раза - это скорее небольшой по размеру пакет (или очень разнородный пакет, т.е. данные, которые слабо поддаются сжатию)?

Для проверки с o1-preview написал скриптик, который гоняет разное количество разных по формату пакетов через protobuf и json с lz4 компрессией и получил в качестве результата те же 10-50% выигрыша у protobuf (меньше пакетов - больше выигрыш у бинарного формата, разумеется).

Не спец в python и тем более в реализации protobuf, но изъянов на беглый взгляд не обнаружил, можете посмотреть репозиторий.

В контексте web-разработки (а в статье упоминается она) пакетов обычно не так много, и они большие (десятки килобайт в среднем) и жмутся хорошо. Приводить 50-80% экономии трафика без сжатия на таких данных считаю некорректным

выигрыш в 2+ раза - это скорее небольшой по размеру пакет

А я писал: "на небольших пакетах более чем в два раза". Вы это повторно не увидели?

Не спец в python

Но на proto то можно было посмотреть, раз именно его обсуждаем? Бинарный protobuf экономит место для чисел, но уж никак не для строк. А в репозитории по ссылке его старательно грузят преимущественно строками, на которых по определению заметной разницы между бинарным и текстовым форматом быть не может.

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

В контексте web-разработки

В контексте применимости RPC, пакеты могут любыми. С точки зрения скорости прохождения сообщений (реакции системы), они наоборот должны быть маленькими.

Даже в web-разработке для меня странно гонять десятки килобайт в одном запросе. Это же на один-два порядка хуже время реакции на одно сообщение в сотню байт. Для примера, в Kafka по умолчанию max.in.flight.requests.per.connection = 5. То есть сжимаемый пакет содержит не более пяти сообщений.

К вашему комментарию нет никаких вопросов, на ваших данных все именно так, на числах с плавающей точкой тем более.

В моей сфере (интернет-магазины) типовое сообщение это на 90% текстовая информация и даже небольшой блок на сайте с картинками вполне может весить больше килобайта, а страница каталога с двумя десятками товаров больше 10 килобайт - возможно, у меня здесь профдеформация и для других систем (биржи акций, например) действительно можно слать очень небольшие пакеты из чисел.

Я ни в коем случае не спорю с тем, какого сжатия с protobuf можно добиться на определенных данных, но безаппеляционно заявлять про 50-80% экономии трафика на gRPC по сравнению с REST - это большое лукавство.

безаппеляционно заявлять про 50-80% экономии трафика на gRPC по сравнению с REST - это большое лукавство

Бритва Хэнлона. Это, скорее, ошибка, чем лукавство, так как не указано было, что речь идет исключительно о несжатых данных. В случае компрессии выигрыш 10-60%, в зависимости от количества бинарных данных и размеров пакета. Что, впрочем, тоже не мало.

gRPC по сравнению с REST

Protobuf по сравнению с JSON. Нужно отделять мух от котлет. gRPC не обязан использовать именно protobuf. Все же потоковый gRPC (HTTP/2) дает заметные преимущества перед REST в некоторых сценариях использования. Например, сервис прогнозируемых курсов валют на активном двунаправленном потоковом gRCP в локальной сети вполне может давать ответ на запрос за 1 мс. На REST такого достигнуть мало реально.

У нас контракты каждого сервиса живут в отдельном проекте. При сборке собираются пакеты: npm для front-end, nuget для backend, py для тестов. Плюс генерируется документация на контракт (html). Всё через ptotoc, в рамках ci. И всё это добро пушится в nexus. Front-end общается с бэком по gRPC. Полёт нормальный.

В постмане актуальной версии отлично работает подгрузка контрактов как через протофайлы так и через рефлексию. Аналогично с автозаполнением для запросов.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий