Monitoring

Uptime Kuma sau 1 năm tự host: Giới hạn chịu tải và bài học vận hành

Đánh giá vận hành Uptime Kuma sau 1 năm tự host: mức tiêu thụ RAM/CPU thực tế, xử lý nghẽn SQLite, tối ưu WAL mode, vacuum dọn dẹp đĩa và chống bão cảnh báo Telegram.

Uptime Kuma sau 1 năm tự host giới hạn chịu tải và bài học vận hành
MỤC LỤC

Uptime Kuma là một trong những công cụ mã nguồn mở được lựa chọn nhiều nhất để tự xây dựng trang trạng thái (Status Page) và giám sát thời gian hoạt động của website. Nhờ giao diện trực quan, hỗ trợ đa dạng giao thức kiểm tra (HTTP, TCP, Ping, DNS) và tích hợp sẵn hàng chục kênh thông báo, công cụ này giúp người vận hành theo dõi tình trạng dịch vụ mà không cần phụ thuộc vào các gói dịch vụ giám sát trả phí. Trong khuôn khổ các tiêu chí đánh giá tự host công cụ nội bộ trên VPS, Uptime Kuma luôn là ứng viên hàng đầu được khuyến nghị triển khai nhờ tính độc lập cao và chi phí hạ tầng thấp.

Tuy nhiên, khi quy mô giám sát tăng dần từ một vài trang web lên hàng chục hoặc hàng trăm endpoint với tần suất kiểm tra dày đặc, hệ thống bắt đầu bộc lộ các giới hạn về tài nguyên. Cơ sở dữ liệu SQLite mặc định dễ gặp tình trạng khóa ghi (database locked), file log phình to làm cạn kiệt dung lượng đĩa và tiến trình Node.js có thể tiêu tốn nhiều RAM hơn dự tính. Những bài học vận hành thực tế dưới đây giúp bạn cấu hình tối ưu Uptime Kuma để hệ thống hoạt động bền bỉ, cung cấp dữ liệu đo lường chính xác và không trở thành một điểm nghẽn hạ tầng.

Kiến trúc lưu trữ và giải pháp tối ưu SQLite trong Uptime Kuma

1. Mức tiêu thụ tài nguyên thực tế của Uptime Kuma trên VPS

Uptime Kuma được phát triển trên nền tảng Node.js ở phía máy chủ và Vue.js ở giao diện người dùng, thường được triển khai dưới dạng một container Docker duy nhất. Trong môi trường thử nghiệm trên máy chủ VPS cấu hình 1 vCPU và 2GB RAM chạy hệ điều hành Ubuntu, mức độ tiêu thụ tài nguyên có sự thay đổi rõ rệt tùy theo quy mô giám sát.

Bảng theo dõi mức tiêu thụ tài nguyên thực tế

Số lượng Endpoint (Monitors)Tần suất kiểm tra (Interval)Mức RAM trung bìnhMức CPU trung bìnhĐánh giá vận hành
10 – 30 monitors60 giây180MB – 250MB1% – 3%Rất ổn định, phù hợp với cả gói VPS nhỏ nhất (1GB RAM).
50 – 100 monitors30 – 60 giây350MB – 500MB5% – 12%Bắt đầu xuất hiện độ trễ khi mở dashboard nếu ổ đĩa có tốc độ IOPS thấp.
150 – 200+ monitors20 – 30 giây650MB – 900MB15% – 25%Node.js duy trì hàng trăm kết nối mạng đồng thời, SQLite dễ bị nghẽn ghi.

Quản lý bộ nhớ cho tiến trình Node.js

Node.js quản lý bộ nhớ thông qua cơ chế thu gom rác (Garbage Collection). Khi Uptime Kuma phải xử lý hàng trăm request HTTP và duy trì nhiều kết nối WebSocket liên tục tới các trình duyệt đang mở dashboard, lượng bộ nhớ cấp phát có thể tăng nhanh và giải phóng chậm.

Để ngăn chặn tình trạng Uptime Kuma rò rỉ bộ nhớ làm kích hoạt tiến trình OOM Killer của Linux đánh sập các dịch vụ quan trọng khác trên VPS (tham khảo thêm cách chẩn đoán tại bài VPS hết RAM và OOM Killer: dấu hiệu và cách phòng ngừa), bạn nên cấu hình giới hạn phần cứng trong file docker-compose.yml:

