← Tất cả bài viết

Giảm CPU pressure trên VM 2 vCPU từ 56% xuống 17% mà không nâng cấp máy

VM production của chúng tôi chậm hẳn. Thay vì thuê máy lớn hơn, chúng tôi quy từng phần trăm CPU về đúng chỗ và tìm ra hàng chục chi phí nhỏ lặp lại: đó là gì, 2server đã thay đổi gì để chúng không quay lại, và cách chạy cùng cuộc kiểm tra trên máy chủ của bạn.

VM production của chúng tôi có 2 vCPU và chạy khoảng 20 container: một trang đọc truyện, API của nó, một dịch vụ dịch, cơ sở dữ liệu, cache, giám sát và vài app nhỏ. Một buổi chiều, mọi thứ chậm hẳn. Load đứng quanh 6, trong khi cơ sở dữ liệu managed vẫn bình thường.

Cách dễ nhất là thuê máy lớn hơn. Chúng tôi đo trước. Hai ngày sau, CPU pressure trên chính VM đó giảm từ 56% xuống 17%. Bài này kể những gì chúng tôi tìm thấy, những gì đã sửa trong 2server để lỗi không quay lại, và cách chạy cùng cuộc kiểm tra trên máy chủ của bạn.

Đo pressure, không chỉ đo usage

"CPU 60%" không cho biết request có đang phải chờ hay không. Linux báo điều đó trực tiếp qua pressure stall information (PSI): /proc/pressure/cpu cho biết tỉ lệ thời gian có ít nhất một tác vụ sẵn sàng chạy nhưng phải chờ CPU. Của chúng tôi là 56% trong 60 giây. Hơn nửa thời gian, có việc muốn chạy mà không được chạy.

Để biết ai đang dùng CPU, chúng tôi đọc usage_usec trong cpu.stat của từng cgroup ở đầu và cuối một cửa sổ hai phút. Cách này cho ra thời gian CPU chính xác của từng container và từng systemd service, không cần cài agent nào. Thêm hai góc nhìn để bắt những gì công cụ theo container bỏ sót:

  • Tiến trình đã kết thúc. Job chạy theo timer và probe docker run --rm xong trước khi kịp nhìn thấy. Chi phí của chúng chỉ hiện ra ở phần system.slice không thuộc tiến trình con nào còn sống, và ở dòng Consumed … CPU time trong journal cho mỗi lần chạy.
  • Hoạt động của Docker. Mỗi healthcheck và docker exec đều khởi động tiến trình, và containerd, dockerd trả giá cho từng lần. docker events cho ra số lần theo từng container.

Những gì chúng tôi tìm thấy

Không ai chọn những thứ này làm workload. Đó là hàng chục chi phí nhỏ, lặp lại hàng nghìn lần mỗi ngày.

Ứng dụng làm việc thừa. Đây là phần lớn nhất.

  • Một client thử lại một probe cache rẻ ngay khi nhận 429, tổng cộng khoảng 23.000 request bị từ chối mỗi giờ.
  • Một dịch vụ chạy image cũ hơn chính bản sửa của nó: mỗi request kiểm tra hash mật khẩu bằng JavaScript thuần. Deploy lại image hiện tại đưa nó từ 12% một core xuống 1,8%.
  • API xác thực lại cùng một token ở mỗi request. Một cache ngắn đưa chi phí về khoảng 4 ms CPU mỗi request.

Probe và polling.

  • Bộ thu metrics tốn 11–12 giây CPU mỗi phút, khoảng 19% một core, vì gọi jq khoảng 300 lần mỗi lượt. Gộp lại còn khoảng 1 giây.
  • Việc làm mới metadata cứ 5 giây chạy một lần. Giờ nó đi theo sự kiện Docker, kèm một timer an toàn chậm.
  • Healthcheck chạy mỗi 5–10 giây. 30 giây là đủ khi đã có start_interval ngắn cho lúc khởi động.
  • Edge proxy kiểm tra một app bằng cách render trang chủ mỗi 5 giây, tốn khoảng 3% một core. Một file tĩnh gần như không tốn gì.
  • Probe kiểm tra sẵn sàng khi deploy khởi động một container curl cho mỗi lần thử, khoảng 1,5 giây mỗi lần. Gọi curl từ host chỉ mất khoảng 25 ms.

