Рубрики
Без рубрики

Реализация сервера GRPC с помощью Python

Примечание: это было первоначально опубликовано на Martinheinz.dev В наши дни, когда люди хотят реализовать Backend … Помечено с Python, WebDev, API, GRPC.

Примечание: это было первоначально опубликовано в martinheinz.dev

В настоящее время, когда люди хотят реализовать Backend API, они идут прямо к созданию приложения с помощью RESTFLAY API, который связывается с использованием JSON, даже не рассматривая другие варианты. В последние годы, Хотя GRPC и его Протобуфс начал получать некоторую тягу и популярность благодаря многим своим преимуществам. Итак, давайте посмотрим, в чем все Buzz/Hype и реализует сервер GRPC с помощью Python!

TL; DR: Вот мой репозиторий с GRPC. Ветка со всеми источниками из этой статьи: https://github.com/MartinHeinz/python-project-blueprint/tree/grpc

Что такое GRPC, в любом случае?

GRPC Протокол удаленной процедуры (RPC), который использует Буферы протокола (Protobufs) Как это формат сообщения. Использование GRPC, клиентское приложение может напрямую вызовать метод, доступный на удаленном сервере, используя методы STUBS. В каком языке на каком языке приложение Server-Side реализуется до тех пор, пока у вас есть заглушки (сгенерированные) для вашего языка клиента. GRPC поддерживает множество языков, включая GO, Java, Ruby, C # или наш язык выбора – Python. Вы можете найти больше информации в этом Обзор Отказ

Теперь, что такое Буферы протокола (Protobufs) ? Протобуфс альтернативы форматам, такими как JSON или XML. Они меньше, проще и более эффективный способ сериализации данных. Использовать протобуфс , вам нужно определить, как вы хотите, например, обмененные сообщения (для получения дополнительной специфики см. Это руководство по языку ):

// example.proto
syntax = "proto3";

package example;

message User {
  int32 id = 1;
  string name = 2;
}

message UserInfo {
  int32 age = 1;
  string address = 2;
  string phoneNumber = 3;
}

Помимо сообщений, нам также нужно определить Сервис с и их RPC Методы, которые будут реализованы на сервере и вызывают с клиентской стороны:

// ...

service UserService {
  rpc GetUserInfo (User) returns (UserInfo) {}
}

Почему я должен заботиться, в любом случае?

Существует довольно много преимуществ для использования GRPC на отдых. Во-первых, GRPC гораздо лучше, когда дело доходит до производительности, благодаря жесткой упаковке Протобуфс , что снижает размер отправки полезных нагрузок. Он также использует HTTP/2, а не HTTP/1.1, как ослаблен. По этим причинам это отличный выбор для IoT, мобильных устройств или других ограниченных/с низкой мощностью.

Другая причина выбрать GRPC за все время отдохнуть состоит в том, что отдых не имеет никакой реальной структуры. Вы можете определить формат запросов и ответов, используя Openapi, но это свободно и необязательно. Контракты GRPC с другой стороны являются более строгими и четко определены.

Как уже упомянутое GRPC использует HTTP/2 И приятно упомянуть, что это в полной мере, в полном объеме его функций. Чтобы назвать несколько: одновременные запросы, потоковое вместо запроса-ответ, меньшая чувствительность к задержелю.

Тем не менее, существуют также недостатки, и самый большой, который является усыновлением. Не все клиенты (браузеры) поддерживают использование HTTP/2, что делает его проблематичным для наружного использования. Учитывая преимущества производительности, хотя это явно отличный выбор для внутренних услуг и коммуникаций, который у вас есть контроль.

Настройка

Сделать что-нибудь с GRPC и протобуфс Нам нужно установить его компилятор:

#! /bin/bash
# Download and Unzip compiler
curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip
unzip protoc-3.11.4-linux-x86_64.zip -d protoc3