yaml
services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - ./data:/app/data
    ports:
      - "127.0.0.1:3001:3001"
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 800M
        reservations:
          memory: 256M

Việc giới hạn 800M RAM vừa đảm bảo container có đủ không gian xử lý dữ liệu biểu đồ, vừa giữ cho hệ điều hành VPS luôn có khoảng trống bộ nhớ an toàn cho các tác vụ nền.

2. Nút thắt cổ chai SQLite và lỗi "database is locked"

Mặc định, Uptime Kuma lưu trữ toàn bộ cấu hình, lịch sử đo lường và nhật ký sự kiện vào một tệp tin cơ sở dữ liệu SQLite duy nhất tại đường dẫn /app/data/kuma.db.

SQLite là một hệ quản trị cơ sở dữ liệu xuất sắc cho các ứng dụng vừa và nhỏ nhờ tính gọn nhẹ và không cần duy trì một tiến trình dịch vụ riêng biệt. Tuy nhiên, kiến trúc truyền thống của SQLite sử dụng mô hình ghi đơn luồng với cơ chế khóa tệp tin toàn phần (Exclusive File Lock).

Cơ chế gây lỗi khi giám sát nhiều endpoint

Khi bạn cấu hình hơn 100 endpoint và để cùng một khoảng thời gian kiểm tra (ví dụ 60 giây), các worker của Uptime Kuma sẽ gửi request đồng loạt và hoàn thành gần như cùng một thời điểm. Hàng chục luồng ghi kết quả heartbeat sẽ cố gắng chèn dữ liệu vào bảng cơ sở dữ liệu cùng lúc.

Đồng thời, nếu người quản trị mở trang web Uptime Kuma để xem báo cáo lịch sử 30 ngày qua giao diện, tiến trình đọc này sẽ khóa cơ sở dữ liệu trong vài giây để quét qua hàng trăm ngàn bản ghi. Hậu quả là các tiến trình ghi của worker bị chặn lại. Khi thời gian chờ vượt quá ngưỡng cho phép, Uptime Kuma sẽ ghi nhận hàng loạt lỗi trong log:

text
SqliteError: database is locked
    at Statement.run (/app/node_modules/better-sqlite3/lib/methods/wrappers.js:9:14)

Nghiêm trọng hơn, khi worker không thể ghi nhận trạng thái phản hồi vào cơ sở dữ liệu do tệp bị khóa, Uptime Kuma có thể coi lần kiểm tra đó là thất bại (Timeout) và phát tín hiệu cảnh báo dịch vụ sập, tạo ra các báo động giả (False Alarm) gây hoang mang cho đội ngũ kỹ thuật.

Hai giải pháp khắc phục triệt để lỗi khóa SQLite

Để giải quyết vấn đề tranh chấp ghi trên SQLite, bạn cần áp dụng đồng bộ hai kỹ thuật sau:

Giải pháp 1: Kích hoạt chế độ Write-Ahead Logging (WAL)

Chế độ mặc định của SQLite sử dụng rollback journal: mỗi khi có tiến trình ghi, toàn bộ tệp database bị khóa đối với cả hoạt động đọc lẫn ghi.

Chế độ WAL (Write-Ahead Logging) thay đổi hoàn toàn nguyên lý này:

  • Dữ liệu ghi mới được tuần tự ghi vào một tệp nhật ký riêng biệt (kuma.db-wal).
  • Các tiến trình đọc dữ liệu từ tệp chính kuma.db không bị gián đoạn và không chặn tiến trình ghi.
  • Các worker có thể ghi dữ liệu heartbeat liên tục mà không bị nghẽn bởi thao tác truy vấn báo cáo của dashboard.

Cách kích hoạt chế độ WAL cho Uptime Kuma:

  1. Tạm dừng container Uptime Kuma:
bash
   docker compose stop uptime-kuma
  1. Cài đặt tiện ích dòng lệnh sqlite3 trên VPS (nếu chưa có) và thực thi lệnh đổi chế độ journal:
bash
   sudo apt-get install -y sqlite3
   cd /path/to/uptime-kuma/data
   sqlite3 kuma.db "PRAGMA journal_mode=WAL;"
  1. Lệnh sẽ trả về kết quả wal. Kiểm tra lại cấu hình:
bash
   sqlite3 kuma.db "PRAGMA journal_mode;"
  1. Khởi động lại container:
bash
   docker compose start uptime-kuma

