1. Введение
В этой лабораторной работе вы будете использовать gRPC-Python для создания клиента и сервера, которые составят основу приложения для отображения маршрутов, написанного на Python.
К концу руководства у вас будет клиент, который подключается к удалённому серверу с помощью gRPC для получения названия или почтового адреса объекта, расположенного в определённых координатах на карте. Полноценное приложение может использовать эту клиент-серверную архитектуру для перечисления или суммирования точек интереса на маршруте.
Служба определена в файле Protocol Buffers, который будет использоваться для генерации шаблонного кода для клиента и сервера, чтобы они могли взаимодействовать друг с другом, экономя ваше время и усилия при реализации этой функциональности.
Сгенерированный код учитывает не только сложности взаимодействия между сервером и клиентом, но также сериализацию и десериализацию данных.
Чему вы научитесь
- Как использовать Protocol Buffers для определения API сервиса.
- Как создать клиент и сервер на основе gRPC из определения Protocol Buffers с использованием автоматической генерации кода.
- Понимание клиент-серверного взаимодействия с помощью gRPC.
Эта практическая работа предназначена для разработчиков Python, впервые использующих 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 с помощью плагина компилятора буфера протокола grpc_tools.protoc
.
grpc-codelabs
Исходный код scaffold для этой лабораторной работы доступен в каталоге codelabs/grpc-python-getting-started/start_here . Если вы предпочитаете не реализовывать код самостоятельно, готовый исходный код доступен в каталоге completed
.
Сначала создайте рабочий каталог codelab и перейдите в него:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Загрузите и распакуйте кодовую лабораторию:
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
предоставленного исходного кода.
Буферы протоколов обычно называются 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. Сгенерируйте клиентский и серверный код.
Затем сгенерируйте шаблонный код gRPC для клиента и сервера из файла .proto
, используя компилятор буфера протокола.
Для генерации кода gRPC Python мы создали пакет grpcio-tools . Он включает в себя:
- Обычный компилятор протоколов , который генерирует код Python из определений
message
. - Плагин gRPC protobuf, который генерирует код Python (клиентские и серверные заглушки) из определений
service
.
Мы установим пакет Python grpcio-tools
с помощью 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()
Метод server.start 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