1. Wprowadzenie
W tym module nauczysz się tworzyć za pomocą gRPC-Python klienta i serwera, które stanowią podstawę aplikacji do mapowania tras napisanej w Pythonie.
Po ukończeniu tego samouczka będziesz mieć klienta, który łączy się z serwerem zdalnym za pomocą gRPC, aby uzyskać nazwę lub adres pocztowy miejsca znajdującego się pod określonymi współrzędnymi na mapie. W pełni funkcjonalna aplikacja może korzystać z tego modelu klient-serwer, aby wyliczać lub podsumowywać ważne miejsca na trasie.
Usługa jest zdefiniowana w pliku Protocol Buffers, który będzie używany do generowania kodu szablonowego dla klienta i serwera, aby mogły się ze sobą komunikować. Dzięki temu zaoszczędzisz czas i wysiłek potrzebny na wdrożenie tej funkcji.
Wygenerowany kod obsługuje nie tylko złożoność komunikacji między serwerem a klientem, ale także serializację i deserializację danych.
Czego się nauczysz
- Jak używać buforów protokołu do definiowania interfejsu API usługi.
- Jak utworzyć klienta i serwer oparte na gRPC na podstawie definicji Protocol Buffers za pomocą automatycznego generowania kodu.
- Znajomość komunikacji klient-serwer z użyciem gRPC.
Te warsztaty są przeznaczone dla programistów Pythona, którzy dopiero zaczynają korzystać z gRPC lub chcą sobie przypomnieć podstawy tej technologii, a także dla wszystkich innych osób zainteresowanych tworzeniem systemów rozproszonych. Nie musisz mieć wcześniejszego doświadczenia z gRPC.
2. Zanim zaczniesz
Czego potrzebujesz
- Python w wersji 3.9 lub nowszej. Zalecamy Pythona 3.13. Instrukcje instalacji na poszczególnych platformach znajdziesz w artykule Python Setup and Usage (Konfigurowanie i używanie Pythona). Możesz też zainstalować Pythona, który nie jest częścią systemu, za pomocą narzędzi takich jak uv lub pyenv.
- pip do instalowania pakietów Pythona.
- venv do tworzenia wirtualnych środowisk Pythona.
Pakiety ensurepip
i venv
są częścią standardowej biblioteki Pythona i zazwyczaj są dostępne domyślnie.
Niektóre dystrybucje oparte na Debianie (w tym Ubuntu) decydują się jednak na wykluczenie ich podczas redystrybucji Pythona. Aby zainstalować pakiety, uruchom to polecenie:
sudo apt install python3-pip python3-venv
Pobierz kod
Aby ułatwić Ci naukę, w tym ćwiczeniu w Codelabs znajdziesz gotowy szkielet kodu źródłowego, który pomoże Ci zacząć. Poniższe kroki pomogą Ci wypełnić aplikację, w tym wygenerować kod gRPC za pomocą wtyczki kompilatora grpc_tools.protoc
Protocol Buffer.
grpc-codelabs
Kod źródłowy szkieletu tego modułu jest dostępny w katalogu codelabs/grpc-python-getting-started/start_here. Jeśli nie chcesz samodzielnie implementować kodu, gotowy kod źródłowy znajdziesz w katalogu completed
.
Najpierw utwórz katalog roboczy z ćwiczeniami i przejdź do niego:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Pobierz i rozpakuj ćwiczenia z programowania:
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
Możesz też pobrać plik ZIP zawierający tylko katalog z instrukcjami i rozpakować go ręcznie.
3. Określ usługę
Pierwszym krokiem jest zdefiniowanie usługi gRPC aplikacji, jej metody RPC oraz typów wiadomości żądania i odpowiedzi za pomocą języka definicji interfejsu Protocol Buffers. Twoja usługa będzie zapewniać:
- Metoda RPC o nazwie
GetFeature
, która jest zaimplementowana na serwerze i wywoływana przez klienta. - Typy wiadomości
Point
iFeature
to struktury danych wymieniane między klientem a serwerem podczas korzystania z metodyGetFeature
. Klient podaje współrzędne mapy jakoPoint
w żądaniuGetFeature
wysyłanym do serwera, a serwer odpowiada, przesyłając odpowiedniFeature
, który opisuje wszystko, co znajduje się pod tymi współrzędnymi.
Ta metoda RPC i jej typy wiadomości będą zdefiniowane w pliku protos/route_guide.proto
podanego kodu źródłowego.
Bufory protokołu są powszechnie znane jako protobuf. Więcej informacji o terminologii gRPC znajdziesz w artykule Podstawowe koncepcje, architektura i cykl życia.
Rodzaje wiadomości
W protos/route_guide.proto
pliku kodu źródłowego najpierw zdefiniuj Point
typ wiadomości. Symbol Point
reprezentuje parę współrzędnych szerokości i długości geograficznej na mapie. W tym ćwiczeniu używaj liczb całkowitych jako współrzędnych:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Numery 1
i 2
to unikalne identyfikatory poszczególnych pól w strukturze message
.
Następnie określ Feature
typ wiadomości. Feature
używa pola string
na nazwę lub adres pocztowy czegoś w lokalizacji określonej przez Point
:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Metoda usługi
Plik route_guide.proto
ma strukturę service
o nazwie RouteGuide
, która definiuje co najmniej 1 metodę udostępnianą przez usługę aplikacji.
Dodaj metodę rpc
GetFeature
w definicji RouteGuide
. Jak wspomnieliśmy wcześniej, ta metoda wyszukuje nazwę lub adres lokalizacji na podstawie podanego zestawu współrzędnych, więc w przypadku danego Point
zwraca GetFeature
Feature
:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Jest to metoda RPC typu unary: prosta procedura RPC, w której klient wysyła żądanie do serwera i czeka na odpowiedź, podobnie jak w przypadku lokalnego wywołania funkcji.
4. Generowanie kodu klienta i serwera
Następnie wygeneruj kod gRPC dla klienta i serwera z pliku .proto
za pomocą kompilatora bufora protokołu.
Do generowania kodu Pythona gRPC stworzyliśmy narzędzie grpcio-tools. Usługa ta obejmuje:
- Zwykły kompilator protoc, który generuje kod Pythona z definicji
message
. - wtyczka gRPC protobuf, która generuje kod Pythona (namiastki klienta i serwera) z definicji
service
;
Zainstalujemy pakiet Pythona grpcio-tools
za pomocą narzędzia pip. Utwórz nowe wirtualne środowisko Pythona (venv), aby odizolować zależności projektu od pakietów systemowych:
python3 -m venv --upgrade-deps .venv
Aby aktywować środowisko wirtualne w powłoce bash/zsh:
source .venv/bin/activate
W przypadku systemu Windows i niestandardowych powłok zobacz tabelę na stronie https://docs.python.org/3/library/venv.html#how-venvs-work.
Następnie zainstaluj grpcio-tools (spowoduje to również zainstalowanie pakietu grpcio):
pip install grpcio-tools
Aby wygenerować kod początkowy w Pythonie, użyj tego polecenia:
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
Spowoduje to wygenerowanie tych plików dla interfejsów zdefiniowanych w route_guide.proto
:
route_guide_pb2.py
zawiera kod dynamicznie tworzący klasy wygenerowane na podstawie definicjimessage
.route_guide_pb2.pyi
to „plik stub” lub „plik wskazówek dotyczących typu” wygenerowany na podstawie definicjimessage
. Zawiera tylko sygnatury bez implementacji. Pliki stub mogą być używane przez środowiska IDE, aby zapewnić lepsze autouzupełnianie i wykrywanie błędów.route_guide_pb2_grpc.py
jest generowany na podstawie definicjiservice
i zawiera klasy oraz funkcje specyficzne dla gRPC.
Kod gRPC zawiera:
RouteGuideStub
, z którego klient gRPC może korzystać do wywoływania wywołań RPC RouteGuide.RouteGuideServicer
, który definiuje interfejs implementacji usługiRouteGuide
.add_RouteGuideServicer_to_server
, która służy do rejestrowaniaRouteGuideServicer
na serwerze gRPC.
5. Tworzenie usługi
Najpierw zobaczmy, jak utworzyć RouteGuide
serwerRouteGuide
. Tworzenie i uruchamianie serwera RouteGuide
dzieli się na 2 etapy:
- Wdrożenie interfejsu usługi wygenerowanego na podstawie definicji usługi za pomocą funkcji, które wykonują rzeczywistą „pracę” usługi.
- Uruchomienie serwera gRPC na określonym porcie, aby nasłuchiwać żądań od klientów i przesyłać odpowiedzi.
Początkowy serwer RouteGuide
znajdziesz w start_here/route_guide_server.py
.
Implementacja RouteGuide
Klasa route_guide_server.py
ma klasę RouteGuideServicer
, która jest podklasą wygenerowanej klasy route_guide_pb2_grpc.RouteGuideServicer
:
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer
implementuje wszystkie metody usługi RouteGuide
.
Przyjrzyjmy się szczegółowo prostej implementacji RPC. Metoda GetFeature
otrzymuje od klienta Point
i zwraca odpowiednie informacje o funkcji z bazy danych w 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
Metoda otrzymuje route_guide_pb2.Point
żądanie RPCgrpc.ServicerContext
i obiekt grpc.ServicerContext
, który zawiera informacje specyficzne dla RPC, takie jak limity czasu. Zwraca odpowiedź route_guide_pb2.Feature
.
Uruchamianie serwera
Po zaimplementowaniu wszystkich RouteGuide
metod następnym krokiem jest uruchomienie serwera gRPC, aby klienci mogli korzystać z Twojej usługi:
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()
Metoda serwera start()
nie blokuje wątku. Do obsługi żądań zostanie utworzony nowy wątek. Wątek wywołujący funkcję server.start()
często nie ma w tym czasie nic innego do zrobienia. W takim przypadku możesz wywołać funkcję server.wait_for_termination()
, aby prawidłowo zablokować wątek wywołujący do momentu zakończenia działania serwera.
6. Tworzenie klienta
W tej sekcji zajmiemy się tworzeniem klienta dla usługi RouteGuide
. Początkowy kod klienta znajdziesz w start_here/route_guide_client.py
.
Tworzenie stubu
Aby wywoływać metody usługi, musimy najpierw utworzyć stub.
Tworzymy instancję klasy RouteGuideStub
z modułu route_guide_pb2_grpc
, wygenerowaną z naszego .proto
w pliku route_guide_client.py
.
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Metody wywoływania usługi
W przypadku metod RPC, które zwracają pojedynczą odpowiedź – znanych jako metody response-unary – gRPC Python obsługuje zarówno synchroniczną (blokującą), jak i asynchroniczną (nieblokującą) semantykę przepływu sterowania.
Proste wywołanie RPC
Najpierw zdefiniujmy Point
, za pomocą którego będziemy wywoływać usługę. Powinno to być tak proste, jak utworzenie instancji obiektu z pakietu route_guide_pb2
z kilkoma właściwościami:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Synchroniczne wywołanie prostego RPC GetFeature
jest prawie tak proste jak wywołanie metody lokalnej. Wywołanie RPC czeka na odpowiedź serwera i zwraca odpowiedź lub zgłasza wyjątek. Możemy wywołać metodę i zobaczyć odpowiedź w ten sposób:
feature = stub.GetFeature(point)
print(feature)
Możesz sprawdzić pola obiektu Feature i wyświetlić wynik żądania:
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. Wypróbuj
Uruchom serwer:
python route_guide_server.py
W innym terminalu ponownie aktywuj środowisko wirtualne, a potem uruchom klienta:
python route_guide_client.py
Zobaczysz dane wyjściowe podobne do tych (sygnatury czasowe zostały pominięte dla przejrzystości):
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. Co dalej?
- Dowiedz się, jak działa gRPC, z artykułów Wprowadzenie do gRPC i Podstawowe pojęcia.
- Zapoznaj się z samouczkiem dotyczącym podstaw.
- Zapoznaj się z dokumentacją interfejsu API w Pythonie