Kubernetes DNS Latency: Khi ndots:5 kéo latency lên gấp 5 lần

Đúng là dùng kubernetes lâu mới gặp các issue hay ho, hôm nọ xử lý sự cố ở hệ thống Kubernetes tải cao, tôi gặp một issue khá khó chịu: latency của một service khi gọi API bên ngoài tăng đột biến, dù CPU, memory, băng thông mạng đều bình thường. Điều đầu tiên gây chú ý là CoreDNS tăng CPU bất thường và số lượng DNS query trong VPC nhảy rất cao…

Sau hồi vận lộn cũng tìm ra root cause. Vấn đề không nằm ở code. Không nằm ở network. Không nằm ở đối tác cung cấp API. Nó nằm trong file /etc/resolv.conf của mọi Pod trong Kubernetes.

Chính xác là ndots:5, có nhiều điểm hay ho nên viết bài chia sẻ nếu bạn nào gặp có thể thêm một tài liệu tham khảo thử nhé.

4f3e8dd5-5da6-48b4-b834-f0c1b08164e1

Bài toán

Tôi không tiện show y nguyên architecture cái này mọi người cũng đều hiểu nên lấy ví dụ tương đối giống nhé, chắc chắn vẫn đảm bảo chúng ta tập trung vào đúng mục đích là được.

Một microservice Payment-Service viết bằng Go, chạy trên EKS, xử lý khoảng 5000 RPS. Mỗi request cần gọi đến API của một nhà cung cấp thanh toán, ví dụ:

api.payment-provider.com

Khi traffic tăng, latency P99 từ mức khoảng 50ms nhảy lên 500ms, có lúc lên 1-2 giây. CoreDNS bắt đầu gần chạm CPU limit.

  • Đối tác xác nhận API phản hồi dưới 50ms.
  • Node không nghẽn.
  • SNAT không hết port.
  • Không packet drop.

Nhưng hệ thống DNS thì khác.

DNS query tăng bất thường: dấu hiệu của một vấn đề lớn hơn

Khi kiểm tra bằng tcpdump, thay vì thấy 1 query đến domain thật, tôi lại thấy một chuỗi truy vấn:

  1. api.payment-provider.com.default.svc.cluster.local
  2. api.payment-provider.com.svc.cluster.local
  3. api.payment-provider.com.cluster.local
  4. api.payment-provider.com.<provider internal domain>
  5. api.payment-provider.com

Bốn truy vấn đầu đều trả về NXDOMAIN.

Điều này có nghĩa là để resolve một domain bên ngoài, resolver phải thử 4 domain rác trước đó.

Nguyên nhân là vì cấu hình mặc định của Kubernetes:

search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Domain api.payment-provider.com chỉ có 2 dấu chấm. 2 nhỏ hơn 5 -> resolver coi đây là domain chưa đầy đủ, và thử tất cả search domain trước khi gọi ra internet.

Với 5000 RPS:

5000 requests x 5 DNS queries = 25.000 DNS queries/giây

CoreDNS bị đẩy lên 5 lần tải. Latency tăng theo cấp số nhân.

Tại sao vấn đề này nghiêm trọng?

Resolver không chỉ làm thêm việc mà:

  • mỗi NXDOMAIN tốn round-trip network
  • CoreDNS phải xử lý nhiều hơn
  • thời gian chờ DNS tăng
  • request ứng dụng chậm theo
  • P99 latency bị kéo dài
  • CPU CoreDNS tăng -> queue tăng -> latency càng tăng

Đây là điển hình của DNS overload, không phải DDoS, nhưng hiệu ứng tương tự.

Các giải pháp tối ưu

Cách 1: Dùng FQDN tuyệt đối với dấu chấm ở cuối (tối ưu nhất)

Chỉ cần đổi:

api.payment-provider.com

thành:

api.payment-provider.com.

Dấu chấm giúp resolver biết đây là domain đầy đủ, bỏ qua search domain, truy vấn thẳng ra internet.

Ưu điểm:

  • Không phụ thuộc hạ tầng
  • Hiệu quả ngay lập tức
  • Không thêm chi phí

Nhược điểm:

  • Phải sửa code hoặc config
  • Dễ bị team dev bỏ sót

Cách 2: Giảm ndots trong Pod Spec

Nếu không muốn sửa code:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
spec:
  template:
    spec:
      dnsConfig:
        options:
          - name: ndots
            value: "2"

Khi ndots=2, domain có nhiều hơn 2 dấu chấm sẽ được coi là FQDN.

Cảnh báo quan trọng: Giảm ndots có thể ảnh hưởng việc resolve short-name của service nội bộ.

Ví dụ gọi user-db thay vì user-db.default.svc.cluster.local thì cần đảm bảo các service nội bộ dùng full DNS.

Cách 3: Triển khai NodeLocal DNSCache (tối ưu hạ tầng)

NodeLocal DNSCache đặt một cache DNS ở từng node thì giảm:

  • hop mạng đến CoreDNS
  • CPU load trên CoreDNS tập trung
  • latency cho NXDOMAIN
  • tỉ lệ timeout DNS

Trong traffic cao, đây là giải pháp kiến trúc ổn định nhất.

Bài học quan trọng về vận hành Kubernetes

1. Kubernetes không giấu được Linux

Resolver hoạt động dựa trên glibc, ndots, search domain. Debug DNS phải hiểu OS, không chỉ Kubernetes.

2. Latency không chỉ nằm trong code

DNS, handshake, TLS, retry, timeout đều ngốn ngân sách latency.

3. Quan sát DNS phải là bắt buộc

Cần theo dõi:

  • số lượng DNS query
  • tỉ lệ NXDOMAIN
  • latency của CoreDNS
  • CPU của CoreDNS pods

Nếu NXDOMAIN tăng, đây là dấu hiệu domain bị resolve sai hoặc cấu hình DNS chưa tối ưu.

Kết luận

Tôi có share docs này cho mấy em trong team để mấy em hiểu sau có gặp nhưng có vẻ hơi khó hiểu nếu yếu networking. Nên tôi nghĩ cứ share lên đây rồi sẽ có bạn gặp và thấy cần thiết.

Nói chung là một thay đổi nhỏ trong cách resolve domain có thể tạo ra khác biệt lớn về latency. Cấu hình ndots:5 mặc định của Kubernetes phù hợp cho service nội bộ, nhưng không phù hợp với các service gọi ra ngoài có tần suất cao.

Cách tiếp cận tốt nhất:

  • dùng FQDN tuyệt đối khi gọi external API
  • xem xét hạ ndots trong các deployment cần hiệu năng cao
  • triển khai NodeLocal DNSCache cho cluster lớn

Đây là vấn đề rất dễ bị bỏ sót, nhưng chỉ cần để ý đúng chỗ thì latency có thể giảm 20 đến 50ms ở P99, và load DNS giảm hàng chục lần, cái này phải kiểm chứng thực tế lâu dài nhưng tôi thấy rất khả thi.

Thông tin nổi bật

Sự kiện phát trực tiếp​

Event Thumbnail

Báo cáo quan trọng

Article Thumbnail
Article Thumbnail
Chia sẻ bài viết:
Theo dõi
Thông báo của
1 Bình luận
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận

Tiêu điểm chuyên gia