Pull to refresh

Comments 30

Выглядит полезно, обязательно попробую при случае.

Как по мне, gRPC не выглядит таким уж и сложным даже для новичков. Конечно придется немного изучить документацию и выполнить раз-другой рутинные действия по генерации pb файлов.. что в свою очередь решается одной банальной make командой

Да, в статье я как раз описал, что по моему мнению сам протокол абсолютно не сложный, в данном случае мною была попытка как раз убрать рутинные действия, чтобы разработчику в принципе было просто начать. Да и в принципе как разработчик всегда стараюсь убрать рутинные действия

Получается, proto-файл генерируется новый при изменениях. А как быть клиентам вашего сервиса? py-клиенты не могут использовать вашу либу, т.к. чтобы им сгенерировать идентичный proto-файл, клиент сам должен быть сервисом. Таким образом, используя вашу библиотеку, могут общатся только одинаковые сервисы?

Я думал, что protobuf предполагает другую схему работы - proto-файл единственный источник правды для всех сервисов и клиентов на любых языках. Вдумчиво меняем proto -> генерируем клиентов/серверы.

У вас же, простое добавление поля в модель ведёт к критическим изменениям протокола.

Сейчас - никак, вы правы, но сама библиотека генерирует proto файл и на его основе делает gRPC сервер, совсем нет проблем так же в рантайме генерировать proto файл и получать его (или генерировать перед этим), а клиент уже генерировать на основе этого proto файла (или вообще чтобы сервер генерировал полноценный Python клиент).

Здесь я скорее хотел показать другой способ использования gRPC и упросить некоторые шаги. Опять же, если версионирование и обратная совместимость нужны, то конечно вариант с proto-файлом как основным источником - максимально полезный. Но в тех случаях когда это не очень важно, думаю, что такая библиотека была бы удобным инструментом, это позволяет быстро поднять gRPC интерфейс, посмотреть что да как

Еще, если бы сервер также автоматически выставлял сервис GRPC reflection, к нему можно было бы сразу делать тестовые запросы хотя бы grpcurl.

Уже сейчас есть возможность включить рефлексию, но возможно было бы лучше, если бы рефлексия была включена по умолчанию, возможно, вы правы

Можно попробовать развернуть схему работы с proto. Редактировать proto-файл руками, не генерировать. Через декоратор класса указывать путь к proto-файлу и имя реализуемого grpc-сервиса, через декоратор метода указывать реализуемый grpc-метод. В декораторе модели указывать путь к proto-файлу и имя message в нём.

Похоже вы используете бибоиотеку не по назначению. Если вам просто нужно уменьшить траффик, то вам нужно включить сжатие траффика, которое предусмотрено в протоколе http. Оно будет на порядок эффективнее и не сильно нагрузит сервер (по своему опыту, но на nodejs)

Да нет, тут скорее в рамках пробы, как я и описывал, не было потребности в Sapphire уменьшать размер трафика (его в принципе пока почти нет), просто хотелось попробовать

Выглядит крайне полезно, тут точно +rep

Тоже при случае пощупаю

По собственным скромным наблюдениям, когда внедряют gRPC, зачастую даже не понимают — а какую, собственно, задачу этим решают. Действительно, какую? Просто, потому что хочется?

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

При сериализации в JSON для каждого свойства можно задать имя поля JSON, которое может отличаться от имени свойства, заданного в программном коде. Это даже является хорошей практикой, чтобы ничего не ломалось при рефакторинге. Добавление полей в JSON не помню что хоть когда-то и для кого-то было проблемой.

А вот минусы:

  • в proto намеренно отключена поддержка null для передачи примитивных типов, и требуются дополнительные совершенно неудобные приседания, либо для обеспечения этой поддержки (через обёртки), либо через усложнённый маппинг, который будет пустые строки конвертить в null. А всегда ли null и пустая строка -- одно и то же? Нет. Или 0 и null, нет!

  • gRPC создан для работы через HTTP/2, а это HTTPS, не получится выполнять классическую детерминацию на прокси (Ingress), придётся возиться с сертификатами там, где с ними обычно никто не возится

  • особо доставляет, когда gRPC на костылях, нарушая требования, запускают на HTTP, потому что "нам так неудобно" и "мы так не привыкли", ну и в общем-то теряя в возможностях протокола, используя только унарные вызовы (ну т.е. тот же REST, только в с лишним обвесом и проблемами).

Конечно, spec first выглядит действительно хорошо. Но это возня с protoc-ом, который просто отваливается, если сервер перешёл на новую версию, а клиентская поддержка ещё не подоспела.

Вообще, gRPC это про экстремальные нагрузки и производительность. Когда это действительно становится уместным, тут уже узким местом будет Python. Вот поэтому и странно, когда низкоуровневый протокол вкорячивают туда, где ему совершенно не место.