# Move the binary to directory which is PATH
sudo mv protoc3/bin/* /usr/local/bin/

sudo mv protoc3/include/* /usr/local/include/

# Change owner
sudo chown $USER /usr/local/bin/protoc
sudo chown -R $USER /usr/local/include/google

# Test if it works
protoc --version
# libprotoc 3.11.4

Учитывая, что мы используем Python, чтобы построить наше приложение, нам также понадобятся Grpcio и grpcio-tools Библиотеки:

# Activate venv if you have one
source .../venv/bin/activate
pip install grpcio grpcio-tools

Давайте построить что-то

Со всеми инструментами готовы теперь мы можем на самом деле двигаться на создание приложения. Для этого примера я выбрал Simple Echo Server, который отправляет вам свои собственные сообщения.

Во-первых, о том, что мы должны говорить, хотя, это проектный макет. Я выбрал следующую каталог/Структуру файлов:

.
├── blueprint                 <- Source root - Name of our project
│   ├── app.py                <- Application server
│   ├── echo_client.py        <- gRPC client for testing
│   ├── generated             <- Generated gRPC Python code
│   │   ├── echo_pb2_grpc.py
│   │   └── echo_pb2.py
│   ├── grpc.py               <- Actual gRPC code
│   ├── __init__.py
│   ├── __main__.py
│   ├── proto                 <- Protobuf definitions
│   │   └── echo.proto
│   └── resources
├── tests                     <- Test suite
│   ├── conftest.py
│   ├── context.py
│   ├── __init__.py
│   └── test_grpc.py
├── Makefile
├── pytest.ini
└── requirements.txt

Этот макет помогает нам четко отделить Protobuf Файлы ( .../Proto ), сгенерированные источники ( .../сгенерированы ), фактический исходный код и наш тестовый люкс. Чтобы узнать больше о том, как настроить Python Project с таком родом макета вы можете оформить заказ моей предыдущей статьи:

https://towardsdatascience.com/ultimate-setup-for-your-next-python-project-179bda8a7c2c

Итак, построить сервер GRPC, мы – во-первых и прежде всего – нужно определить Сообщения и Сервисы) Это будет использовать вас для общения с клиентами:

// echo.proto
syntax = "proto3";
package echo;

// The request message containing the user's message.
message EchoRequest {
  string message = 1;
}

// The response message containing the original message.
message EchoReply {
  string message = 1;
}

// The echo service definition.
service Echo {
  // Echo back reply.
  rpc Reply (EchoRequest) returns (EchoReply) {}
}

В этом echo.proto Файл Мы можем увидеть очень простое определение типов сообщений – один для запроса ( echorequest ) и один для ответа ( e echoreply ) с сервера. Эти сообщения затем используются Эхо Сервис, который состоит из одного метода RPC под названием Отвечать .

Чтобы иметь возможность использовать эти определения в Python Code, нам нужно создать серверные и клиентские интерфейсы. Для этого мы можем запустить эту команду:

python3 -m grpc_tools.protoc \
        --python_out=./blueprint/generated \
        --grpc_python_out=./blueprint/generated \
        ./blueprint/proto/*.proto

sed -i -E 's/^import.*_pb2/from . \0/' ./blueprint/generated/*.py

Мы указали довольно много аргументов. Сначала из них – -Я План/Прото рассказывает grpc_tools Где искать наш .Proto Файлы (определяет путь ). Следующие два, -PYPON-OUT и --grpc_Python_out. Укажите, где выводится сгенерированные * _PB2.PY и * _grpc_pb2.py . Файлы соответственно. Последний аргумент – ./blueprint/proto/*.proto актуальный путь к .Proto Файлы – это может показаться избыточным, как мы указали ДОРОЖКА с -I , Но вам нужно оба, чтобы сделать эту работу.

Однако при запуске этой команды вы получите несколько разбитых импорта в этих сгенерированных файлах. Есть несколько поднятых проблемы в GRPC. и Protobuf Репозитории и самое простое решение – просто исправить эти импорт с Sed Отказ

Написание этой команды не будет очень приятным и неэффективным, поэтому я завернул его в сделать цель, чтобы сделать вашу (и мою) жизнь проще. Вы можете найти полный Makefile в моем репозитории здесь Отказ

Там довольно много кода, который генерируется с помощью этой команды, поэтому я не буду проходить все немного, но есть несколько важных вещей, чтобы посмотреть. Каждый из этих * _PB2_GRPC.PY Файлы выполняют следующие 3 вещи:

  • Заглушка – Сначала из них – Заглушка И в нашем случае Echostub – это класс, используемый клиентом для подключения к службе GRPC
  • Сервис – В нашем случае Echoservicer – используется сервером для реализации службы GRPC
  • Регистрация Функция – Наконец, кусок, add_echoservicer_to_server . Это необходимо для регистрации обслуживания с сервером GRPC.

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

Первое, что мы хотим сделать, это реализовать фактический сервис. Мы сделаем это в grpc.py Файл, где мы будем хранить весь конкретный код GRPC:

# grpc.py
from .generated import echo_pb2_grpc, echo_pb2


class Echoer(echo_pb2_grpc.EchoServicer):

    def Reply(self, request, context):
        return echo_pb2.EchoReply(message=f'You said: {request.message}')

Выше мы создаем Echoer Класс, который наследует от создания Echoservicer Класс, который содержит все методы, определенные в .Proto файл. Все эти методы предназначены для переопределения в нашей реализации, и здесь мы делаем только это. Мы реализуем единственный метод Ответить Вернувшись Эхопросто Сообщение, которое мы также определены в .Proto файл. Я хочу указать, что Запрос Параметр здесь является экземпляром Эхопросто – Вот почему мы можем получить сообщение из этого. Мы не используем контекст Параметр здесь, но он содержит некоторую полезную информацию, специфичную к RPC, например, пределы времени ожидания.

Одна аккуратная функция, я также хочу упомянуть, что на случай, если вы хотите использовать Реакция Вы могли бы заменить вернуть с доходность и вернуть несколько ответов (в для Цикл).

Теперь, когда мы реализовали службу GRPC, мы хотим запустить его. Для этого нам нужен сервер:

# app.py
from concurrent import futures
import grpc

from .generated import echo_pb2_grpc
from .grpc import Echoer


class Server:

    @staticmethod
    def run():
        server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
        echo_pb2_grpc.add_EchoServicer_to_server(Echoer(), server)
        server.add_insecure_port('[::]:50051')
        server.start()
        server.wait_for_termination()

Все это, это просто один статический метод. Это создает сервер от GRPC Библиотека с несколькими работниками – в этом случае 10. После этого он использует ранее упомянутую регистрацию ( add_echoservicer_to_server ), чтобы связать наше Echoer Сервис к серверу. Оставшиеся 3 строки просто добавьте порту прослушивания, запускайте сервер и дождитесь прерывания.

Все, что остается для сервера – __main__.py Так что мы можем начать его как модуль Python:

# __main__.py
from .app import Server

if __name__ == '__main__':
    Server.run()

С этим мы все настроены на запуск сервера. Вы можете сделать это с Python -m blueprint или если вы используете свой шаблон, то просто сделать бегать Отказ

У нас есть сервер работает, но у нас нет способа позвонить … Вот где он приходит клиент. Для демонстрационных целей мы создадим клиента в Python, используя для нас заглушки, но вы можете написать клиенту на совершенно другом языке.

from __future__ import print_function
import logging

import grpc

from .generated import echo_pb2
from .generated import echo_pb2_grpc


def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = echo_pb2_grpc.EchoStub(channel)
        response = stub.Reply(echo_pb2.EchoRequest(message='Hello World!'))
    print("Echo client received: " + response.message)


if __name__ == '__main__':
    logging.basicConfig()
    run()

Для клиента нам нужна только одна функция, которую мы называем Беги Отказ После подключения сервера он создает заглушку, который позволит нам вызвать метод сервера, который является следующим шагом. Это называет Ответить Метод реализован на стороне сервера, проходя мимо Echorequest сообщение с некоторой полезной нагрузкой. Все, что осталось, это просто распечатать его.

Теперь давайте запустим клиента и посмотрим, будет ли все, как и ожидалось:

~ $ python -m blueprint.echo_client
Echo client received: You said: Hello World!

И это работает!

Тестирование с pteest.

Как и со всеми моими небольшими проектами и статьями, мы не делаем, пока не будут тесты единиц для всего кода. Чтобы написать образец теста на этот сервер GRPC, я буду использовать Питиш и его плагин pytest-grpc. .

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

# conftest.py
import pytest


@pytest.fixture(scope='module')
def grpc_add_to_server():
    from blueprint.generated.echo_pb2_grpc import add_EchoServicer_to_server

    return add_EchoServicer_to_server


@pytest.fixture(scope='module')
def grpc_servicer():
    from blueprint.grpc import Echoer

    return Echoer()


@pytest.fixture(scope='module')
def grpc_stub(grpc_channel):
    from blueprint.generated.echo_pb2_grpc import EchoStub

    return EchoStub(grpc_channel)

Я думаю, что все это довольно просто. Просто обязательно используйте эти конкретные имена для этих светильников, так как это выглядит плагин. Одна вещь, чтобы заметить, это grpc_channel Аргумент в grpc_stub. . Это поддельный канал, поставляемый pytest-grpc плагин. Для получения дополнительной информации я рекомендую идти прямо в pytest-grpc Исходный код , как плагин довольно прост. С этим давайте перейдем к фактическому тесту:

# test_grpc.py

def test_reply(grpc_stub):
    value = 'test-data'
    request = blueprint.echo_pb2.EchoRequest(message=value)
    response = grpc_stub.Reply(request)

    assert response.message == f'You said: {value}'

Мы создаем этот тест, используя grpc_stub Приспособление, которое мы написали на предыдущем шаге. Мы создаем Echorequest который передан на grpc_stub. Ответить следуют простым утверждать . И, когда мы запускаем тест ( Run ):

plugins: cov-2.8.1, metadata-1.8.0, grpc-0.7.0, html-2.0.1
collected 1 item                                                                                                                           

tests/test_grpc.py::test_reply PASSED                                                                                                [100%]

----------- coverage: platform linux, python 3.7.5-final-0 -----------
Name                                   Stmts   Miss Branch BrPart  Cover
------------------------------------------------------------------------
blueprint/__init__.py                      3      0      0      0   100%
blueprint/app.py                          11      5      0      0    55%
blueprint/echo_client.py                  10     10      0      0     0%
blueprint/generated/echo_pb2.py           18      0      0      0   100%
blueprint/generated/echo_pb2_grpc.py      18      4      0      0    78%
blueprint/grpc.py                          4      0      0      0   100%
------------------------------------------------------------------------
TOTAL                                     64     19      0      0    70%
Coverage XML written to file coverage.xml


============================================================ 1 passed in 0.09s =============================================================

Мы прошли! Aaaand мы сделали!

Заключение

Если вы забрали только одну вещь из этой статьи, я думаю, что это будет тот факт, что мы всегда должны учитывать возможные альтернативы при принятии решения о решении/технологии, которые мы хотим использовать для некоторых проектов. Это не всегда нужно отдыхать и json. Иногда GRPC может лучше соответствовать требованиям. Такое мышление также относится к любым другим технологиям или инструменту. Чтобы увидеть полный список кодовых списков с Makefile Автоматизация, подготовленные докинские изображения и даже настроек для развертывания в Kubernetes, пожалуйста, проверьте GRPC Ветка в моем репозитории здесь: https://github.com/martinheinz/python-project-blueprint/tree/master Отказ Любая обратная связь ценится, как и звезда или вилка, если вам нравится этот вид контента. 😉

Оригинал: “https://dev.to/martinheinz/implementing-grpc-server-using-python-4fk0”