Tại sao cần observability cho mạng

Hạ tầng mạng “chạy ổn” không có nghĩa là “chạy tốt”. Không có observability, bạn chỉ biết hệ thống bị lỗi sau khi user báo, và mất rất nhiều thời gian tìm nguyên nhân.

Không có observability:
  User: "App bị chậm"
  Bạn: tail log → thấy gì? grep lỗi → khoảng thời gian nào? → mất 30 phút

Có observability:
  Alert: p99 latency > 2s trong 5 phút
  Dashboard: tăng 13:42 → correlate với deploy → rollback ngay

RED và USE, hai framework metric

RED (cho service hướng request)

ChữMetricVí dụ
RateRequest/srate(http_requests_total[5m])
ErrorsError raterate(http_requests_total{code=~"5.."}[5m])
DurationLatency distributionp50, p95, p99 của response time

Dùng cho: HTTP API, gRPC service, bất kỳ service có request/response.

USE (cho tài nguyên)

ChữMetricVí dụ
Utilization% capacity đang dùngCPU 80%, connection pool 90%
SaturationQueue / backlogTCP backlog, request queue depth
ErrorsLỗi hardNIC error, packet drop

Dùng cho: CPU, memory, network interface, DB connection pool.


Access log, nguồn dữ liệu rẻ nhất

NGINX access log chứa đủ thông tin để tính RED metric:

# nginx.conf - log format với thời gian
log_format main '$remote_addr - $request_time $status '
                '"$request" $body_bytes_sent '
                '"$http_x_forwarded_for" "$http_user_agent"';

Phân tích nhanh với awk:

# p99 latency từ access log (field $3 = request_time theo log_format trên)
awk '{print $3}' /var/log/nginx/access.log \
  | sort -n | awk 'BEGIN{c=0} {a[c++]=$1} END{print a[int(c*0.99)]}'

# Đếm HTTP status code (field $4 = status)
awk '{print $4}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# Top 10 request chậm nhất (>2s) và request line
awk '$3 > 2 {print $3, $5}' /var/log/nginx/access.log | sort -rn | head -10