Со всем согласен, с перечисленными проблемами в gRPC столкнулся ещё на работе, но хочу поспорить с тем, что если gRPC - это про экстремальные нагрузки, то и Python будет узким местом. Мне кажется, что это не всегда справедливо, ведь большая нагрузка на сеть (соответственно требуется экономия трафика и увеличение скорости передачи) не всегда связаны с невозможностью этот трафик обработать. Например, сеть у нас ограниченная, а вот вычислительных ресурсов достаточно.

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

И насколько уместен gRPC в той или иной задаче - решать каждому отдельному программисту, но мне кажется что связка Python + gRPC имеет право на существование

Так я и не спорю :) Мой вопрос простой, как тапок. Вот, допустим, решали такую-то задачу... Столкнулись с проблемой, взяли gRPC -- получили решение проблемы, которое на классическом REST-е либо вообще не решалось, либо решение было сильно дороже, чем использование gRPC.

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

А просто так, брать и затаскивать gRPC, без целевой задачи, без НТ, без понимания профита, это уже выглядит как "потому что хочется". Ну или это эксперименты. Что вовсе даже и не плохо, только об этом не сказано :)

Конечно могу сильно ошибаться, я со своей стороны вижу проблему применения gRPC в Python не в том, что он интерпретируемый. А в том, что gRPC прямо подразумевает многопоточный процесс с легковесными потоками, управлением памятью, ресурсами -- и это должна быть чистая и естественная среда обитания для платформы, а не приделанная на костылях и подпорках. Вот тогда можно выжимать из протокола максимум. А это постоянный двунаправленный канал, мультиплексирование, почти полное отсутствие сериализации (данные берутся AS IS, по максимуму memcopy). Экономия трафика тут не целевая задача, а скорее побочная.

Если уж хочется просто экономить трафик, можно сжатие, или MessagePack вместо JSON, например :) Вообще позиционных бинарных форматов хватает.

Это не камень в огород, просто хотелось понять, какие были предпосылки.

Конечно могу сильно ошибаться, я со своей стороны вижу проблему
применения gRPC в Python не в том, что он интерпретируемый. А в том, что gRPC прямо подразумевает многопоточный процесс с легковесными потоками, управлением памятью, ресурсами -- и это должна быть чистая и
естественная среда обитания для платформы, а не приделанная на костылях и подпорках. Вот тогда можно выжимать из протокола максимум. А это постоянный двунаправленный канал, мультиплексирование, почти полное отсутствие сериализации (данные берутся AS IS, по максимуму memcopy). Экономия трафика тут не целевая задача, а скорее побочная.

Вы ошибаетесь. Ничего gRPC не подразумевает, прекрасно работает и в других конфигурациях. Кстати в современном мире принято масштабироваться не многопоточностью, а репликами в кубике, оно тогда легко горизонтально масштабируется и блокировками друг другу не мешает.

Я ответ на свой вопрос не получил. Не то, чтобы мне кто-то его обязан давать. Но пока я вижу чистые домыслы, фантазии, и демагогию. Проводились ли какие-то сравнения? Получали какой-то видимый, ощутимый профит? Вообще, была ли обнаружена хоть крупица полезного при использовании gRPC? У инженеров принято как бы не просто занавесочки с розовыми цветочками вешать, потому что фиолетовые "устарели", а розовые они от goolge и вообще модные, но работать с результатом, с цифрами, бенчмарками.

Со своей стороны могу сказать следующее, чистый опыт. Понятно, что это наш субъективный опыт, и вообще не показательно. Но факт, есть факт. Внедрение в наши проекты gRPC на PHP и Python, ничего не принесло, кроме боли, страданий, увеличения Т2М и постоянных проблем у девопсов. Вплоть до того, что проекты стали переносить обратно на REST.

И, в обратную сторону, на проектах .NET был получен видимый профит, просто увидели реальное увеличение производительности, на средних нагрузках. Но, самое главное, на проектах .NET есть транскодинг, т.е. реализация gRPC сервера позволяет сразу покрыть и чистый gRPC и REST для тех клиентов, которым это просто неудобно. Т.е. одним выстрелом двух зайцев.

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

Опять же, я спрашиваю не потому что хочу кого-то захейтить, или задеть за живое. Действительно интересно. Ну правда. Не хочется выслушивать истории фейсбука, варгейминга и прочих волшебных каракатиц. А конкретный опыт. Взяли gRPC, был REST, стало действительно лучше вот настолько-то и настолько-то. Ну или хотябы бенчи какие-нибудь. Нельзя же просто так что-то внедрять, это же не мир модных красных трусов на подиуме. Мы же инженеры. Ну как так :)