Sau khi kích hoạt, bạn sẽ thấy xuất hiện hai tệp phụ là kuma.db-wal và kuma.db-shm bên cạnh tệp kuma.db. Đây là dấu hiệu cơ sở dữ liệu đã chuyển sang chế độ chịu tải cao thành công.

Giải pháp 2: Giãn cách nhịp kiểm tra (Staggered Interval)

Tránh đặt toàn bộ các monitor ở cùng một nhịp kiểm tra tròn như 60 giây. Hãy chủ động phân bổ tần suất theo mức độ quan trọng của dịch vụ:

  • Các endpoint giao dịch thanh toán hoặc API quan trọng: Đặt nhịp 30s hoặc 45s.
  • Các trang blog, landing page tĩnh: Đặt nhịp 60s hoặc 75s.
  • Các dịch vụ nội bộ, cổng SMTP, DNS: Đặt nhịp 90s hoặc 120s.

Việc giãn cách các chu kỳ này giúp phân tán đều các nhịp ghi dữ liệu qua từng giây, tránh việc hàng trăm kết nối cùng dồn về một thời điểm gây đột biến I/O đĩa.

3. Kiểm soát dung lượng đĩa: Auto-purge và lệnh VACUUM

Một trong những bất ngờ lớn nhất sau vài tháng vận hành Uptime Kuma là dung lượng ổ đĩa của máy chủ bị tiêu hao nhanh chóng.

Tốc độ tăng trưởng dữ liệu của bảng Heartbeat

Mỗi lần Uptime Kuma thực hiện ping, một bản ghi mới được thêm vào bảng heartbeat gồm các trường: thời gian phản hồi (ping time), mã trạng thái HTTP, thông điệp phản hồi và mốc thời gian (timestamp).

Hãy làm một phép tính đơn giản:

  • Bạn theo dõi 80 endpoint với tần suất kiểm tra trung bình 30 giây một lần.
  • Mỗi phút có: 80 × 2 = 160 bản ghi.
  • Mỗi ngày có: 160 × 60 × 24 = 230.400 bản ghi.
  • Sau 1 năm, bảng này tích lũy hơn 84 triệu bản ghi.

Nếu không có chính sách kiểm soát, tệp kuma.db có thể phình to từ vài trăm megabyte lên đến 8GB – 15GB, không chỉ chiếm dụng tài nguyên lưu trữ của VPS mà còn làm tê liệt chức năng vẽ biểu đồ trên giao diện.

Cấu hình chính sách lưu giữ dữ liệu (Retention Policy)

Truy cập vào giao diện web của Uptime Kuma: Settings -> General -> Auto-purge old data:

  • Mặc định, Uptime Kuma có thể lưu giữ dữ liệu trong 180 ngày hoặc không giới hạn.
  • Khuyến nghị thực tế: Chuyển thời gian lưu giữ về mức 30 ngày hoặc tối đa 60 ngày.

Dữ liệu trạng thái uptime theo từng phút sau 30 ngày thường không còn nhiều giá trị thực tiễn cho việc chẩn đoán sự cố, trong khi việc cắt giảm này giúp giữ quy mô database ở mức dưới 1GB.

Thu hồi dung lượng thực tế với lệnh VACUUM

Khi Uptime Kuma thực thi chính sách tự động xóa các bản ghi cũ (Auto-purge), SQLite chỉ đánh dấu các vùng dữ liệu đó là "trang trống" (free pages) để tái sử dụng cho các bản ghi tiếp theo chứ không trả lại dung lượng ổ đĩa cho hệ điều hành.

Nếu tệp kuma.db đã từng phình lên 5GB, sau khi bật Auto-purge và xóa hàng triệu dòng dữ liệu, kích thước tệp hiển thị trên Linux bằng lệnh ls -lh vẫn giữ nguyên là 5GB.

Để thực sự thu hồi dung lượng đĩa, bạn cần chạy lệnh VACUUM để SQLite dọn dẹp các trang trống và đóng gói lại tệp cơ sở dữ liệu:

bash
# 1. Tạm dừng Uptime Kuma để giải phóng các tiến trình đang kết nối
docker compose stop uptime-kuma

# 2. Thực thi lệnh VACUUM trực tiếp trên file database
cd /path/to/uptime-kuma/data
sqlite3 kuma.db "VACUUM;"

# 3. Khởi động lại dịch vụ
docker compose start uptime-kuma

