Skip to content

Cấu Hình, Giám Sát & Tối Ưu Cloud NAT

Tại Sao Cấu Hình Timeout Quan Trọng

Timeout trong Cloud NAT không chỉ là thông số "thử chỉnh xem sao". Mỗi giá trị timeout kiểm soát bao lâu Cloud NAT giữ một connection tracking entry sau khi connection đó kết thúc hoặc im lặng. Giá trị quá cao → port bị giữ lâu → pool cạn kiệt. Giá trị quá thấp → connection tracking entry bị xóa sớm → valid connections bị drop.

Hiểu từng loại timeout từ cơ chế giúp bạn chỉnh đúng mà không gây side effects.


Connection Timeout Mechanics

TCP Timeouts: Ba Trạng Thái Khác Nhau

Cloud NAT phân biệt ba trạng thái của TCP connection, mỗi cái có timeout riêng:

1. TCP Established Idle Timeout (tcp-established-idle-timeout)

Connection đang ở trạng thái ESTABLISHED nhưng không có packet nào trong thời gian này → Cloud NAT xóa tracking entry.

  • Giá trị mặc định: 1.200 giây (20 phút)
  • Phạm vi cấu hình: 300 giây đến 9.000 giây
  • Tại sao dài: TCP connections có thể "ngủ" hợp lệ (idle database connection, long-polling HTTP connections, gRPC bidirectional streams). Xóa quá sớm gây drop connections đang active.

2. TCP Transitory Idle Timeout (tcp-transitory-idle-timeout)

Connection trong trạng thái half-open (SYN gửi nhưng chưa nhận SYN-ACK) hoặc kết nối vừa bắt đầu nhưng chưa complete handshake.

  • Giá trị mặc định: 30 giây
  • Phạm vi cấu hình: 10 giây đến 300 giây
  • Tại sao ngắn: Nếu TCP handshake không hoàn thành sau 30 giây, nhiều khả năng destination unreachable hoặc bị block. Không cần giữ tracking entry lâu.

3. TCP TIME_WAIT Timeout (tcp-time-wait-timeout)

Connection đã fully closed (FIN/ACK exchange hoàn thành) nhưng Cloud NAT chưa cho phép tái sử dụng cùng 5-tuple.

  • Giá trị mặc định: 120 giây (sẽ giảm xuống 30 giây từ tháng 9/2026 theo Google)
  • Phạm vi cấu hình: 5 giây đến 120 giây
  • Đây là giá trị quan trọng nhất để tune khi gặp port exhaustion từ short-lived connections

Tại Sao TCP TIME_WAIT Tồn Tại

TIME_WAIT là cơ chế bảo vệ từ TCP specification (RFC 793). Mục đích:

  1. Ngăn "ghost packets": Packet cũ từ connection đã đóng có thể vẫn đang trên đường. Nếu cùng 5-tuple được reuse ngay lập tức, packet cũ có thể nhầm vào connection mới, gây corruption dữ liệu.

  2. Đảm bảo phía kia nhận FIN/ACK: TCP TIME_WAIT ở phía active close (bên gửi FIN trước) đảm bảo rằng nếu final ACK bị mất và phía kia retransmit FIN, bên này vẫn có thể respond.

Trong kernel TCP stack, TIME_WAIT thường là 2× MSL (Maximum Segment Lifetime) = 2 × 60s = 120s. Cloud NAT default đồng bộ với giá trị này.

Khi nào có thể giảm TIME_WAIT:

  • Application của bạn không sensitive với ghost packets (nhiều UDP-based hoặc idempotent HTTP APIs)
  • Destination servers hỗ trợ TCP RST để clear half-open connections
  • Bạn muốn aggressively reuse ports cho high-throughput scenarios
bash
# Giảm TCP TIME_WAIT timeout:
gcloud compute routers nats update NAT_GATEWAY_NAME \
  --router=ROUTER_NAME \
  --region=REGION \
  --tcp-time-wait-timeout=30s   # safe minimum cho hầu hết workloads
  # hoặc --tcp-time-wait-timeout=5s cho aggressive reuse

UDP và ICMP Timeouts

UDP (udp-idle-timeout)

UDP không có connection state (connectionless protocol), nhưng Cloud NAT vẫn cần tracking để route return traffic. Tracking dựa trên "luồng UDP" — cùng source/destination 4-tuple.

  • Mặc định: 30 giây sau khi không có UDP packet nào trong luồng
  • Phạm vi: 30 giây đến 300 giây
  • Với DNS queries (short-lived UDP): 30 giây là quá đủ
  • Với VoIP hoặc game UDP streams (continuous but with gaps): có thể cần tăng lên 60–120 giây

ICMP (icmp-idle-timeout)