Давайте я попробую.

  1. Если вы очень хорошо умеете готовить межсервисное взаимодействие на REST, то gRPC по перформансу ничего вам дополнительно не даст. Ровно как и никакая другая технология.

  2. gRPC сложнее, если вы в целом не готовы в нём глубоко разобраться, а может даже проверить производительность, то не стоит его брать.

  3. Существуют ли преимущества при использовании gRPC? Конечно. Сжатие трафика, разные режимы работы, изменение АПИ без необходимости менять запущенных клиентов. Некоторая обязательная валидация сообщений. Это всё уже есть в коробке. Но при наличии пункта 1 выше, это всё можно написать ручками и поверх REST.

Мы, например, получаем плюсы от gRPC при взаимодействии между командами со своими стеками.
У нас есть ряд сервисов на java, python, js и go.
Есть единый proto репозиторий со спеками продукта.
Команды вносят туда изменения при совместном согласовании (ревью MR).
Далее релизится новая спека и автоматически идёт кодогенерация клиентов и серверов для каждого стека (в отдельных репах). Плюс grpc мок сервера.

С REST контракты поддерживать сложнее и менее удобно. Кодогенерация везде своя и может быть багованной.

Зато у REST отладка удобнее.

в proto намеренно отключена поддержка null

https://protobuf.dev/programming-guides/proto3/#field-labels

optional: An optional field is in one of two possible states:

  • the field is set, and contains a value that was explicitly set or parsed from the wire. It will be serialized to the wire.

  • the field is unset, and will return the default value. It will not be serialized to the wire.

You can check to see if the value was explicitly set.

С остальными проблемами не сталкивались. Работаем по HTTP. В спеки так же добавляем новые поля без необходимости обновления, главное соблюдать порядок.

gRPC создан для работы через HTTP/2, а это HTTPS, не получится выполнять
классическую детерминацию на прокси (Ingress), придётся возиться с
сертификатами там, где с ними обычно никто не возится

Ложное утверждение, всё прекрасно терминируется и HTTP/2 допускает нешифрованный трафик.

Вообще, gRPC это про экстремальные нагрузки и производительность. Когда
это действительно становится уместным, тут уже узким местом будет
Python. Вот поэтому и странно, когда низкоуровневый протокол вкорячивают
туда, где ему совершенно не место.

Расскажите это компании Wargaming, у которой игровые сервера на python, а в каких-нибудь World of warplanes каждая пуля проходит через сервер.

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

gRPC создан для работы через HTTP/2, а это HTTPS, не получится выполнять классическую детерминацию на прокси (Ingress), придётся возиться с сертификатами там, где с ними обычно никто не возится

Вот решение:

ops := []grpc.DialOption{
	grpc.WithTransportCredentials(insecure.NewCredentials()),
}

conn, err := grpc.DialContext(ctx, addr, ops...)

Можно повесить на флаг или env.

Внутри контура не всегда нужен ssl. К тому же это создаёт лишние проблемы и тратит ресурсы. Поэтому вполне нормальным может быть выключение ssl на некоторых сервисах.

Так же полезно при локальной отладке.

А, да, при этом сгенерированные модули практически не читабельны и
потребуют модификации (как минимум потому что там могут быть некорректно
указаны импорты, как максимум - линтеры не пропустят).

Если нужно модифицировать эти файлы, то вы делаете что-то не так.

Всего оказалось две проблемы:

  1. protoc генерирует файлы с абсолютным импортом, то есть если он генерирует файл greeter_pb2.py, то в соседнем greeter_pb2_grpc.py будет импорт `import greeter_pb2`. Есть несколько решений, но все они требуют каких-то действий:

    1. Руками изменить импорт на относительный

    2. В модулях нашего приложения добавить путь к директории сgreeter_pb2.py в sys.path для простого импорта.

    3. Помещать сгенерированные файлы в корень проекта

  2. Изначально сгенерированный код не проходит линтеры, варианты:

    1. Править руками

    2. Править автоматически

    3. Не править и добавить в исключения

Лично мне не нравится добавлять в игнорирование Python модуль, который явно добавляется в репозиторий, но это ИМХО.

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

Всё верно.

  1. В sys.path надо дописать папку

  2. Не проверять файлы линтерами, это не ваши файлы и они не делаются вручную

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

Питонистам? Это как раз тот случай когда прямая калька режет слух и опускает термин до унизительных шуточек. Автор поменяйте на питонщиков!

Это какой-то странный юмор, или вы всерьёз?

Вам действительно "питонист" режет ухо, а "питонщик" - не режет?

Странно сравнивать архитектуру REST и способ сериализации данных Protbuff внутри фреймворка для работы с этой сериализацией gRPC.Выбирая gRPC в самом начале проекта вы замедляете разработку. Сетевого трафика он потребляет меньше, но на этом надо ещё суметь что-то выйграть стоящего времени потраченного на обучение и возьню с прото-файлами. Самое главное, что даёт Protobuff это экономия процессорного времени при сериализации/десериализии данных, на которой тоже надо постараться сэкономить больше чем на времени разработчиков. Какая может быть эффективная экономия ресурсов при использовании Python (я люблю питон) не очень понятно.

Sign up to leave a comment.

Articles