Lúc 2 giờ sáng, điện thoại rung lên — alert từ Grafana báo log timestamp của 3 server không khớp nhau, sai lệch đến 5 phút. Certificate TLS bắt đầu báo lỗi, cronjob chạy sai giờ, và database replica lag tăng đột biến vì binlog timestamp lệch pha. Tất cả chỉ vì time sync bị lỗi.
Đây là tình huống thật mình đã gặp khi quản lý cluster 15 server. Bài học rút ra: NTP không phải thứ “cài một lần rồi quên” — nó cần cấu hình đúng và monitor liên tục.
Tại sao time sync quan trọng đến vậy?
Không ít sysadmin xem NTP là optional — “server chạy được là ổn”. Nhưng clock drift âm thầm phá hoại hệ thống theo những cách rất khó đoán:
- Log không khớp: Trace incident mà log server A trước log server B 3 phút, không thể dựng lại flow được
- TLS certificate lỗi: TLS kiểm tra thời gian khi handshake — sai lệch quá 5 phút là reject ngay
- Distributed systems bất ổn: Kafka, Cassandra, etcd đều dựa vào time để đồng thuận và ordering
- Authentication thất bại: Kerberos token, JWT, OAuth đều có time window ngắn
- Cronjob chạy sai giờ: Backup chạy lúc peak hour vì giờ server lệch múi giờ
Hồi mới làm sysadmin, mình từng mất cả buổi chiều vì authentication fail giữa hai microservice. Log lật đi lật lại không thấy gì bất thường. Hóa ra JWT token bị reject vì server source và destination lệch nhau đúng 8 phút. Từ đó mình có thói quen: server mới lên, việc đầu tiên là check NTP.
chrony vs ntpd — Dùng cái nào?
Từ RHEL 7, CentOS 7, Ubuntu 16.04 trở đi, chrony là lựa chọn mặc định thay thế ntpd cũ. Lý do thực tế:
- Sync nhanh sau boot — thường xong trong vài giây, so với ntpd có thể mất vài phút
- Xử lý tốt hơn trong môi trường ảo hóa — VM thường bị clock drift nhiều hơn bare metal
- Footprint nhỏ — process memory dưới 5MB, phù hợp cả VPS 512MB RAM
ntpd vẫn dùng được. Nhưng chrony là default từ RHEL 7 và Ubuntu 16.04 trở đi, nên đây là thứ bạn gặp hàng ngày trên production.
Cài đặt chrony
Trên Ubuntu/Debian
# Cài đặt
sudo apt update && sudo apt install -y chrony
# Enable và start
sudo systemctl enable --now chronyd
# Kiểm tra status
sudo systemctl status chronyd
Trên CentOS/RHEL/Rocky Linux
# Cài đặt (dnf cho RHEL 8+, yum cho CentOS 7)
sudo dnf install -y chrony
# Enable và start
sudo systemctl enable --now chronyd
Một lưu ý trước khi bắt đầu: một số hệ thống cũ chạy song song cả ntpd lẫn chronyd — hai daemon này conflict nhau và cho kết quả không đoán được. Dọn dẹp trước:
# Kiểm tra ntpd có đang chạy không
sudo systemctl status ntpd
# Nếu có, tắt và khóa lại
sudo systemctl stop ntpd
sudo systemctl disable ntpd
sudo systemctl mask ntpd # Đảm bảo không tự start lại
Cấu hình chi tiết
File config chính: /etc/chrony.conf (Ubuntu: /etc/chrony/chrony.conf).
Cấu hình NTP client cơ bản
# NTP servers — dùng pool thay vì server đơn lẻ để có redundancy
pool 0.pool.ntp.org iburst
pool 1.pool.ntp.org iburst
pool 2.pool.ntp.org iburst
pool 3.pool.ntp.org iburst
# Nếu chạy trên cloud, ưu tiên dùng NTP của provider (độ trễ thấp hơn)
# AWS: server 169.254.169.123 prefer iburst
# GCP: server metadata.google.internal prefer iburst
# Drift file — lưu thông tin clock drift để sync nhanh hơn sau reboot
driftfile /var/lib/chrony/drift
# Cho phép step time nếu lệch quá 1 giây (chỉ 3 lần đầu sau khi start)
makestep 1.0 3
# Sync hardware clock (RTC)
rtcsync
# Log directory
logdir /var/log/chrony
Cấu hình NTP server nội bộ cho toàn cluster
Quản lý cluster nhiều server? Kiến trúc nên làm là:
- 1-2 server sync với NTP public (Internet)
- Tất cả server còn lại sync với NTP server nội bộ
Cách này giảm traffic ra ngoài và tránh phụ thuộc vào latency mạng công cộng. Trên NTP master server, thêm vào cuối /etc/chrony.conf:
# Cho phép client trong subnet này sync thời gian
allow 192.168.1.0/24
allow 10.0.0.0/8
# Nếu mất kết nối internet, vẫn serve time cho client bằng local clock
local stratum 10
Trên các server client, thay thế pool công khai bằng địa chỉ NTP nội bộ:
# Comment hoặc xóa các dòng pool.ntp.org
# pool 0.pool.ntp.org iburst
# Chỉ sync từ NTP server nội bộ
server 192.168.1.10 iburst prefer
server 192.168.1.11 iburst # Backup
makestep 1.0 3
driftfile /var/lib/chrony/drift
rtcsync
Sau khi chỉnh config, restart service:
sudo systemctl restart chronyd
Firewall — hay bị quên nhất
NTP dùng UDP port 123. Nếu setup NTP server nội bộ, mở firewall cho client kết nối vào:
# Ubuntu với ufw
sudo ufw allow 123/udp
# CentOS/RHEL với firewalld
sudo firewall-cmd --permanent --add-service=ntp
sudo firewall-cmd --reload
Kiểm tra & Monitoring
Kiểm tra trạng thái sync ngay sau khi cài
# Xem danh sách NTP sources và trạng thái
chronyc sources -v
Output mẫu:
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.example.com 2 6 377 43 +12us[ +34us] +/- 456us
^+ ntp2.example.com 2 6 377 44 -8us[ +12us] +/- 234us
Ý nghĩa ký tự đầu dòng:
*= Source đang được dùng (best)+= Source tốt, đang được combine?= Không reach được — cần debug ngayx= Time có thể bị lỗi — bỏ qua source này
# Xem tracking info — offset hiện tại và stratum
chronyc tracking
Reference ID : C0A80101 (192.168.1.1)
Stratum : 3
System time : 0.000012345 seconds fast of NTP time
Last offset : +0.000008234 seconds
RMS offset : 0.000015678 seconds
Frequency : 12.345 ppm fast
Leap status : Normal
Con số cần quan tâm là System time (offset). Dưới 100ms là chấp nhận được, dưới 10ms là tốt. Chạy distributed database như etcd hay Cassandra? Cần dưới 1ms — không phải khuyến nghị, đó là yêu cầu.
Script check offset và alert
Mình hay dùng script nhỏ này trong cron hoặc tích hợp vào Nagios/Zabbix:
#!/bin/bash
# /usr/local/bin/check-ntp-offset.sh
THRESHOLD=0.5 # seconds — alert nếu offset > 500ms
offset=$(chronyc tracking | grep "System time" | awk '{print $4}')
offset_abs=$(echo "$offset" | tr -d '-')
if (( $(echo "$offset_abs > $THRESHOLD" | bc -l) )); then
echo "CRITICAL: NTP offset ${offset}s vượt ngưỡng ${THRESHOLD}s"
exit 2
else
echo "OK: NTP offset là ${offset}s"
exit 0
fi
chmod +x /usr/local/bin/check-ntp-offset.sh
/usr/local/bin/check-ntp-offset.sh
Debug khi chrony không sync được
chronyc sources toàn dấu ? là dấu hiệu rõ nhất của sự cố. Hai nguyên nhân chiếm 90% trường hợp: firewall chặn UDP 123 hoặc DNS không resolve được. Kiểm tra lần lượt:
# Xem log real-time
sudo journalctl -u chronyd -f
# Test reach NTP server
ntpdate -q 0.pool.ntp.org 2>&1 | head -5
# Kiểm tra DNS
nslookup 0.pool.ntp.org
# Force sync ngay lập tức (dùng khi offset lớn cần fix nhanh)
sudo chronyc makestep
Checklist setup NTP trên server mới
- Cài chrony, kiểm tra và tắt ntpd nếu đang chạy
- Cấu hình pool NTP phù hợp (ưu tiên NTP của cloud provider nếu đang trên cloud)
- Nếu có cluster: setup 1-2 NTP server nội bộ, các server còn lại sync từ đó
- Mở firewall UDP 123 trên NTP server nội bộ
- Verify bằng
chronyc sources -vvàchronyc tracking - Thêm monitoring để alert khi offset vượt ngưỡng
Lần tới khi onboard server mới vào cluster, check NTP ngay từ đầu — đừng để đến 2 giờ sáng mới phát hiện như mình đã từng.

