Comments 33
И благодаря HTTP/2 и протоколу Protobuf решает проблемы, связанные со скоростью передачи данных, их весом, в результате повышая эффективность обмена сообщениями.
А эти проблемы они есть? Допустим для типичного довольно нагруженного сайта с парой тысяч РПС они точно есть?
Да, http 2 дает реальный прирост в скорости загрузки сайта, причем независимо от количества пользователей в секунду. Если говорить не только о потоковой передаче, то можно увидеть разницу даже в контексте одного единственного пользователя: здесь роль играет тот факт, что HTTP/2 позволяет эффективней обрабатывать раздельные запросы большой коллекции ресурсов. Но следует сделать ремарку, что разница в производительности несущественна для простых схем раздельной отдачи ресурсов от методов. Источник
Да вроде все освоили выкладывание статики на CDNки какие-то. От nginx в своей сети, до всемирной CDN в зависимости от. У всех приличных людей с аппликейшен серверов только джейсоны отдаются давно уже.
Судя по вашей картинке разница между джейсон+gzip+keep_alive и grpc на уровне погрешности. Так ради чего усложнять все? Джейсон человекочитаемый и дебажить его заметно проще. Сервер и клиент для джейсона тоже заметно проще.
… то на вебе подобное может дорого стоить. Библиотека протобафа вместе с самим вебовым API могла занимать в бандле до нескольких мегабайт.
Сложности при этом могут быть как в отладке, так и в поддержке необходимого дополнительного кода, который все это обрабатывает. На каждой из платформ.
Так что крайне желательно, чтоб плюсы перехода на gRPC на клиентах перевешивали все сопутствующие минусы.
Не знаю на счёт веба, но gRPC очень хорошо себя показывают в высоконагруженных сетевых играх с разными системами и интерфейсами. Например вот выступление товарища из ЕVE Online на эту тему на GDC)
Как-то делали нагрузочное тестирование на gatling сравнивали http, http2 и grpc. Так вот, судя по результатам, grpc очень хорошо держит нагрузку. Http2 разваливается при большом количестве соединений
А что ваш тест тестирует? По тексту статьи это вообще непонятно.
Я вам могу точно сказать что сериализация/сжатие/отправка сообщений размером в единицы килобайт на 1000 rps ни в одном сценарии ни даст никакой значимой нагрузки. Если у вас это не так, то стоит перепроверить свой тест.
Тестировался сервис, обмен данными с которым осуществлялся по трем rpc http, http2, grpc (3 разных теста) с небольшими возможностями инфраструктуры в кубере нагрузка давалась разная примерно до 5к одновременно работающих пользователей. Grpc нагрузку выдержал, http нет (c keep_alive не игрались)
Что такое одновременно работающие пользователи? Они ведь как-то конвертируются в rps?
Я как и в прошлом сообщении говорю вам абсолютно точно, опираясь на реальные цифры, что 1000rps это совершенно незаметная нагрузка для типичного rest сервиса. Если не брать вашу бизнес логику, а только сериализацию со сжатием. У вас точно есть какая-то проблема в тесте, если он показал что-то другое.
Для веб-интерфейсов есть grpc-web, который, в принципе, поддерживает почти все нужные плюшки grpc (со стримингом только шляпа, поддерживается только серверный и автореконнекта в клиенте нет, нужно колхозить свой велосипед).
Объем библиотеки не так уж и велик, у нас в проекте админки vuetify больше весит.
Кодогенерация на основе proto-файлов устраняет много ручной работы, что однозначно перевешивает немногие минусы.
Но на беке к реализации grpc для некоторых языков есть вопросы (не буду показывать пальцем в Python)
Протокол
Ему вообще чихать на протокол. Он спокойно http/3 может использовать. Вопрос будет ли лучше от протокола. Понимаете ли вы как они устроены и в каких случаях реально дают преимущества?
Формат обмена данными
...а ещё можно использовать msgpack (который без сжатия более эффективный, кстати), yaml, xml или любой другой (хоть свой изобретайте). И внезапно интегрироваться проще, больше нативной поддержки, как уже сказали выше, уменьшает размер бандла.
Избыточность
Вот опять же, странный маркетинговый булшит или как выкинуть непонятную метрику. Размер бадла или приложения говорит, что grpc избыточен. Более того, он более эффективно справляется в межсерверном взаимодействии, чем для клиента (а собственно кто сказал, что для конкретного PWA оно будет лучше?). Вся статья из домыслов состоит и передёргиваний.
Декларативность
Прям единственная правда. Единого стандарта и правда нет, потому что где-то удобнее выдать swagger 2.0, но часто лучше OpenAPI 3.0, но в некоторых случаях достаточно удобно HATEOAS. Притом каждый очень удобно подбирается под задачу, отлично жмётся br или gzip.
Больше половины преимуществ вообще звучат в стиле "это лучше потому что новое и крутое". Как, например, HTTP/2 преподносится как крутизна, но какую конкретно проблему он решает? Если это браузер, то можно сказать никакую, потому что в 1.1 есть keep-alived и браузер поднимает 8 параллельных соединений. На самом деле, довольно много кейсов, в которых это гораздо эффективнее. Но почему тогда не HTTP/3? Он вообще ж на udp и там круто решена проблема шифрования. REST API могут в него, а grpc? Я, кстати, не шучу, мне и правда интересно может ли.
Кстати, в http2 есть push-апи, от которого решили вообще отказаться. Так что это не односторонняя связь. Обычно, когда хотят двустороннюю связь поднимают websocket и его родственников.
У меня всё.
Главное - не пытайтесь использовать gRPC в Win приложениях. Скомпилировать код в dll из коробки - нельзя, авторы неправильно расставили dllexport по коду. Попытка отгрузить dll с gRPC - приводит к утечке памяти. В общем, как с любым другим гугловым кодом - убедитесь, что ваш сценарий использования совпадает с Гуглом, иначе ходить вам по минному полю.
Где можно об этом почитать? Используем у себя gRPC под Windows на C#, не замечал таких проблем
Скорее всего проблем и не будет. Те C# библиотеки что я видел - реализованы независимо, а не поверх гугловского с++ кода, так что скорее всего эти проблемы вас не коснутся.
Тут уже ответили, что C# библиотека отличается от плюсовой, мне надо было уточнить это в комментарии. Мы использовали gRPC для коммуникации между плюсовым и шарповым кодом и со стороны шарпов проблем, действительно, не было. Где это можно почитать - не знаю, у нас все шишки набиты самостоятельно и судя по коду gRPC - наш сценарий был уникальным и никем не е предусмотренным. Если бы мы использовали gRPC как статическую lib, со всеми влинковаными зависимостями, то, наверное, тоже было бы все хорошо. Но мы хотели все разделяемые библиотеки иметь динамическими (сейчас только zlib вспомню, но их было с десяток), и это резко всё усложнило.
grpc может работать через любой хттп, ничто не мешает использовать его в веб клиенте. Вообще учитывая скорость передачи и задержки везде бы использовал его, а не тяжелый рест с жсоном
Слово "тяжелый" вы готовы подтвердить бенчмарками? В таких вопросах принято измерять, а не верить словам.
Жаль не ставятся комменты к минусам, чего минусят не понятно.. Да тяжелый, это же очевидно из протокола, rest с json избыточен, хоть как его сжимай бротли/зипом/дефлейтом. Т.е. по-простому: куча сжатого хоть и повторяющегося текста всегда будет хуже заранее предопределенного бинарного пакета. Измерял уже дотнетовский грпс и не я один. Если можете сервер в с++, то задержки еще меньше будут. Да размер клиента будет побольше, но не 20мбайт никак, 667 кб весит протобаф и грпс для wpf, например. Да где-то не работает хттп 2, но доступен хттп 1.1 и это все равно лучше чем рест получается, quick (хттп 3) в вин11 есть и можно в никсах подключить через бубен (не тестировал, но по судя по изменениям протокола еще быстрее работать будет). Конечно для каждого проекта нужно тестировать отдельно все, но сделать клиент и сервер на шарпе для пары унарных методов проще простого. У всех свои причины перейти на грпс, я это делал для уменьшения трафика и задержек в мобильном и впф клиенте. Если кто тестил грпс в хттп3 киньте результаты сравнения с хттп 2, интересно.
Размер сообщения? Лол. Http серверы давно умеют отдавать со сжатием данные. Что само по себе нивелирует необходимость заморачиваться с форматами, а пользовать тот, который удобнее в конкретной ситуации. И да в случае с протобуф будут заморочки с изменением структур api. В случае с json этих проблем нет - обратно-совместимые изменения делать легко. Если идти дальше то уходить от http на rsocket какой
В протобуферах довольно хорошо продуман вопрос изменения API, добавления и удаления полей, совместимость при некоторых изменениях (скажем optional в repeated). Проблем скорее всего будет не больше чем с json, а может и меньше, поскольку изменения формализованы. По-моему это одно из главных его достоинств (есть еще всякие возможности мультиплексирования - но они появляются в бекэнде, а в общении клиента с одним сервером не помогают).
JSОN-RPC - золотая середина
Мои пять копеек.
1) Remote Procedure Calls как конценпция разработана не в Google. Уже лет 20 существуют XML-RPC и JSON-RPC со своими спецификациями.
2) как видно из графика, обычный HTTP+Keep-Alive почти не уступает по скорости gRPC. Позволить Keep-Alive себе может каждый.
3) Как справедливо заметили выше, gRPC дорого обходится в вебе. Схема с JSON-RPC + websockets/keep-alive наоборот, работает прозрачно и открыто.
4) любой RPC (JSON, XML, Googe) выигрывает у REST просто за счет того, что есть единая точка входа в API. Не нужно иметь 30 урлов с вариациями GET/PUT/ETC. В RPC достаточно один раз все наладить, а потом расширять определения.
5) Синтаксис: что такое калькулятор это понятно: класс с двумя числами. Но как объяснить эту запись:
```
Calculator calculator = 1
```
мы что, присвоили экземпляру калькулятора единицу?
Вместо итога: gRPC, может быть и хорош, но как правило хватает JSON-RPC + gzip + websocket/keep-alive.
Вдогонку 6) JSON-RPC не обязывает использовать именно JSON. Можно различать формат по заголовку и для веба использовать JSON, а для бека MessagePack, что уменьшит трафик на треть и повысит скорость записи/чтения.
1 - это нумерация поля, в grpc в передаваемом сообщении нет названий полей, а только номер поля, емнип
Автор совершенно не раскрыл тему gRPC.
аутентификации, потоковой передачи данных в любую сторону, управление потоками, отмену и time-out запросов
Часть преимуществ, которые действительно значительны, уместил в половину предложения. Вся остальная статья про "преимущества" которые никакой роли не играют.
В отличие от REST, gRPC - решение, которое не зависит от платформы и языка
REST тоже не зависит от платформы и языка
в gRPC наименования полей, ожидаемых запросов и возвращаемых ответов определяется и описывается в одном месте - в файле .proto
На практике разницы практически никакой, посмотреть в документации, какую структуру создать перед кодированием в JSON или посмотреть в proto файл, какую структуру создать перед отправкой по gRPC.
Так же совершенно не раскрыл тему, где он применяется, в каких кейсах.
Раз уж так, дополню из личного опыта.
gRPC отлично себя показывает в бэкенде при взаимодействии микросервисов друг с другом под высокой нагрузкой.
Тот самый protobuf, автор так и не сказал, в чем его преимущество, а оно вот в чем: перед отправкой данные запаковываются в бинарный вид и сжимаются. Эта операция легче, чем кодирование/декодирование JSON. Тут мы получаем во-первых уменьшение утилизации CPU, т.к. отсутствует кодирование/декодирование JSON, во-вторых отказываемся от передачи (пусть и сжатых в gzip) избыточных данных (всякие кавычки, двоеточия, названия параметров и т.д.), что уменьшает объем передаваемых данных, что в свою очередь уменьшает задержку и снова нагрузку на CPU.
Возможность потоковой передачи от сервера к клиенту, от клиента к серверу или в обе стороны одновременно.
Общий таймаут на всю цепочку сервисов. Например, у нас есть сервис А который принимает внешний HTTP запрос и отправляет его дальше в обработку в сервис B. "B" в свою очередь в С и т.д. Получается подобная цепочка: A->B->C->D->E, Сервис E генерирует окончательный результат и он возвращается по цепочке обратно в A. Допустим, сервис A должен вернуть ответ клиенту максимум за 1 секунду. Получается, если, например, сервис C затупил, на нем уже истекла эта секунда, сервис А прекращает ждать ответ по таймауту и возвращает клиенту ошибку, все остальные все-равно продолжают работать, сервис С, а затем D и E не знают ничего о том, что сервис А ответ уже не ждет и их работа бесполезна.
В gRPC можно установить общий таймаут на всю цепочку сервисов. Если сервис А прекращает ожидание ответа, об этом узнает и сервис C и прекращает обработку запроса и не отправляет его дальше по цепочке в D и CУ gRPC клиентов из коробки доступна балансировка запросов по Round Robin. При настройке коннекта передаем несколько хостов или хост DNS, который возвращает несколько ip. В результате, клиент начинает их чередовать, поочередно отправляет запросы на разные сервера. Это позволяет не писать самостоятельно подобную балансировку на каждом клиенте (сервисе) и не ставить балансировщики перед каждым сервисом.
gRPC так же имеет в своем арсенале трассировку запросов, по ней подробно ничего не могу сказать, не использовал, т.к. привык уже работать с Jaeger, но такая возможность есть.
Зашёл написать такой же комментарий, а он тут уже есть! Поэтому просто добавлю чуть-чуть в копилочку плюсов:
gRPC это не только протокол, но и целый фреймворк с возможностью расширения во все стороны: перехват (и опционально модификация) запросов, перехват (и модификация) ответов, возможность написания своих сериализаторов и десериализаторов (чем-то не нравится бинарный protobuf? можно в json. Хотите какую-нибудь экзотическую компрессию? Пожалуйста), хотите сервис-дискавери эндпоинтов через какой-нибудь zookeeper (если его ещё кто-то использует), чтобы в рантайме устанавливались новые соединения, плавно вводились в использование, а когда они пропадают из дискавери, плавно снимать с них нагрузку и закрывать.
gRPC поддерживает побочные каналы, которые позволяют вместе с запросами отправлять любые метаданные. Скажем, трассировку, аутентификационные данные пользователя или любую другую служебную информацию. Менять при этом описание структур запроса и ответа не надо - API сервисов остаётся чистым.
На практике разницы практически никакой, посмотреть в документации,
какую структуру создать перед кодированием в JSON или посмотреть в proto
файл, какую структуру создать перед отправкой по gRPC.
Нюанс в том, что если в proto просто переименовать поле, не меняя его тип и индекс, то клиенту будет всё равно на это. В REST же потребуется поменять имя поля и в клиенте тоже
В случае использования FieldMask-ов это уже не будет обратно совместимым изменением, т.к. клиент в маске передаёт серверу именно названия полей, а не номера.
Недавно познакомился с gRPC, заметил, что имена пакета на сервере и клиенте должны быть идентичны, иначе запрос не проходит. Это часть контракта, или возможно этого избежать?
Почитал комменты и осталось какое-то неоднозначное впечатление от gRPC.
И появился вопрос:
Я так понимаю, что подход Contract First считается хорошей практикой при разработке сервисов.
Можно ли считать преимуществом gRPC то, что он делает для разработчика использование Contract First? Если используешь gRPC, то поступать иначе как-то неудобно и невыгодно
gRPC — альтернатива REST API от Google