Trùng lặp và đồ bỏ quên.

  • Agent logging, metrics và OS-config của nhà cung cấp cloud chạy song song với Prometheus của chính chúng tôi. Không gì dùng dữ liệu của chúng, mà chúng tốn khoảng 4% một core và 350 MB bộ nhớ.
  • Một image proxy thứ hai không có chút traffic nào, nằm cạnh bản đang phục vụ mọi ảnh.
  • Một script autoheal hỏi Docker mỗi 10 giây. Giờ nó phản ứng theo sự kiện health_status.

Việc thật. Phần còn lại là traffic: API, web server và cơ sở dữ liệu. Chỉ phần này mới đáng để mua thêm tài nguyên.

Kết quả

Trước Sau
CPU pressure (PSI some, trung bình 60 s) 56% 17%
Load average ~6 1,5–2
Kích thước VM 2 vCPU, 8 GB giữ nguyên

Gỡ các agent không dùng và proxy thừa cũng giải phóng khoảng 320 MB bộ nhớ. Phần lớn mức giảm CPU đến từ các bản sửa ứng dụng. Con số trên máy của bạn sẽ khác, nhưng thứ tự của danh sách thì thường giống: xem ứng dụng trước, rồi probe và timer, rồi đồ trùng lặp, cuối cùng mới đến tài nguyên.

Deploy cũng là tài nguyên

Một lần deploy chậm hoặc bị chặn cũng là chi phí. Trong lúc đo, chúng tôi rút ngắn luôn những gì 2server giữ trong một lần phát hành:

  • Mỗi bước remote giờ dùng lại một kết nối SSH. Qua GCP IAP tunnel, một bước giảm từ 4–7 giây xuống khoảng 0,15 giây, và một lần plan từ 32 giây xuống 7.
  • Lock toàn server khi cập nhật monitoring giảm từ 112 giây xuống 43. Phiên bản cũ được drain sau khi đã nhả lock.
  • Hai app khác nhau giờ deploy cùng lúc mà không chờ nhau, miễn là tên miền của chúng không đổi. Thứ duy nhất dùng chung là một lần reload Caddy dưới một giây.

Thay đổi cuối cùng làm lộ ra một bug. Nhiều tên miền dùng chung một zone Cloudflare không bao giờ cùng được tính là "không đổi", vì mỗi tên miền đều muốn cache rule của mình đứng cuối zone. Mỗi lần deploy lại âm thầm xếp lại các rule. Giờ rule chỉ cần đứng trước policy chung của zone.

Để vấn đề không quay lại

Sửa một VM một lần là chưa đủ. App tiếp theo sẽ chép cấu hình của app trước, nên chúng tôi đưa các bước kiểm tra vào chính 2server:

  • 2srv validate và 2srv plan in một dòng Advisory: khi một probe sẽ tốn CPU suốt đời app: healthPath là trang / được render, healthcheck dày hơn mỗi 10 giây, hoặc probe dùng interpreter như node -e dày hơn mỗi 30 giây. Advisory không bao giờ chặn deploy. Lần chạy đầu trên các repo của chính chúng tôi, nó bắt thêm được một app.
  • Các template dịch vụ (PostgreSQL, Redis, NATS, Meilisearch, giám sát, image proxy) probe mỗi 30 giây với start interval ngắn.
  • Usage snapshot kết thúc bằng phần tự phát hiện: healthcheck ngắn hoặc dùng interpreter, timer polling dày hơn 30 giây, container không do 2server quản lý, và agent của nhà cung cấp cloud đang chạy.

Một dịch vụ đã cài giữ nguyên template lúc nó được áp dụng. Sau khi nâng cấp CLI, hãy chạy plan cho từng file dịch vụ và áp lại những file có thay đổi.

Chạy kiểm tra trên VM của bạn

Cuộc kiểm tra này nằm trong skill 2server cho agent. Hãy nhờ agent lập trình của bạn:

text
Use $2server:2server to audit resource usage on my connected VM. Take a
usage snapshot, attribute CPU and memory, and give me ranked, low-risk
proposals. Read-only: do not restart, redeploy or change anything.

Script snapshot chạy bằng root qua kết nối SSH sẵn có, không thay đổi gì và không bao giờ in dòng lệnh hay giá trị biến môi trường. Tài liệu tham khảo ở usage-audit.md.

2server deploy app container lên VM của bạn qua SSH, với bản phát hành blue/green chỉ chuyển traffic khi app sẵn sàng. Giữa các lần chạy lệnh, không có agent hay control plane nào chạy thường trực trên máy chủ. Bắt đầu tại 2found.dev/vi/tools/2server.