Vấn đề loadbalancing với gRPC communication trong Kubernetes PART 2
Giới thiệu
Ở phần 1, mình đã giới thiệu về những hạn chế của Kubernetes service đối với gRPC load-balancing. Trong phần này, mình sẽ tập trung vào các giải pháp khắc phục tình trạng này
Repository: https://github.com/phamsyhung2110/test-grpc-lb
Solution 1: Sử dụng client side loadbalancing
Client-side load balancing là phương pháp mà client tự quản lý việc phân phối request đến các instance backend. Thay vì dựa vào một load balancer bên ngoài, client sẽ sử dụng danh sách các endpoint để tự chọn nơi gửi request.
Cách hoạt động
- Service Discovery: Client cần biết danh sách các endpoint backend. Điều này thường được thực hiện thông qua DNS hoặc API của Kubernetes.
- Chọn Endpoint: Client sử dụng thuật toán như Round Robin, Least Connections, hoặc Random để chọn endpoint từ danh sách.
- Gửi Request: Client gửi request trực tiếp đến pod backend.
Điều kiện cần
- Headless Service: Cần sử dụng Kubernetes headless service để DNS trả về danh sách các IP của các pod backend thay vì ClusterIP.
- Thư viện hỗ trợ: Client-side load balancing yêu cầu các thư viện hoặc framework có hỗ trợ, ví dụ: gRPC balancer trong các SDK chính thức của gRPC.
Ví dụ triển khai
1. Thay đổi trên source code của service A (HTTP proxy)
Tạo file service-A-lb.js trong folder grpc-app/
Sử dụng DNS cho Service Discovery
const grpcServiceAddress = process.env.GRPC_SERVICE_ADDRESS || 'dns:///service-b-grpc.default.svc.cluster.local:50051';
2. Add Load-balancing logic
- Mục đích: Cho phép gRPC client tự động phát hiện các pod của Service B trong môi trường Kubernetes.
- Chi tiết:
- dns:///: Đây là prefix bắt buộc khi sử dụng DNS để định tuyến trong gRPC.
- service-b-grpc.default.svc.cluster.local: Đây là DNS name đầy đủ của Service B trong Kubernetes.
- service-b: Tên của Service Kubernetes.
- default: Namespace chứa Service. Thay đổi namespace nếu cần.
- svc.cluster.local: Domain nội bộ của Kubernetes.
const client = new echoService(grpcServiceAddress, grpc.credentials.createInsecure(), {
'grpc.service_config': JSON.stringify({
loadBalancingConfig: [{ round_robin: {} }]
})
});
- Mục đích: Kích hoạt Client-Side Load Balancing trên gRPC client.
- Chi tiết:
grpc.service_config
: Cung cấp cấu hình cho thuật toán load balancing.loadBalancingConfig: [{ round_robin: {} }]:
Sử dụng thuật toán Round Robin, phân phối đều các request đến các backend pod của Service B.
Như vậy phần sửa source code đã xong, bạn tự build và deploy lại service A nhé
cd grpc-app/
docker build . -f dockerfile -t <repo>/testgrpc:v1
docker push <repo>/testgrpc:v1
3. Đổi k8s service của service B thành Headless service
apiVersion: v1
kind: Service
metadata:
name: service-b-grpc
spec:
clusterIP: None
selector:
app: service-b-grpc
ports:
- protocol: TCP
port: 50051
targetPort: 50051
Apply manifest: kubectl apply -f deploy/grpc-deploy.yaml -n grpc
Test: Gửi request tới service A bằng K6 (Chú ý đổi )
kubectl port-forward svc/service-a-grpc 5000:5000 -n grpc
cd k6/
k6 run grpc-loadtest.js
Kết quả: Như vậy requests đã được load-balance đến các pods của service B
Solution 2: Sử dụng Service mesh
Cách này không yêu cầu sửa source code, tuy nhiên cần sử dụng service mesh tool. Ở đây mình sẽ sử dụng Istio.
Note: Vì đây không phải là hướng dẫn cài đặt Istio, bạn cần đã biết các hoặc đã cài Istio trong cluster
Enabled sidecar injection
kubectl label namespace dev-hung istio-injection=enabled
Restart service
kubectl delete -f deploy/grpc-deploy.yaml && kubectl apply -f deploy/grpc-deploy.yaml
Các service đã được chạy với Istio sidecar Đơn giản vậy thôi, giờ ta chạy lại test như đã hướng dẫn ở phần trên. Kết quả trong quá trình chạy test
Một chút lưu ý, theo như tài liệu của Istio, cơ chế load balancing mặc định của Envoy proxy là Least Connection. Vì vậy khi sử dụng Istio, bạn có thể tùy chỉnh cấu cơ chế load balancing.
By default, the Envoy proxies distribute traffic across each service’s load balancing pool using a least requests model, where each request is routed to the host with fewer active requests from a random selection of two hosts from the pool; in this way the most heavily loaded host will not receive requests until it is no more loaded than any other host.
Đọc thêm tại: https://istio.io/latest/docs/concepts/traffic-management/#introducing-istio-traffic-management
Kết luận
Như vậy mình đã trình bày về lí thuyết cũng như cách triển khai các giải pháp khắc phục vấn đề gRPC load-balancing trong Kubernetes. Hy vọng sẽ giúp mọi người có thêm kiến thức về Networking cũng như triển khai gRPC trong Kubernetes.
All rights reserved