Ba mươi phần của sê-ri đã đo từng lớp quan sát riêng lẻ: một dòng log tốn bao nhiêu, một chỉ số sinh ra bao nhiêu chuỗi, một span nặng bao nhiêu byte. Phần này cộng chúng lại trên cùng một dịch vụ, bật dần từng lớp, và đo tổng.
Bảng số liệu
Một dịch vụ HTTP làm việc tính toán thật, 20 000 yêu cầu mỗi lần đo, bật dần từng lớp bằng biến môi trường.
| Cấu hình | Thông lượng | CPU | Bộ nhớ | Dữ liệu sinh ra |
|---|---|---|---|---|
| Trần trụi | 4 125 req/s | 3,939 s | 19,2 MB | 0 |
| + log | 3 949 (−4,3%) | 4,163 s (+5,7%) | 19,4 MB | 1,28 MB |
| + log + chỉ số | 3 913 (−5,1%) | 4,193 s (+6,4%) | 23,9 MB (+24,5%) | +1 312 B |
| + log + chỉ số + trace | 3 591 (−12,9%) | 4,698 s (+19,3%) | 28,0 MB (+45,8%) | +2,57 MB |
Tách riêng từng lớp:
| Thông lượng | CPU | Bộ nhớ | Dữ liệu | |
|---|---|---|---|---|
| Log | −4,3% | +5,7% | +0,2 MB | 1,28 MB |
| Chỉ số | −0,9% | +0,7% | +4,5 MB | 1 312 B |
| Trace | −8,2% | +12,0% | +4,1 MB | 2,57 MB |
Quy ra ở 1 000 yêu cầu mỗi giây:
| Mỗi ngày | |
|---|---|
| Log — 67 byte mỗi yêu cầu | 5,4 GB |
| Trace — 135 byte mỗi yêu cầu | 10,8 GB |
| Chỉ số — 1 312 byte mỗi lần thu thập, chu kỳ 15 giây | 7,2 MB |
Điều đáng nhớ
Bật cả ba lớp lấy đi 12,9% thông lượng, 19,3% CPU và 45,8% bộ nhớ. Đó là một khoản thật — gần một phần tám công suất — nhưng nó không phải thảm hoạ, và nó mua về toàn bộ khả năng biết chuyện gì đang xảy ra.
Trace là lớp đắt nhất ở cả ba cột: −8,2% thông lượng, +12,0% CPU, 2,57 MB dữ liệu. Nó cũng là lớp duy nhất trả lời được câu "chậm ở đâu" — như phần 20 đã đo, khi một dịch vụ giữa chuỗi chậm thì không chỉ số nào ở đầu chuỗi chỉ ra được thủ phạm.
Chỉ số gần như miễn phí về CPU và băng thông, nhưng tốn bộ nhớ. +0,7% CPU và 1 312 byte dữ liệu — trong khi trace sinh 2,57 MB cho cùng lượng công việc. Nhưng nó chiếm thêm 4,5 MB bộ nhớ, nhiều hơn cả trace.
Và đây là khác biệt bản chất, không phải khác biệt mức độ: chỉ số không tỷ lệ với lưu lượng. 1 312 byte đó là toàn bộ trạng thái của mọi bộ đếm và histogram; nó vẫn là 1 312 byte nếu có 20 triệu yêu cầu thay vì 20 nghìn. Log và trace thì ngược lại — mỗi yêu cầu thêm một dòng và bốn span.
Ở 1 000 yêu cầu mỗi giây, khác biệt đó thành 10,8 GB mỗi ngày cho trace so với 7,2 MB cho chỉ số — gấp 1 540 lần.
Vì sao
Ba lớp có ba mô hình dữ liệu khác nhau, và mô hình quyết định cách chi phí tăng.
Chỉ số giữ trạng thái gộp. Một Counter là một số; nó tăng lên chứ không dài ra. Chi phí bộ nhớ tỷ lệ với số chuỗi thời gian — phần 11 đã đo chuyện đó — chứ không tỷ lệ với số sự kiện. Đó là lý do nó chiếm 4,5 MB ngay từ đầu (các đối tượng histogram và bộ đăng ký) rồi gần như đứng yên.
Log và trace ghi sự kiện. Mỗi yêu cầu để lại dấu vết riêng, nên dung lượng tỷ lệ tuyến tính với lưu lượng. Chi phí CPU của chúng cũng vậy: định dạng một chuỗi, dựng một span, đẩy vào hàng đợi — làm một lần cho mỗi yêu cầu.
Trace đắt hơn log vì mỗi yêu cầu tạo bốn span chứ không phải một dòng, và mỗi span cần dựng đối tượng, quản lý ngữ cảnh, đặt thuộc tính, rồi tuần tự hoá. Phần 21 đo riêng phần đó là 48,6 µs mỗi span khi có xuất OTLP.
Điều đáng nói là thứ tự chi phí không giống thứ tự giá trị. Chỉ số rẻ nhất nhưng chỉ nói "có vấn đề". Trace đắt nhất nhưng là thứ duy nhất nói "vấn đề ở chặng nào". Cắt theo chi phí là cắt ngược với giá trị.
Nghĩa là gì trong thực tế
- Ngân sách 10–15% công suất cho quan sát là hợp lý, và hãy coi nó là chi phí vận hành chứ không phải thứ để tiết kiệm. Một sự cố kéo dài thêm một giờ vì thiếu dữ liệu đắt hơn nhiều so với 12,9% thông lượng.
- Nếu buộc phải cắt, cắt theo thứ tự này: lấy mẫu trace trước (phần 23 đã đo — lấy mẫu đuôi giữ 100% trace lỗi với 5,93% chi phí lưu), rồi giảm số dòng log. Đừng cắt chỉ số — nó rẻ nhất trong ba và là thứ duy nhất cho bạn cảnh báo.
- Tính ngân sách lưu trữ theo lớp, không tính chung. 10,8 GB trace và 7,2 MB chỉ số là hai bài toán khác nhau tới mức gộp chúng vào một dòng ngân sách là vô nghĩa.
- Đo bộ nhớ, đừng chỉ đo CPU. Chỉ số chỉ tốn 0,7% CPU nhưng 24,5% bộ nhớ — nếu container của bạn có giới hạn bộ nhớ chặt, đó mới là cột đáng lo.
- Đừng suy ra tỷ lệ phần trăm này cho dịch vụ của bạn. Dịch vụ của tôi xử lý một yêu cầu trong khoảng 240 µs. Một dịch vụ tốn 20 ms mỗi yêu cầu sẽ thấy cùng chi phí tuyệt đối đó thành dưới 1%.
Chỗ tôi không kết luận được
Tỷ lệ phần trăm phụ thuộc hoàn toàn vào việc dịch vụ của tôi rất nhanh. Đây là điểm quan trọng nhất cần nói. Chi phí tuyệt đối của quan sát gần như cố định trên mỗi yêu cầu; tỷ lệ của nó thì tỷ lệ nghịch với thời gian xử lý. Dịch vụ càng nhanh thì quan sát càng đắt tương đối — cùng một hiện tượng đã gặp ở phần 28 với thời gian máy chủ so với thời gian người dùng.
Tôi đếm byte span bằng ước lượng, không phải đo. Bộ xuất của tôi đếm số span rồi nhân với 135 byte — con số đo được ở phần 21 với đúng bộ thuộc tính này. Nó không phải phép đo độc lập trong bài này, và nếu thuộc tính khác đi thì con số đổi.
Không có bộ thu nào ở đầu kia. Log ghi ra tệp cục bộ, chỉ số nằm trong bộ nhớ, span đi vào một bộ xuất giả. Hệ thống thật đẩy tất cả qua mạng tới Loki, Prometheus và Tempo — và như phần 24 đã đo, phía nhận có chi phí riêng đáng kể.
Đây là Python. Phần lớn chi phí CPU trong bài này là chi phí của một ngôn ngữ động dựng đối tượng và định dạng chuỗi. Với Go hay Rust, cả ba lớp đều rẻ hơn nhiều bậc, và tỷ lệ giữa chúng cũng có thể đổi.
Một lỗi làm hỏng trọn lần đo đầu tiên, và tôi đã từng viết về chính nó. Lần chạy đầu cho thông lượng gần như y hệt nhau ở cả bốn cấu hình — 3 972, 3 980, 4 024, 4 043 req/s — và không lớp nào sinh ra một byte nào. Nguyên nhân: tôi dùng set -- $CFG để tách chuỗi "1 1 1" thành ba tham số, nhưng zsh không tách từ khi khai triển tham số không đặt trong nháy. Biến LOG nhận giá trị "1 1 1", so sánh LOG == "1" cho sai, và cả ba lớp đều tắt ở mọi cấu hình.
Điều đáng nói: tôi đã gặp đúng cái bẫy này ở phần 47 của sê-ri Linux trước đó, khi một cờ --security-opt bị gộp thành một đối số duy nhất, và tôi đã viết hẳn một đoạn về nó. Lần đó Docker báo lỗi rõ ràng nên tôi phát hiện ngay. Lần này không có lỗi nào — chương trình chạy bình thường với mọi lớp tắt, và thứ duy nhất tố cáo là bốn con số giống nhau đến mức đáng ngờ.
Thử ba mươi giây
# Do chi phi quan sat cua chinh dich vu ban, khong can cong cu gi
# Chay hai lan: mot lan nhu binh thuong, mot lan tat het quan sat
# 1. Lay so nen (tat log/metric/trace bang bien moi truong cua ung dung ban)
# 2. Bat lai va do lai
# 3. So ba cot nay:
ps -o pid,%cpu,rss,comm -p <PID_UNG_DUNG>
curl -s localhost:<PORT>/metrics | wc -c # so byte metric moi lan thu thap
ls -l /var/log/<ung-dung>.log # so byte log tich luy
Ba con số đó — CPU, bộ nhớ, byte mỗi lớp — là toàn bộ hoá đơn. Cột cuối là cột hay bị bỏ quên nhất, và ở 1 000 yêu cầu mỗi giây nó là hàng chục gigabyte mỗi ngày.