Lưu ý: field number phụ thuộc log_format. Format trên dùng space separator với $remote_addr ($1), - ($2), $request_time ($3), $status ($4), "$request" ($5 tính cả dấu "). Nếu dùng JSON log format, thêm jq thay awk cho chính xác hơn: jq -r '.request_time'.

Với Prometheus + NGINX:

# nginx-prometheus-exporter hoặc OpenTelemetry collector đọc log
# → Grafana dashboard tự động

Trace ID, theo dõi request qua nhiều service

Khi request đi qua nhiều service, cần một trace ID duy nhất để ghép log lại:

(Cùng X-Trace-ID ví dụ abc123 trên mọi hop)

Client
│
▼
API Gateway
│
▼
Service A
│
▼
Service B

Truyền trace ID trong HTTP header:

X-Request-ID: abc123        # tự định nghĩa
X-B3-TraceId: ...           # Zipkin/B3 format
traceparent: 00-abc123...   # W3C Trace Context (chuẩn mới, khuyến nghị)

Trong app (Node.js ví dụ):

// Middleware: gán trace ID
app.use((req, res, next) => {
  req.traceId = req.headers["x-request-id"] || crypto.randomUUID();
  res.setHeader("X-Request-ID", req.traceId);
  next();
});

// Khi gọi service khác, truyền trace ID
fetch("http://service-b/api", {
  headers: { "X-Request-ID": req.traceId },
});

// Log với trace ID
logger.info({ traceId: req.traceId, path: req.path }, "request received");

Metric mạng quan trọng cần theo dõi

Tại tầng LB / Ingress

# Prometheus queries ví dụ (NGINX Ingress Controller)

# Request rate
rate(nginx_ingress_controller_requests[5m])

# Error rate (5xx)
rate(nginx_ingress_controller_requests{status=~"5.."}[5m])
  / rate(nginx_ingress_controller_requests[5m])

# p99 latency
histogram_quantile(0.99,
  rate(nginx_ingress_controller_request_duration_seconds_bucket[5m]))

# Active connections
nginx_ingress_controller_nginx_process_connections{state="active"}

Tại tầng TCP (Linux host)

# Connection state hiện tại
ss -tan | awk '{print $1}' | sort | uniq -c

# Chi tiết TCP info của từng socket: RTT, retransmit, cwnd, rcv_space
ss -tip state established

# Drop packet trên NIC
ip -s link show eth0 | grep -A2 "RX\|TX"

# TCP retransmit, syncookies, listen overflow… (nstat thay cho netstat -s)
nstat -az | grep -E "Retrans|Listen|SyncookiesSent|TcpExtTCPSynRetrans"
# Hoặc đọc trực tiếp counter tăng dần:
cat /proc/net/snmp | grep Tcp

ss -ti cho phép nhìn trạng thái sức khoẻ từng kết nối: rtt:1.2/0.5ms cwnd:10 bytes_acked:... retrans:0/3, cực hữu ích khi nghi ngờ packet loss với một đối tác cụ thể. nstat -az là công cụ khuyến nghị thay netstat -s (đã deprecated trên nhiều distro).

eBPF observability (xu hướng 2025)

Với kernel ≥ 4.15, các công cụ eBPF cho phép quan sát traffic không cần sidecar, không sửa app:

  • Cilium Hubble: flow log L3/L4/L7 trên K8s, theo dõi HTTP method, gRPC service, DNS query của mọi Pod.
  • Pixie (CNCF, New Relic): capture request/response ở kernel, auto-tracing gRPC, Redis, MySQL.
  • bpftrace / bcc: scripting cho investigation ad-hoc (tcplife, tcpretrans, tcpconnect).

Khác với packet capture (tcpdump): eBPF đọc metadata ở chỗ kernel đã decode, gần như zero overhead và không bỏ sót gói ở mạng tốc độ cao.


Backlog, dấu hiệu overload

Linux có hai hàng chờ TCP khác nhau (xem chi tiết bài 08):

  • SYN queue (tcp_max_syn_backlog): connection đang handshake.
  • Accept queue (somaxconn): connection đã handshake xong, chờ app accept().

ss -lntp hiển thị accept queue:

ss -lntp
# State   Recv-Q  Send-Q  Local Addr:Port
# LISTEN  150     128     0.0.0.0:80

# Recv-Q = số connection đang chờ accept (hiện tại)
# Send-Q = backlog size (= min(somaxconn, app backlog))
# 150 > 128 → accept queue đã đầy → connection mới bị DROP

Khi backlog đầy → client thấy timeout (không phải refused).

Alert nên có: Recv-Q trên LISTEN socket > 0 trong > 30s.


Dashboard tối thiểu

Một dashboard mạng cơ bản nên có:

  1. Rate: request/s theo service và endpoint.
  2. Error rate: % 5xx, % 4xx.
  3. Latency: p50, p95, p99, theo thời gian.
  4. Active connections: đang ESTABLISHED.
  5. LB health: số instance healthy/unhealthy.

Thêm khi có: packet drop, TCP retransmit, connection pool saturation.


Tóm tắt

  • RED cho service request; USE cho tài nguyên, hai framework bổ sung nhau.
  • Access log là nguồn dữ liệu không cần instrumentation, phân tích ngay từ log.
  • Trace ID trong header là điều kiện tối thiểu để debug request qua nhiều service.
  • Backlog đầy = client timeout, không phải refused, theo dõi Recv-Q.

Câu hỏi hay gặp

p99 tăng mạnh sau deploy nhưng p50 vẫn thấp, gợi ý gì?

Trả lời: Thường là một nhánh request hoặc một tỷ lệ nhỏ chậm (cold start, lock, query xấu, canary). Cần histogram/percentile theo route, so sánh phiên bảntrace vài request chậm.

Không có trace ID, lọc log thế nào? Có trace ID thì lợi gì?

Trả lời: Không có trace: lọc theo thời gian + path + status + IP, mất thời gian. Có trace ID: grep một ID xuyên gateway → app → downstream, nhanh và chắc.

USE: metric nào “báo trước” overload?

Trả lời: Saturation (queue backlog, connection pool đầy, Recv-Q tăng, CPU run queue) thường sớm hơn error rate, utilization 100% đã muộn hơn một bước.


Bài tiếp theo (Giai đoạn IV): IaC và GitOps cho hạ tầng mạng, quản lý Security Group, route và listener bằng code, không click-ops.