1. Введение
В этом практическом занятии вы будете использовать gRPC-Python для создания клиента и сервера, которые составляют основу приложения для построения маршрутов, написанного на Python.
К концу этого урока у вас будет клиент, который подключается к удалённому серверу с помощью gRPC , чтобы получить имя или почтовый адрес объекта, расположенного по определённым координатам на карте. Полноценное приложение может использовать эту клиент-серверную архитектуру для перечисления или обобщения точек интереса вдоль маршрута.
Сервис определяется в файле Protocol Buffers, который будет использоваться для генерации шаблонного кода для клиента и сервера, чтобы они могли взаимодействовать друг с другом, экономя ваше время и усилия на реализации этой функциональности.
Сгенерированный код учитывает не только сложности взаимодействия между сервером и клиентом, но и сериализацию и десериализацию данных.
Что вы узнаете
- Как использовать Protocol Buffers для определения API сервиса.
- Как создать клиент и сервер на основе gRPC из определения Protocol Buffers с помощью автоматической генерации кода.
- Понимание взаимодействия клиент-сервер с использованием gRPC.
Данный практический семинар предназначен для разработчиков на Python, которые только начинают работать с gRPC или хотят освежить свои знания gRPC, а также для всех, кто заинтересован в создании распределенных систем. Предварительный опыт работы с gRPC не требуется.
2. Прежде чем начать
Что вам понадобится
- Python 3.9 или выше. Мы рекомендуем Python 3.13. Инструкции по установке для конкретной платформы см. в разделе «Настройка и использование Python» . В качестве альтернативы можно установить Python, не являющийся системным, используя такие инструменты, как uv или pyenv .
- Используйте pip для установки пакетов Python.
- venv для создания виртуальных сред Python.
Пакеты ensurepip и venv являются частью стандартной библиотеки Python и обычно доступны по умолчанию.
Однако некоторые дистрибутивы на основе Debian (включая Ubuntu) исключают их при распространении Python. Для установки пакетов выполните следующую команду:
sudo apt install python3-pip python3-venv
Получите код
Для упрощения обучения в этом практическом занятии предлагается готовый шаблон исходного кода, который поможет вам начать работу. Следующие шаги проведут вас через завершение приложения, включая генерацию кода gRPC с использованием плагина компилятора Protocol Buffer grpc_tools.protoc .
grpc-codelabs
Исходный код для этого практического занятия доступен в каталоге codelabs/grpc-python-getting-started/start_here . Если вы предпочитаете не реализовывать код самостоятельно, готовый исходный код доступен в каталоге completed .
Сначала создайте рабочую директорию codelab и перейдите в неё с помощью команды cd:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Скачайте и распакуйте CodeLab:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-python-getting-started/start_here
В качестве альтернативы вы можете скачать ZIP-архив, содержащий только папку codelab, и распаковать его вручную.
3. Определите услугу.
Первым шагом является определение gRPC-сервиса приложения, его RPC-метода, а также типов сообщений запроса и ответа с использованием языка определения интерфейса Protocol Buffers . Ваш сервис будет предоставлять:
- Метод RPC под названием
GetFeature, который реализует сервер, а клиент вызывает. - Типы сообщений
PointиFeatureпредставляют собой структуры данных, которыми обмениваются клиент и сервер при использовании методаGetFeature. Клиент предоставляет координаты карты в видеPointв своем запросеGetFeatureк серверу, а сервер отвечает соответствующимFeature, описывающим то, что находится по этим координатам.
Данный RPC-метод и типы сообщений для него будут определены в файле protos/route_guide.proto предоставленного исходного кода.
Протоколы Protocol Buffers обычно называются protobuf. Для получения дополнительной информации о терминологии gRPC см. раздел «Основные концепции, архитектура и жизненный цикл gRPC».
Типы сообщений
В файле protos/route_guide.proto исходного кода сначала определите тип сообщения Point . Point представляет собой пару координат широты и долготы на карте. Для этого практического задания используйте целые числа для координат:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Цифры 1 и 2 — это уникальные идентификационные номера для каждого поля в структуре message .
Далее определите тип сообщения Feature . В Feature используется string поле для имени или почтового адреса объекта, расположенного в точке Point :
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Метод обслуживания
В файле route_guide.proto содержится структура service с именем RouteGuide , которая определяет один или несколько методов, предоставляемых сервисом приложения.
Добавьте rpc метод GetFeature в определение RouteGuide . Как объяснялось ранее, этот метод будет искать название или адрес местоположения по заданному набору координат, поэтому пусть GetFeature возвращает Feature для заданной Point :
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Это унарный RPC-метод: простой RPC-вызов , при котором клиент отправляет запрос на сервер и ожидает ответа, подобно вызову локальной функции.
4. Сгенерируйте код клиента и сервера.
Далее, используя компилятор Protocol Buffer, сгенерируйте шаблонный gRPC-код для клиента и сервера из файла .proto .
Для генерации кода gRPC на Python мы создали grpcio-tools . Он включает в себя:
- Стандартный компилятор protoc , генерирующий код Python на основе определений
message. - Плагин gRPC protobuf, генерирующий код Python (заглушки для клиента и сервера) на основе определений
service.
Мы установим пакет grpcio-tools для Python с помощью pip. Давайте создадим новое виртуальное окружение Python (venv), чтобы изолировать зависимости вашего проекта от системных пакетов:
python3 -m venv --upgrade-deps .venv
Для активации виртуального окружения в оболочке bash/zsh:
source .venv/bin/activate
Для Windows и нестандартных оболочек см. таблицу по адресу https://docs.python.org/3/library/venv.html#how-venvs-work .
Далее установите grpcio-tools (это также установит пакет grpcio ):
pip install grpcio-tools
Для генерации шаблонного кода на Python используйте следующую команду:
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
В результате будут сгенерированы следующие файлы для интерфейсов, определенных в route_guide.proto :
-
route_guide_pb2.pyсодержит код , который динамически создает классы, генерируемые на основе определенийmessage. -
route_guide_pb2.pyi— это «файл-заглушка» или «файл подсказок типов», созданный на основе определенийmessage. Он содержит только сигнатуры без какой-либо реализации. Файлы-заглушки могут использоваться IDE для улучшения автозавершения кода и обнаружения ошибок. -
route_guide_pb2_grpc.pyгенерируется на основе определенийserviceи содержит классы и функции, специфичные для gRPC.
Специализированный код gRPC содержит:
-
RouteGuideStub, который может использоваться gRPC-клиентом для вызова RPC-вызовов RouteGuide. -
RouteGuideServicer, который определяет интерфейс для реализаций сервисаRouteGuide. - Функция
add_RouteGuideServicer_to_serverиспользуется для регистрацииRouteGuideServicerна gRPC-сервере .
5. Создайте сервис.
Для начала давайте рассмотрим, как создать сервер RouteGuide . Создание и запуск сервера RouteGuide состоит из двух этапов:
- Реализация интерфейса сервиса, сгенерированного на основе определения нашего сервиса, с функциями, которые выполняют фактическую «работу» сервиса.
- Запуск gRPC-сервера на определенном порту для приема запросов от клиентов и отправки ответов.
Исходный сервер RouteGuide можно найти в start_here/route_guide_server.py .
Внедрить RouteGuide
В route_guide_server.py есть класс RouteGuideServicer , который наследует сгенерированный класс route_guide_pb2_grpc.RouteGuideServicer :
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer реализует все методы сервиса RouteGuide .
Давайте подробно рассмотрим простую реализацию RPC. Метод GetFeature получает Point от клиента и возвращает соответствующую информацию о объекте из его базы данных в Feature .
def GetFeature(self, request, context):
feature = get_feature(self.db, request)
if feature is None:
return route_guide_pb2.Feature(name="", location=request)
else:
return feature
Методу передается запрос route_guide_pb2.Point для RPC-вызова и объект grpc.ServicerContext , предоставляющий информацию, специфичную для RPC, например, ограничения по времени ожидания. Он возвращает ответ route_guide_pb2.Feature .
Запуск сервера
После реализации всех методов RouteGuide следующим шагом будет запуск gRPC-сервера, чтобы клиенты могли фактически использовать ваш сервис:
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
RouteGuideServicer(),
server,
)
listen_addr = "localhost:50051"
server.add_insecure_port(listen_addr)
print(f"Starting server on {listen_addr}")
server.start()
server.wait_for_termination()
Метод start() сервера является неблокирующим. Для обработки запросов будет создан новый поток. Поток, вызывающий server.start() , часто не имеет других задач в это время. В этом случае можно вызвать server.wait_for_termination() , чтобы корректно заблокировать вызывающий поток до завершения работы сервера.
6. Создайте клиента.
В этом разделе мы рассмотрим создание клиента для нашего сервиса RouteGuide . Начальный код клиента можно посмотреть в start_here/route_guide_client.py .
Создать заглушку
Для вызова методов сервиса нам сначала нужно создать заглушку .
Мы создаём экземпляр класса RouteGuideStub модуля route_guide_pb2_grpc , сгенерированного из нашего .proto файла внутри файла route_guide_client.py .
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Способы вызова сервиса
Для методов RPC, возвращающих один ответ (известных как методы с унарным ответом), gRPC Python поддерживает как синхронную (блокирующую), так и асинхронную (неблокирующую) семантику управления потоком.
Простой RPC
Для начала определим Point с помощью которой будет вызываться сервис. Это должно быть так же просто, как создание объекта из пакета route_guide_pb2 с некоторыми свойствами:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Синхронный вызов простого RPC- GetFeature почти так же прост, как вызов локального метода. RPC-вызов ожидает ответа от сервера и либо возвращает ответ, либо генерирует исключение. Мы можем вызвать метод и увидеть ответ примерно так:
feature = stub.GetFeature(point)
print(feature)
Вы можете просмотреть поля объекта Feature и вывести результат запроса:
if feature.name:
print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
print(f"Found no feature at at {format_point(feature.location)}")
7. Попробуйте.
Запустите сервер:
python route_guide_server.py
С другого терминала снова активируйте виртуальную среду, затем запустите клиент:
python route_guide_client.py
В результате вы увидите примерно такой вывод, при этом временные метки для наглядности опущены:
name: "16 Old Brook Lane, Warwick, NY 10990, USA"
location {
latitude: 412346009
longitude: -744026814
}
Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814
8. Что дальше?
- Узнайте, как работает gRPC, в разделе «Введение в gRPC и основные концепции».
- Пройдите базовый курс.
- Изучите справочник по API Python.