ICMP echo (ping) được track theo cặp request/response.

  • Mặc định: 30 giây
  • Phạm vi: 30 giây đến 300 giây
  • Ít khi cần tune — ICMP thường không chiếm nhiều ports

Bảng Tổng Hợp Timeouts

LoạiMặc địnhMinMaxKhi Nào Tune
TCP Established Idle1.200s (20m)300s9.000sNếu có nhiều long-lived idle TCP connections
TCP Transitory30s10s300sHiếm khi cần tune
TCP TIME_WAIT120s5s120sKhi gặp exhaustion từ short-lived connections
UDP30s30s300sNếu có UDP streams với gaps dài
ICMP30s30s300sKhông cần tune trong hầu hết cases

NAT Rules: Phân Tách Traffic Theo Destination

Khi Nào Cần NAT Rules

Mặc định, tất cả traffic qua Cloud NAT đều dùng chung một pool NAT IPs. Điều này tạo ra risk: traffic volume lớn từ một loại workload có thể cạn kiệt port và ảnh hưởng các workloads quan trọng khác.

NAT Rules cho phép route traffic đến các destinations khác nhau qua các NAT IP pools khác nhau:

Không có NAT Rules:
  Traffic đến payment.example.com  ─┐
  Traffic đến cdn.example.com      ─┤─→ Shared NAT IP pool
  Traffic đến logs.example.com     ─┘

Với NAT Rules:
  Traffic đến payment.example.com  ─→ Dedicated IP pool (2 IPs, allowlisted)
  Traffic đến cdn.example.com      ─→ High-volume pool (5 IPs)
  Traffic đến logs.example.com     ─→ Default pool (remaining IPs)

Cấu Trúc NAT Rule

Mỗi NAT rule có:

  • Rule number: priority (1–65.000), thấp hơn = được evaluate trước
  • Match condition: CEL expression xác định traffic nào áp dụng rule này
  • Action: NAT IP pool nào dùng cho traffic này
bash
# Tạo NAT rule cho payment gateway traffic:
gcloud compute routers nats rules create 1 \
  --nat=NAT_GATEWAY_NAME \
  --router=ROUTER_NAME \
  --region=REGION \
  --match="destination.ip == '203.0.113.1' || destination.ip == '203.0.113.2'" \
  --source-nat-active-ips=projects/PROJECT/regions/REGION/addresses/payment-nat-ip

Match conditions hỗ trợ:

  • destination.ip == 'x.x.x.x'
  • inIpRange(destination.ip, '203.0.113.0/24')
  • destination.ip != 'x.x.x.x'
  • Kết hợp với &&, ||

Traffic không khớp bất kỳ rule nào sẽ đi qua default rule (dùng default NAT IP pool).

Use Case: Allowlisting Destination Với Fixed IPs

Một số third-party services (payment processors, compliance APIs) yêu cầu bạn allowlist source IPs phía họ. Điều này đòi hỏi traffic đến họ luôn xuất phát từ một set IP cố định, không phải bất kỳ IP nào trong auto-allocated pool.

bash
# Reserve static IPs cho payment gateway:
gcloud compute addresses create payment-nat-ip-1 --region=REGION
gcloud compute addresses create payment-nat-ip-2 --region=REGION

# NAT Rule: traffic đến payment processor luôn dùng 2 IPs này:
gcloud compute routers nats rules create 100 \
  --nat=GKE_NAT \
  --router=GKE_ROUTER \
  --region=REGION \
  --match="inIpRange(destination.ip, '10.100.200.0/24')" \
  --source-nat-active-ips=payment-nat-ip-1,payment-nat-ip-2

Lợi ích: traffic thông thường có thể dùng auto-allocated IPs (dynamic), nhưng payment traffic luôn xuất phát từ 2 IPs cố định mà bạn đã allowlist với payment processor.

NAT Rules Kết Hợp Dynamic Port Allocation

DPA và NAT Rules hoạt động cùng nhau: mỗi NAT rule có pool IP riêng và DPA được áp dụng cho từng pool độc lập. Traffic "nặng" và traffic "quan trọng" cạnh tranh port trong pools khác nhau, không ảnh hưởng lẫn nhau.


Metrics Quan Trọng Cần Monitor

port_usage

compute.googleapis.com/nat/port_usage

Đo số NAT source ports hiện tại đang được sử dụng bởi mỗi VM. Đây là metric quan trọng nhất để phát hiện nguy cơ exhaustion trước khi xảy ra.

Cách đọc:

  • So sánh với min-ports-per-vm (static) hoặc max-ports-per-vm (dynamic)
  • Nếu nhiều VMs đang ở gần maximum → nguy cơ exhaustion
  • Trend quan trọng hơn absolute value: nếu đang tăng dần → cần action