Nên đưa thao tác này vào quy trình bảo trì định kỳ mỗi 3 đến 6 tháng một lần. Lệnh VACUUM có thể giúp thu nhỏ kích thước tệp từ nhiều gigabyte xuống chỉ còn vài trăm megabyte trong vài phút.

4. Quy trình sao lưu kuma.db an toàn không làm hỏng dữ liệu

Toàn bộ công sức cấu hình hàng trăm endpoint, thông tin tài khoản và lịch sử vận hành đều nằm trọn vẹn trong thư mục dữ liệu của Uptime Kuma. Tuy nhiên, việc sao lưu cơ sở dữ liệu SQLite đang hoạt động đòi hỏi phương pháp chính xác.

Rủi ro khi sao chép trực tiếp bằng lệnh cp

Nhiều quản trị viên thường tạo một cronjob chạy lệnh cp /path/to/kuma.db /backup/ hàng đêm. Khi cơ sở dữ liệu đang chạy ở chế độ WAL, các giao dịch mới nhất đang nằm trên tệp kuma.db-wal và bộ nhớ tạm kuma.db-shm.

Nếu bạn sao chép tệp kuma.db trong lúc hệ thống đang ghi dữ liệu, bản sao lưu sẽ bị khuyết các giao dịch chưa được đồng bộ (checkpoint). Khi cần khôi phục, SQLite có thể báo lỗi tệp bị hư hỏng (database disk image is malformed) và từ chối mở dữ liệu.

Giải pháp 1: Sử dụng SQLite Online Backup API

Tiện ích sqlite3 tích hợp sẵn lệnh .backup sử dụng cơ chế Online Backup API. Lệnh này khóa an toàn ở cấp độ giao dịch nội bộ, tự động đồng bộ các bản ghi từ WAL vào bản sao lưu mà không làm gián đoạn các luồng đọc/ghi của container:

Tạo script sao lưu tự động tại /opt/scripts/backup-kuma.sh:

bash
#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/data/backups/uptime-kuma"
DATA_DIR="/opt/uptime-kuma/data"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
TARGET_FILE="${BACKUP_DIR}/kuma_${TIMESTAMP}.db"

mkdir -p "${BACKUP_DIR}"

# Thực hiện snapshot trực tuyến an toàn
sqlite3 "${DATA_DIR}/kuma.db" ".backup '${TARGET_FILE}'"

# Nén file sao lưu để tiết kiệm dung lượng
gzip -9 "${TARGET_FILE}"

# Giữ lại các bản sao lưu trong 14 ngày gần nhất
find "${BACKUP_DIR}" -type f -name "kuma_*.db.gz" -mtime +14 -delete

echo "Sao lưu Uptime Kuma thành công: ${TARGET_FILE}.gz"

Cấp quyền thực thi và đặt lịch chạy trong crontab của máy chủ VPS vào lúc 2 giờ sáng hàng ngày:

bash
chmod +x /opt/scripts/backup-kuma.sh
# Thêm vào crontab: 0 2 * * * /opt/scripts/backup-kuma.sh > /dev/null 2>&1

Giải pháp 2: Tạm dừng container khi sao lưu toàn diện (Volume Backup)

Nếu bạn sử dụng các công cụ sao lưu chuyên dụng theo bài so sánh Restic và Borg Backup cho VPS để đóng gói toàn bộ thư mục ./data (bao gồm cả ảnh đại diện, chứng chỉ, cấu hình), hãy sử dụng lệnh docker compose pause trước khi đọc tệp và unpause ngay sau khi hoàn thành:

bash
# Tạm dừng các tiến trình trong container (không tắt container)
docker compose pause uptime-kuma

# Thực hiện lệnh sao lưu thư mục data ra bộ nhớ đám mây (Cloudflare R2 / S3)
restic backup /opt/uptime-kuma/data

# Phục hồi hoạt động bình thường cho container
docker compose unpause uptime-kuma

Thao tác pause chỉ diễn ra trong vài giây, đảm bảo toàn bộ các tệp kuma.db, kuma.db-wal và kuma.db-shm được chụp lại ở trạng thái đóng băng nhất quán tuyệt đối.

5. Cấu hình cảnh báo Telegram và Slack chống dội thông báo

