1. Giới thiệu
Trong lớp học lập trình này, bạn sẽ dùng gRPC-Python để tạo một ứng dụng khách và máy chủ tạo thành nền tảng của một ứng dụng lập bản đồ tuyến đường được viết bằng Python.
Khi kết thúc hướng dẫn này, bạn sẽ có một ứng dụng kết nối với một máy chủ từ xa bằng gRPC để lấy tên hoặc địa chỉ bưu chính của nội dung nằm tại một toạ độ cụ thể trên bản đồ. Một ứng dụng hoàn chỉnh có thể sử dụng thiết kế máy chủ-máy khách này để liệt kê hoặc tóm tắt các địa điểm yêu thích dọc theo một tuyến đường.
Dịch vụ này được xác định trong một tệp Protocol Buffers. Tệp này sẽ được dùng để tạo mã chuẩn cho ứng dụng và máy chủ để chúng có thể giao tiếp với nhau, giúp bạn tiết kiệm thời gian và công sức khi triển khai chức năng đó.
Mã được tạo này không chỉ xử lý sự phức tạp của việc giao tiếp giữa máy chủ và ứng dụng mà còn xử lý quá trình chuyển đổi dữ liệu thành chuỗi và chuyển đổi chuỗi thành dữ liệu.
Kiến thức bạn sẽ học được
- Cách sử dụng Protocol Buffers để xác định một API dịch vụ.
- Cách tạo máy khách và máy chủ dựa trên gRPC từ một định nghĩa Protocol Buffers bằng cách sử dụng tính năng tạo mã tự động.
- Hiểu rõ về giao tiếp máy khách-máy chủ bằng gRPC.
Lớp học lập trình này dành cho những nhà phát triển Python mới làm quen với gRPC hoặc muốn tìm hiểu lại về gRPC, hoặc bất kỳ ai khác quan tâm đến việc xây dựng các hệ thống phân tán. Bạn không cần có kinh nghiệm sử dụng gRPC.
2. Trước khi bắt đầu
Bạn cần có
- Python 3.9 trở lên. Bạn nên dùng Python 3.13. Để biết hướng dẫn cài đặt theo từng nền tảng, hãy xem phần Thiết lập và sử dụng Python. Ngoài ra, hãy cài đặt Python không phải là hệ thống bằng các công cụ như uv hoặc pyenv.
- pip để cài đặt các gói Python.
- venv để tạo môi trường ảo Python.
Các gói ensurepip
và venv
là một phần của Thư viện chuẩn Python và thường có sẵn theo mặc định.
Tuy nhiên, một số bản phân phối dựa trên Debian (bao gồm cả Ubuntu) chọn loại trừ các bản phân phối này khi phân phối lại Python. Để cài đặt các gói, hãy chạy:
sudo apt install python3-pip python3-venv
Lấy mã
Để đơn giản hoá quá trình học tập, lớp học lập trình này cung cấp một cấu trúc mã nguồn được tạo sẵn để giúp bạn bắt đầu. Các bước sau đây sẽ hướng dẫn bạn hoàn tất ứng dụng, bao gồm cả việc tạo mã gRPC bằng trình bổ trợ trình biên dịch grpc_tools.protoc
Protocol Buffer.
grpc-codelabs
Mã nguồn giàn giáo cho lớp học lập trình này có trong thư mục codelabs/grpc-python-getting-started/start_here. Nếu bạn không muốn tự triển khai mã, thì mã nguồn hoàn chỉnh có trong thư mục completed
.
Trước tiên, hãy tạo thư mục làm việc cho lớp học lập trình rồi chuyển đến thư mục đó:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Tải và giải nén lớp học lập trình:
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
Ngoài ra, bạn có thể tải tệp .zip chỉ chứa thư mục codelab xuống rồi giải nén theo cách thủ công.
3. Xác định dịch vụ
Bước đầu tiên là xác định dịch vụ gRPC của ứng dụng, phương thức RPC và các loại thông báo yêu cầu và phản hồi bằng ngôn ngữ định nghĩa giao diện Protocol Buffers. Dịch vụ của bạn sẽ cung cấp:
- Một phương thức RPC có tên là
GetFeature
mà máy chủ triển khai và máy khách gọi. - Các loại thông báo
Point
vàFeature
là các cấu trúc dữ liệu được trao đổi giữa ứng dụng và máy chủ khi sử dụng phương thứcGetFeature
. Ứng dụng cung cấp toạ độ trên bản đồ dưới dạngPoint
trong yêu cầuGetFeature
gửi đến máy chủ, còn máy chủ sẽ trả lời bằng mộtFeature
tương ứng mô tả mọi thứ nằm ở toạ độ đó.
Phương thức RPC này và các loại thông báo của phương thức này sẽ được xác định trong tệp protos/route_guide.proto
của mã nguồn được cung cấp.
Vùng đệm giao thức thường được gọi là protobuf. Để biết thêm thông tin về thuật ngữ gRPC, hãy xem phần Các khái niệm, cấu trúc và vòng đời cốt lõi của gRPC.
Loại thông báo
Trong tệp protos/route_guide.proto
của mã nguồn, trước tiên hãy xác định kiểu thông báo Point
. Point
biểu thị một cặp toạ độ vĩ độ và kinh độ trên bản đồ. Trong lớp học lập trình này, hãy sử dụng số nguyên cho toạ độ:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Các số 1
và 2
là số nhận dạng duy nhất cho từng trường trong cấu trúc message
.
Tiếp theo, hãy xác định loại thông báo Feature
. Feature
sử dụng trường string
cho tên hoặc địa chỉ bưu chính của một thứ gì đó tại một vị trí do Point
chỉ định:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Phương thức dịch vụ
Tệp route_guide.proto
có cấu trúc service
tên là RouteGuide
, xác định một hoặc nhiều phương thức do dịch vụ của ứng dụng cung cấp.
Thêm phương thức rpc
GetFeature
vào bên trong định nghĩa RouteGuide
. Như đã giải thích trước đó, phương thức này sẽ tra cứu tên hoặc địa chỉ của một vị trí từ một tập hợp toạ độ nhất định, vì vậy, hãy để GetFeature
trả về một Feature
cho một Point
nhất định:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Đây là một phương thức RPC đơn phương: một RPC đơn giản, trong đó ứng dụng gửi một yêu cầu đến máy chủ và đợi phản hồi quay lại, giống như một lệnh gọi hàm cục bộ.
4. Tạo mã máy khách và máy chủ
Tiếp theo, hãy tạo mã gRPC chung cho cả máy khách và máy chủ từ tệp .proto
bằng trình biên dịch vùng đệm giao thức.
Đối với việc tạo mã gRPC Python, chúng tôi đã tạo grpcio-tools. Thư mục này bao gồm:
- Trình biên dịch protoc thông thường tạo mã Python từ các định nghĩa
message
. - Trình bổ trợ protobuf gRPC tạo mã Python (mã ứng dụng máy khách và máy chủ) từ các định nghĩa
service
.
Chúng ta sẽ cài đặt gói Python grpcio-tools
bằng pip. Hãy tạo một môi trường ảo Python (venv) mới để tách biệt các phần phụ thuộc của dự án với các gói hệ thống:
python3 -m venv --upgrade-deps .venv
Cách kích hoạt môi trường ảo trong trình bao bash/zsh:
source .venv/bin/activate
Đối với Windows và các shell không theo chuẩn, hãy xem bảng tại https://docs.python.org/3/library/venv.html#how-venvs-work.
Tiếp theo, hãy cài đặt grpcio-tools (thao tác này cũng cài đặt gói grpcio):
pip install grpcio-tools
Sử dụng lệnh sau để tạo mã khởi động Python:
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
Thao tác này sẽ tạo các tệp sau cho những giao diện mà chúng ta đã xác định trong route_guide.proto
:
route_guide_pb2.py
chứa mã tạo động các lớp được tạo từ các định nghĩamessage
.route_guide_pb2.pyi
là một "tệp stub" hoặc "tệp gợi ý loại" được tạo từ các định nghĩamessage
. Nó chỉ chứa các chữ ký không có quá trình triển khai. Các IDE có thể sử dụng tệp stub để cung cấp tính năng tự động hoàn thành và phát hiện lỗi hiệu quả hơn.route_guide_pb2_grpc.py
được tạo từ các định nghĩaservice
và chứa các lớp cũng như hàm dành riêng cho gRPC.
Mã dành riêng cho gRPC chứa:
RouteGuideStub
, có thể được máy khách gRPC sử dụng để gọi các RPC RouteGuide.RouteGuideServicer
, xác định giao diện cho các hoạt động triển khai dịch vụRouteGuide
.- Hàm
add_RouteGuideServicer_to_server
dùng để đăng kýRouteGuideServicer
với máy chủ gRPC.
5. Tạo dịch vụ
Trước tiên, hãy xem cách bạn tạo một máy chủ RouteGuide
. Việc tạo và chạy một máy chủ RouteGuide
được chia thành 2 mục công việc:
- Triển khai giao diện trình chạy dịch vụ được tạo từ định nghĩa dịch vụ của chúng tôi bằng các hàm thực hiện "công việc" thực tế của dịch vụ.
- Chạy một máy chủ gRPC tại một cổng cụ thể để lắng nghe các yêu cầu từ ứng dụng và truyền phản hồi.
Bạn có thể tìm thấy máy chủ RouteGuide
ban đầu trong start_here/route_guide_server.py
.
Triển khai RouteGuide
route_guide_server.py
có một lớp RouteGuideServicer
phân lớp lớp route_guide_pb2_grpc.RouteGuideServicer
đã tạo:
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer
triển khai tất cả các phương thức dịch vụ RouteGuide
.
Hãy xem xét chi tiết một cách triển khai RPC đơn giản. Phương thức GetFeature
nhận Point
từ ứng dụng và trả về thông tin về đối tượng tương ứng từ cơ sở dữ liệu của ứng dụng trong 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
Phương thức này được truyền một yêu cầu route_guide_pb2.Point
cho RPC và một đối tượng grpc.ServicerContext
cung cấp thông tin cụ thể về RPC, chẳng hạn như giới hạn thời gian chờ. Phương thức này trả về một phản hồi route_guide_pb2.Feature
.
Khởi động máy chủ
Sau khi bạn triển khai tất cả các phương thức RouteGuide
, bước tiếp theo là khởi động một máy chủ gRPC để máy khách có thể thực sự sử dụng dịch vụ của bạn:
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()
Phương thức start()
của máy chủ không chặn. Một luồng mới sẽ được khởi tạo để xử lý các yêu cầu. Luồng gọi server.start()
thường không có việc gì khác để làm trong thời gian chờ đợi. Trong trường hợp này, bạn có thể gọi server.wait_for_termination()
để chặn luồng gọi một cách rõ ràng cho đến khi máy chủ kết thúc.
6. Tạo ứng dụng
Trong phần này, chúng ta sẽ xem xét việc tạo một ứng dụng cho dịch vụ RouteGuide
. Bạn có thể xem mã ứng dụng ban đầu trong start_here/route_guide_client.py
.
Tạo một stub
Để gọi các phương thức dịch vụ, trước tiên, chúng ta cần tạo một stub.
Chúng ta tạo thực thể cho lớp RouteGuideStub
của mô-đun route_guide_pb2_grpc
, được tạo từ .proto
bên trong tệp route_guide_client.py
.
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Gọi các phương thức dịch vụ
Đối với các phương thức RPC trả về một phản hồi duy nhất (được gọi là phương thức response-unary), gRPC Python hỗ trợ cả ngữ nghĩa luồng điều khiển đồng bộ (chặn) và không đồng bộ (không chặn).
RPC đơn giản
Trước tiên, hãy xác định một Point
để gọi dịch vụ. Thao tác này đơn giản như việc khởi tạo một đối tượng từ gói route_guide_pb2
với một số thuộc tính:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Lệnh gọi đồng bộ đến RPC đơn giản GetFeature
gần như đơn giản như gọi một phương thức cục bộ. Lệnh gọi RPC sẽ đợi máy chủ phản hồi và sẽ trả về một phản hồi hoặc đưa ra một ngoại lệ. Chúng ta có thể gọi phương thức này và xem phản hồi như sau:
feature = stub.GetFeature(point)
print(feature)
Bạn có thể kiểm tra các trường của đối tượng Feature và xuất kết quả của yêu cầu:
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. Dùng thử
Chạy máy chủ:
python route_guide_server.py
Từ một thiết bị đầu cuối khác, hãy kích hoạt lại môi trường ảo, sau đó chạy ứng dụng:
python route_guide_client.py
Bạn sẽ thấy kết quả như sau, trong đó dấu thời gian đã bị bỏ qua để đảm bảo sự rõ ràng:
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. Bước tiếp theo
- Tìm hiểu cách gRPC hoạt động trong phần Giới thiệu về gRPC và Các khái niệm cốt lõi
- Xem Hướng dẫn cơ bản
- Khám phá tài liệu tham khảo về Python API