Alert recommendation:

# Alert khi bất kỳ VM nào dùng > 80% max allocation:
fetch gce_instance
| metric 'compute.googleapis.com/nat/port_usage'
| group_by 1m, [max_usage: max(value.port_usage)]
| every 1m
| condition max_usage > 3277  # 80% of 4096 max

dropped_sent_packets_count

compute.googleapis.com/nat/dropped_sent_packets_count

Số packet bị drop khi cố gắng gửi qua Cloud NAT. Phân loại theo reason:

  • OUT_OF_RESOURCES: VM hết ports — đây là port exhaustion
  • ENDPOINT_INDEPENDENCE_CONFLICT: EIM conflict (chỉ khi EIM bật)
  • NAT_ALLOCATION_FAILED: Không phân bổ được NAT IP cho VM
bash
# Query drop rate theo reason:
fetch gce_instance
| metric 'compute.googleapis.com/nat/dropped_sent_packets_count'
| align rate(1m)
| every 1m
| group_by [metric.reason], [drop_rate: aggregate(value.dropped_sent_packets_count)]

Alert recommendation: Bất kỳ drop OUT_OF_RESOURCES nào > 0/phút trong 5 phút liên tiếp → PagerDuty.

nat_allocation_failed

compute.googleapis.com/nat/nat_allocation_failed

Binary metric: 0 = bình thường, 1 = Cloud NAT không thể phân bổ IP cho một hoặc nhiều VMs.

Đây là signal nghiêm trọng nhất — cần immediate response.

bash
# Alert khi nat_allocation_failed > 0:
fetch nat_gateway
| metric 'compute.googleapis.com/nat/nat_allocation_failed'
| align next_older(1m)
| every 1m
| condition val() > 0

sent_packets_count và received_packets_count

compute.googleapis.com/nat/sent_packets_count
compute.googleapis.com/nat/received_packets_count

Volume metrics để baseline traffic pattern. Hữu ích để:

  • Tính drop rate = drops / sent_packets (normalize theo traffic volume)
  • Phát hiện traffic spikes bất thường
  • Correlate với application metrics

Normalized Drop Rate

Absolute drop count không đủ context. Nếu bình thường gửi 1M packets/phút và drop 1.000 → 0.1% là có thể acceptable. Nếu chỉ gửi 10K packets/phút và drop 1.000 → 10% là thảm họa.

# MQL: Drop rate normalized theo traffic:
fetch nat_gateway
| { metric 'compute.googleapis.com/nat/dropped_sent_packets_count'
  ; metric 'compute.googleapis.com/nat/sent_packets_count' }
| align rate(1m)
| every 1m
| group_by [resource.gateway_name],
    [drop_rate: (t_0 / (t_0 + t_1)) * 100]

Cloud NAT Logging

Cơ Chế Logging

Cloud NAT có thể log từng connection translation — bao gồm cả successful translations và dropped connections. Log được ghi vào Cloud Logging.

Mỗi log entry chứa:

json
{
  "connection": {
    "src_ip": "10.0.0.5",
    "src_port": 52340,
    "dest_ip": "142.250.1.1",
    "dest_port": 443,
    "protocol": "TCP"
  },
  "endpoint": {
    "vm_name": "gke-cluster-node-abc123",
    "zone": "us-central1-a"
  },
  "gateway_identifiers": {
    "gateway_name": "gke-nat",
    "router_name": "gke-router",
    "region": "us-central1"
  },
  "allocation_status": "OK",  // hoặc "DROPPED"
  "nat_ip": "34.100.200.50",
  "nat_port": 44001
}

Filter Levels và Cost Implications

NAT logging có thể rất expensive — đặc biệt với cluster GKE có traffic cao. Có ba filter options:

FilterLog gìChi phí tương đối
ALLMọi translation (success + failed)Rất cao
TRANSLATIONS_ONLYChỉ successful translationsCao
ERRORS_ONLYChỉ failed/droppedThấp

Recommendation production:

  • Mặc định: ERRORS_ONLY — đủ để debug exhaustion, chi phí thấp
  • Khi debug cụ thể: tạm thời chuyển sang ALL cho 1 gateway và tắt sau khi xong
  • Không dùng ALL liên tục cho high-traffic GKE clusters
bash
# Cấu hình ERRORS_ONLY logging:
gcloud compute routers nats update NAT_GATEWAY_NAME \
  --router=ROUTER_NAME \
  --region=REGION \
  --enable-logging \
  --log-filter=ERRORS_ONLY

# Hoặc tắt logging:
gcloud compute routers nats update NAT_GATEWAY_NAME \
  --router=ROUTER_NAME \
  --region=REGION \
  --no-enable-logging

Query Logs Hữu Ích