Một hệ thống giám sát chỉ thực sự có giá trị khi nó mang lại sự tin cậy. Nếu hệ thống liên tục phát ra cảnh báo sai lệch hoặc gửi dồn dập hàng trăm tin nhắn khi có sự cố nhỏ, đội ngũ kỹ thuật sẽ rơi vào trạng thái mệt mỏi vì cảnh báo (Alert Fatigue) và có xu hướng tắt chuông thông báo, dẫn đến nguy cơ bỏ sót sự cố nghiêm trọng thực tế.

Ngăn chặn "bão cảnh báo" do chập chờn mạng tạm thời

Trong môi trường Internet công cộng, một đợt nghẽn mạng cục bộ (Network Blip) kéo dài 3 đến 5 giây giữa VPS giám sát và trung tâm dữ liệu của ứng dụng là điều hoàn toàn bình thường.

Nếu cấu hình mặc định gửi cảnh báo ngay khi một lần ping thất bại (Retries = 0 hoặc 1), một đợt chập chờn mạng ngắn có thể kích hoạt hàng loạt tin nhắn "DOWN" cho toàn bộ 50 website, rồi 1 phút sau lại gửi tiếp 50 tin nhắn "UP".

Quy tắc cấu hình bộ lọc chống báo động giả:

  1. Số lần thử lại (Retries): Luôn đặt giá trị từ 2 đến 3 lần. Uptime Kuma chỉ được phép xác nhận một dịch vụ bị sự cố và gửi thông báo nếu dịch vụ đó thất bại 3 lần kiểm tra liên tiếp.
  2. Khoảng cách giữa các lần thử lại (Retry Interval): Đặt giá trị mặc định là 10 hoặc 15 giây. Thay vì chờ hết chu kỳ chính (ví dụ 60 giây), khi phát hiện lỗi lần đầu, hệ thống sẽ kiểm tra lại ngay sau 15 giây để xác thực sự cố một cách nhanh chóng.
  3. Thông báo nhắc lại (Resend notification every X times): Khi một website gặp sự cố kéo dài nhiều giờ (ví dụ đang trong thời gian bảo trì hệ thống), bạn không muốn Uptime Kuma spam tin nhắn vào nhóm chat mỗi 60 giây một lần. Hãy đặt thông số này ở mức 10 hoặc 20. Khi đó, nếu kiểm tra thất bại liên tục, hệ thống chỉ gửi tin nhắn nhắc nhở sau mỗi 10 hoặc 20 chu kỳ.

Sử dụng Proxy phân tán khi cần độ chính xác cao

Nếu bạn tự host Uptime Kuma trên một VPS đặt tại Singapore hoặc Tokyo, nhưng đối tượng giám sát là các hệ thống đặt tại Việt Nam, sự cố đứt cáp quang biển quốc tế có thể khiến Uptime Kuma báo toàn bộ website trong nước bị sập dù người dùng trong nước vẫn truy cập bình thường.

Để loại bỏ các cảnh báo sai lệch do vị trí địa lý của VPS:

  • Ưu tiên đặt VPS giám sát cùng vùng địa lý hoặc cùng nhà mạng với tệp khách hàng chính của hệ thống.
  • Sử dụng tính năng Push Monitor (Heartbeat thụ động): Thay vì Uptime Kuma chủ động gửi request đến server, bạn cài đặt một cronjob trên server ứng dụng định kỳ gửi một request ping về Uptime Kuma (curl -k https://kuma.example.com/api/push/key). Nếu sau 2 chu kỳ Uptime Kuma không nhận được tín hiệu push, hệ thống mới phát cảnh báo máy chủ gặp sự cố.

Bằng cách chuyển đổi cơ sở dữ liệu sang chế độ WAL, thiết lập chu kỳ dọn dẹp dung lượng tự động và áp dụng các thông số lọc cảnh báo thông minh, bạn có thể biến Uptime Kuma thành một hệ thống giám sát độc lập, ổn định và tin cậy cho toàn bộ hạ tầng dịch vụ nội bộ mà không tốn kém chi phí phần mềm định kỳ. Để hoàn thiện hệ sinh thái quan sát toàn diện cho máy chủ, bạn có thể kết hợp việc giám sát uptime này với hệ thống thu thập và quản lý log tập trung bằng Grafana Loki và Vector nhằm nhanh chóng đối soát log chi tiết khi phát hiện sự cố.

Nội dung hướng dẫn này có hữu ích với hệ thống của bạn không?

Chia sẻ bài viết hữu ích

Gửi bài viết này cho đồng nghiệp

Đọc tiếp

Bài nên đọc tiếp

Xem tất cả bài về Monitoring