Ngồi đẻ ra một cái thuật toán chạy nhanh như gió mới chỉ đi được nửa quãng đường. Phép thử lửa thực sự (true test) của một Kỹ sư Principal nằm ở chỗ: làm sao vác nguyên một cái Hệ thống Định tuyến có trạng thái (stateful Routing Engine) to tổ chảng đắp lên Cloud mà không làm rớt mạng (downtime) lấy một giây nào mỗi lúc có đợt cập nhật bản đồ hay sập cơ sở hạ tầng.
Answer-first: Đừng hòng đối xử với thằng Graphhopper giống như mấy con web server không trạng thái (stateless) bèo bọt. Cái màn cập nhật dữ liệu OpenStreetMap vắt kiệt sức máy tận 30 phút. Bạn BẮT BUỘC phải xẻ đôi (decouple) cái tiến trình build bản đồ ra bằng Kubernetes Jobs, tiêm cái cục cache 50GB tính sẵn vào qua ngả initContainers, và gạt công tắc chuyển traffic ngay chớp mắt xài chiêu Triển khai Xanh-Đỏ (Blue-Green Deployments).
1. Chiến Lược Triển Khai Không Gián Đoạn (Zero-Downtime Deployment)
Chặt Đứt Khâu Build Ra Khỏi Server
Nếu bạn dại dột vác cái script nặn đồ thị (graph generation script) vào chạy chung chuồng với mấy con Pod đang hầu khách (live serving Pods), bạn nắm chắc phần thắng 30 phút sập mạng (downtime) mỗi bận update bản đồ.
Thuốc Giải: Xách một cái Kubernetes Job (hoặc đường ống CI - CI pipeline) ra để lôi cổ cái file .pbf mới tinh về và hì hục nhào nặn cái graph-cache hoàn toàn cách ly (offline). Đẻ xong thì xách nguyên cái folder cache 50GB thành phẩm ném lên vứt ở một cái sọt AWS S3 bucket.
Trò initContainers & Triển Khai Xanh-Đỏ (Blue-Green Deployments)
Đụng tới màn ném version mới lên, cấm tiệt trò xài chiêu Cập nhật Cuốn chiếu (Rolling Updates) mặc định của Kubernetes. Cái trò Rolling Update sẽ đẻ ra thảm họa “Tâm thần Phân liệt” (Split-Brain) nơi 50% số pod nhà bạn nhai bản đồ cũ, 50% còn lại bú bản đồ mới, và kết cục là đập nát bét (completely destroying) cái Tỷ lệ Trúng (Hit Rate) của cái Semantic Cache Redis.
Thuốc Giải: Vác thằng Argo Rollouts ra để chơi bài Xanh-Đỏ (Blue-Green). Lúc mấy con pod phe “Xanh” khởi động, tụi nó sẽ xài một cái initContainer của Kubernetes để chạy AWS CLI móc rước cục cache 50GB từ S3 về đổ vô một cái volume rỗng tuếch (emptyDir). Cái container Graphhopper chính điện (main) chỉ chịu mở mắt một khi rinh xong toàn bộ dữ liệu. Đợi tới lúc rà máy (Readiness Probes) xác nhận cái đồ thị đã ngoan ngoãn nằm im trong RAM, Argo Rollouts ngay chớp mắt hất 100% traffic lật ngửa cờ sang phe Xanh (Green pods).
Trạm gác Kubernetes đã khóa đuôi khép lại hệ thống định tuyến phân tán của chúng ta. Để vắt kiệt hiệu năng (optimal performance) mà không phí phạm cơ sở hạ tầng, hãy nhớ đảm bảo rằng bạn đã cài cắm xong bộ semantic caching như lột trần ở Phần 6: Gom Nhóm Vị Trí Với Uber H3 & Caching Ngữ Nghĩa (Semantic Caching) Bằng Redis và gõ bùa tối ưu network kernel ở Phần 7: Kiểm Tra Chịu Tải & Tối Ưu Hiệu Năng Cho Production.
2. Sinh Tồn Cùng Kubernetes Đa Vùng (Multi-Region) & Độ Trễ Xuyên Lục Địa (Global Latency)
Lệnh code chạy rẹt rẹt tính bằng mili-giây, nhưng ánh sáng thì éo có nương tay với ai đâu. Một gã user ngồi rung đùi ở London mà cắm request chọc sang tận cái cụm (cluster) ở Singapore thì xác định ngậm hành chịu trận (suffer) cái độ trễ khốn nạn lên tới 200ms riêng mỗi trò bắt tay TCP (TCP handshake) thôi, chưa thèm nói tới lúc API nó rờ được vô cái request.
Geo DNS & Màn Khám Sức Khỏe Ngầm (Active Health Checks)
Đam mê độ trễ thấp ở mức toàn cầu (global low latency), hãy chịu khó rải rác đẻ bầy cụm Kubernetes ra nhiều vùng lãnh thổ (ví dụ: Bờ Đông Mỹ - US-East, Tây Âu - EU-West, Nam Á - AP-South). Thuốc Giải: Bợ một con Geo DNS xài tạm (tựa như Route53 hay Cloudflare). Đám DNS cầm quyền (authoritative) này sẽ rà vị trí người dùng (inspect the user’s location) rồi bẻ lái cái domain phi thẳng về cái IP của cụm gần nhất. Chí mạng ở chỗ, bạn bắt buộc phải lên nòng bộ Khám sức khỏe Lớp 7 (L7 Health Checks) với cái TTL siêu mỏng (tầm 30s). Cụm Singapore mà lỡ có cúp điện sập nguồn, thằng trùm DNS sẽ tự động thủ tiêu cái IP đó và lùa đám khách Châu Á rẽ ngoặt sang Tokyo chơi.
Hỏi Nhanh Đáp Gọn (FAQ): Cơn Ác Mộng Của SRE Senior
SIGTERM vô mặt. Nếu con API Golang nhà bạn thấy cái cờ này rồi cúp đuôi chạy tắt ngúm ngay tắp lự (exits immediately), mấy cái request định tuyến đang bay lơ lửng trên mạng sẽ chết tươi tức tưởi. Khốn nỗi con kube-proxy nó lại cần vài giây ngâm giấm mới ráng lết đi update cái iptables, dẫn tới mấy cái traffic mới đẻ vẫn mù quáng đâm đầu vô cái Pod đã mồ yên mả đẹp. Bạn BẮT BUỘC phải xài cái móc cài preStop (ví dụ: sleep 10) dán vô cái file YAML rồi vác trò http.Server.Shutdown() trong Golang ra để rút ống (drain connections) một cách nhẹ nhàng tình cảm (gracefully).-Xmx 16GB chỉ bóp được đúng cái đống Java Heap. Con quỷ JVM nó còn thèm khát đi lấn chiếm (allocates) thêm đám mảng nhớ “Ngoài Luồng” (Off-Heap) để cúng cho Thread Stacks (Ngăn Xếp Luồng), Metaspace (Không Gian Siêu Dữ Liệu), và ba cái đám NIO buffers nữa. Mức độ ngốn RAM mập lên tới 16.5GB, và cái cgroup của kernel Linux dứt khoát giáng chùy thủ tiêu (kills) con Pod ngay tắp lự không để lại lấy một dòng Java logs vớt vát nào. Bạn BẮT BUỘC phải xài cái bùa -XX:MaxRAMPercentage=75.0 để cắt dọn ra 25% chừa lại thở (safety buffer) cho thằng OS./etc/resolv.conf. Thằng Kubernetes xài mặc định cái quái thai ndots: 5. Luật này bắt ép cái bộ giải mã DNS (DNS resolver) phải nhồi nhét cắm đuôi (append) tới tận 5 cái tên miền nội bộ (internal domain suffixes) đính vô chóp của đủ mọi cái external request (truy vấn ngoại mạng), dấy lên một cơn cuồng phong truy vấn CoreDNS điên loạn. Bạn BẮT BUỘC phải xài Tên Miền Chuẩn Xác (FQDNs - add a trailing dot vào cái chóp của cục URL) hoặc cạo đầu hạ cái ndots xuống mốc 2 trong cái ruột của file cấu hình Pod (Pod spec).