Tìm top destinations bị drop:

resource.type="nat_gateway"
jsonPayload.allocation_status="DROPPED"

Nhóm theo jsonPayload.connection.dest_ipjsonPayload.connection.dest_port để xác định destination nào gây ra nhiều drop nhất.

Tìm VM nào bị drop nhiều nhất:

resource.type="nat_gateway"
jsonPayload.allocation_status="DROPPED"

Nhóm theo jsonPayload.endpoint.vm_name.

Correlate với application logs: Timestamp từ NAT drop log có thể được correlate với application error logs trong cùng thời điểm để xác nhận causal relationship.


Connection Pooling và Keep-Alive Patterns

Tại Sao Connection Pooling Là Giải Pháp Dài Hạn

Mọi giải pháp "thêm NAT IP" hoặc "tăng port" chỉ là delay nếu root cause là application behavior tạo quá nhiều short-lived connections. Connection pooling giải quyết tận gốc.

Nguyên tắc: thay vì mở connection mới cho mỗi request, maintain một pool connections sẵn sàng tái sử dụng:

Không có pooling:
  Request 1 → TCP connect → Send → TCP close → TIME_WAIT 120s
  Request 2 → TCP connect → Send → TCP close → TIME_WAIT 120s
  ...
  Request N → Out of ports (phantom shortage từ TIME_WAIT)

Với connection pool (10 connections):
  Startup: mở 10 TCP connections, giữ ESTABLISHED
  Request 1 → borrow connection từ pool → Send → return to pool
  Request 2 → borrow connection từ pool → Send → return to pool
  ...
  Request N → vẫn dùng 10 connections (không tăng port usage)

HTTP/HTTPS: Keep-Alive và HTTP/2

Với HTTP/1.1: bật Connection: keep-alive header để reuse TCP connections. Với HTTP/2: multiplexing built-in — nhiều requests chia sẻ một TCP connection.

gRPC: mỗi gRPC channel là một HTTP/2 connection với multiplexing. Dùng một channel cho mỗi service, không tạo channel per-request.

Database Connection Pooling

Với PostgreSQL, MySQL: dùng pooler như PgBouncer (transaction mode) thay vì để application tự quản lý connections. Với Cloud SQL: Cloud SQL Auth Proxy tự handle connection pooling.

Không có pooler: 100 app instances × 10 connections = 1.000 database connections
Với PgBouncer: 100 app instances → PgBouncer → 20 database connections
→ Giảm 98% port usage phía database side

Một Ví Dụ Minh Họa: "Connection Spike" Do Health Check

Anti-pattern thực tế: Load balancer health checks. Nếu GKE service có nhiều replicas và mỗi replica nhận health check từ nhiều health check IPs với timeout ngắn (health check không dùng keep-alive), đây tạo ra hàng trăm short-lived TCP connections mỗi phút. Nhân với số replicas và số GKE nodes...

Giải pháp: cấu hình health check dùng keep-alive nếu protocol cho phép, hoặc tăng health check interval để giảm tần suất.


Checklist Operational Cloud NAT

Khi Tạo Cloud NAT Mới

  • [ ] Xác định NAT scope: --nat-all-subnet-ip-ranges nếu GKE VPC-native
  • [ ] Chọn port allocation mode: DPA cho hầu hết GKE workloads
  • [ ] Cấu hình min-ports-per-vm phù hợp (≥ 1.024 cho GKE nodes)
  • [ ] Cấu hình tcp-time-wait-timeout=30s (baseline safe)
  • [ ] Bật logging với ERRORS_ONLY
  • [ ] Tạo alerting policies cho dropped_sent_packets_countnat_allocation_failed

Khi Nghi Ngờ Port Exhaustion

  • [ ] Kiểm tra dropped_sent_packets_count metric với breakdown theo reason
  • [ ] Kiểm tra port_usage để tìm VM nào đang ở near-max
  • [ ] Nếu bật logging: query logs tìm DROPPED entries và nhóm theo destination
  • [ ] Kiểm tra netstat -an | awk '{print $6}' | sort | uniq -c trên VM bị nghi
  • [ ] Xác nhận nat_allocation_failed để biết IP-level hay port-level failure

Tuning Decision Tree

Có drop OUT_OF_RESOURCES không?
  └─ Có:
    ├─ Dynamic Port Allocation đã bật chưa?
    │   └─ Chưa: Bật DPA trước
    ├─ max-ports-per-vm đã ở mức reasonable?
    │   └─ 512 hoặc thấp hơn: Tăng lên 4.096 hoặc 8.192
    ├─ tcp-time-wait-timeout = 120s?
    │   └─ Có: Giảm xuống 30s
    └─ Vẫn còn drop: Thêm NAT IP

References