Sự cố lúc 3 giờ sáng bắt nguồn từ độ lệch 40ms
Sáu tháng trước, cluster CockroachDB gồm ba node của chúng tôi bất ngờ ngừng xử lý transaction và rơi vào trạng thái split-brain. Raft consensus bị timeout. Các tác vụ ghi dữ liệu theo lô bắt đầu báo lỗi transaction retry liên tục, và distributed tracing cho thấy các sự kiện downstream lại được ghi nhận trước cả API call gốc sinh ra chúng. Ban đầu chúng tôi nghi ngờ có lỗi hồi quy (regression) từ phía ứng dụng. Thế nhưng đồ thị telemetry lại phản ánh một thực tế hoàn toàn khác: clock skew giữa ba hypervisor bare-metal đã âm thầm vượt ngưỡng 38 mili-giây.
Cũng như phần lớn các đội ngũ kỹ thuật khác, chúng tôi từng cấu hình bản cài đặt Linux trỏ về các máy chủ upstream công cộng như pool.ntp.org. Các public pool này hoàn toàn đủ tốt cho laptop của lập trình viên hay các web worker thông thường. Nhưng chúng lại là mối rủi ro chí mạng đối với cơ sở dữ liệu phân tán, sổ cái tài chính và các pipeline kiểm toán tuân thủ vốn phụ thuộc nghiêm ngặt vào thứ tự đơn điệu (monotonic ordering).
Nguyên nhân gốc rễ: Vì sao Internet NTP không đáp ứng được hạ tầng production
Trong buổi post-incident review, chúng tôi đã chỉ ra ba điểm yếu cốt tử của việc đồng bộ thời gian qua internet:
- Độ trễ định tuyến bất đối xứng (Asymmetric Route Latency): NTP hoạt động dựa trên giả định thời gian truyền tải đối xứng — tức gói tin đi đến server từ xa và quay về với tốc độ y hệt nhau. Trên thực tế, các tuyến transit của ISP thay đổi liên tục. Một sự dịch chuyển peering ở cấp trung gian có thể làm lệch độ đối xứng khứ hồi từ 15 đến 45 mili-giây mà không hề làm rớt gói tin nào hay kích hoạt bất kỳ cảnh báo nào.
- Hiện tượng Jitter và Bufferbloat trong quá trình truyền tải: Đường uplink WAN bị nghẽn cùng tường lửa kiểm tra gói tin sâu (DPI) gây ra hiện tượng packet jitter. Vào giờ cao điểm buổi chiều, jitter quan sát được từ nguồn Stratum 2 dao động từ 8ms đến 24ms. Mức biến thiên này khiến việc đạt được độ ổn định cấp microsecond trở nên bất khả thi.
- Phụ thuộc nguy hiểm vào mạng bên ngoài: Các phân vùng cơ sở dữ liệu cô lập (air-gapped), vùng đạt chuẩn PCI-DSS và mạng SCADA không bao giờ nên mở kết nối outbound qua cổng UDP 123 tới các địa chỉ IP công cộng. Khi nhà mạng ISP của chúng tôi bị đứt cáp vào tháng 3, các node bị cô lập phải chạy dựa vào bộ dao động thạch anh chất lượng thấp trên bo mạch chủ, khiến đồng hồ trôi dạt tới 1,8 giây mỗi tuần.
So sánh các giải pháp
Chúng tôi đã đánh giá ba phương án nhằm loại bỏ hoàn toàn hiện tượng lệch xung nhịp từ nguồn bên ngoài trên cả hai trung tâm dữ liệu:
| Phương án | Độ chính xác điển hình | Chi phí phần cứng | Phụ thuộc WAN | Khả năng kiểm toán |
|---|---|---|---|---|
| Public NTP Pool | 5 – 50 ms | 0 USD | Yêu cầu kết nối liên tục 24/7 | Server bên thứ ba không xác thực |
| Thiết bị chuyên dụng trọn gói (Meinberg, Microchip) | < 500 ns | 3.500 – 12.000 USD | Không (khóa tín hiệu vệ tinh GNSS) | Firmware đóng gói độc quyền |
| Máy chủ Linux riêng biệt (GPS + PPS + Chrony) | < 1 µs (LAN: 15–30 µs) | 85 – 220 USD | Không (khóa tín hiệu vệ tinh GNSS) | Toàn bộ stack mã nguồn mở, dễ dàng kiểm toán |
Các thiết bị gắn rack thương mại có độ ổn định tuyệt vời, nhưng chi phí 8.000 USD mỗi thiết bị khi triển khai trên toàn bộ các tủ rack staging, edge và primary là khoản đầu tư rất khó thuyết phục. Việc tự dựng node bằng linh kiện phổ thông có sẵn trên thị trường đã mang lại độ chính xác tham chiếu dưới một microsecond với mức chi phí chỉ bằng 3%.
Cơ chế GPS PPS mang lại độ chính xác chuẩn Stratum 1
Hệ thống của chúng tôi kết hợp một mini-PC Intel N100 (hoặc Raspberry Pi 4) với module GNSS u-blox NEO-M8N trị giá 25 USD cùng ăng-ten active patch có từ tính 28dB. Kiến trúc này tách quá trình đồng bộ thời gian thành hai kênh riêng biệt:
Đầu tiên, các chuỗi ký tự ASCII NMEA tiêu chuẩn (chẳng hạn như $GPRMC) được truyền qua cổng nối tiếp serial UART ở tốc độ 9600 baud. Các câu lệnh này cung cấp mốc thời gian tổng quát (coarse time): năm, tháng, ngày, giờ, phút và giây. Tuy nhiên, bộ đệm serial làm phát sinh độ trễ dao động (jitter) từ 20 đến 100 mili-giây.
Thứ hai, module GNSS kích hoạt chân phần cứng Pulse Per Second (PPS). Xung vuông điện áp này chuyển đổi trạng thái chính xác đến từng nanosecond tại mỗi ranh giới giây UTC. Linux kernel bắt cạnh xung này thông qua ngắt phần cứng (hardware interrupt), bỏ qua hoàn toàn độ trễ điều phối tiến trình ở userspace. NMEA cung cấp ngày tháng lịch biểu; còn PPS mang lại nhịp tích tắc tuyệt đối chính xác.
Bước 1: Cài đặt kernel driver và các tiện ích
sudo apt update
sudo apt install -y pps-tools gpsd gpsd-clients chrony
Bước 2: Đấu dây và cấu hình Kernel PPS
Trên các máy tính nhúng đơn bo (SBC) như Raspberry Pi, hãy nối chân TX/RX của module vào cổng UART của bo mạch và chân PPS của module vào GPIO 18 (chân vật lý số 12). Thêm dòng sau vào /boot/firmware/config.txt:
dtoverlay=pps-gpio,gpiopin=18
Vô hiệu hóa console đăng nhập qua serial để tránh xung đột với dữ liệu GPS thô:
sudo systemctl stop [email protected]
sudo systemctl disable [email protected]
Trên server x86 có cổng COM serial 9 chân chuẩn, hãy nối chân PPS vào chân số 1 (Carrier Detect / DCD) và nạp module kernel line discipline:
sudo ldattach PPS /dev/ttyS0
# Hoặc nạp lúc khởi động qua /etc/modules:
sudo modprobe pps-ldisc
Khởi động lại máy chủ và kiểm tra tín hiệu PPS:
ls -l /dev/pps*
# Đầu ra: /dev/pps0
sudo ppstest /dev/pps0
Khi đầu thu đã khóa được tín hiệu vệ tinh, ppstest sẽ in ra các xung kích hoạt mỗi giây một lần với mức sai lệch chỉ ở ngưỡng vài nanosecond:
source 0 - assert 1718873042.000000028, sequence: 104 - clear 0.000000000, sequence: 0
source 0 - assert 1718873043.000000019, sequence: 105 - clear 0.000000000, sequence: 0
Bước 3: Cấu hình GPSD để đọc chuỗi NMEA
Chỉnh sửa file /etc/default/gpsd để mở luồng serial stream. Ở đây chỉ truyền giao diện serial; hãy để Chrony trực tiếp xử lý /dev/pps0 để tránh tranh chấp:
START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyAMA0"
GPSD_OPTIONS="-n"
Khởi động lại service và kiểm tra trạng thái khóa vệ tinh:
sudo systemctl restart gpsd
cgps -s
Hãy đảm bảo terminal hiển thị trạng thái 3D Fix ổn định, theo dõi tối thiểu 6 vệ tinh và chỉ số Time Dilution of Precision (TDOP) dưới 1.5.
Bước 4: Cấu hình Chrony làm Stratum 1 Daemon chuẩn
Chrony hiệu chỉnh đồng hồ hệ thống nhanh hơn nhiều so với ntpd truyền thống, đặc biệt là trên các workload ảo hóa. Mở file /etc/chrony/chrony.conf và thêm các quy tắc reference clock sau:
# Thời gian tổng quát NMEA serial qua bộ nhớ chia sẻ GPSD (SHM 0)
refclock SHM 0 refid NMEA offset 0.128 delay 0.2 noselect
# Đầu vào PPS trực tiếp từ kernel khóa vào giây NMEA
refclock PPS /dev/pps0 refid PPS lock NMEA precision 1e-9 poll 3 prefer
# Cung cấp thời gian cho các dải mạng subnet nội bộ của data center
allow 10.20.0.0/16
allow 192.168.10.0/24
# Tiếp tục phân phối thời gian chuẩn Stratum 1 ngay cả khi mất kết nối WAN uplink
local stratum 1
# Theo dõi độ trôi dạt và ngưỡng điều chỉnh bước nhảy thời gian
driftfile /var/lib/chrony/chrony.drift
makestep 0.1 3
rtcsync
Khởi động lại Chrony để áp dụng cấu hình mới:
sudo systemctl restart chrony
Bước 5: Kiểm tra độ lệch trong thực tế
Để daemon hội tụ trong khoảng hai phút, sau đó chạy lệnh:
chronyc sources -v
Đầu ra của bạn sẽ trông như thế này:
.-- Chế độ nguồn '^' = server, '=' = peer, '#' = đồng hồ nội bộ.
/ .- Chế độ thường, '?' = không tới được, '=' = đã khóa, '^' = không kết hợp.
| / .- Trạng thái '*' = tốt nhất hiện tại, '+' = kết hợp, '-' = không kết hợp,
| | / 'x' = có thể lỗi, '~' = quá biến thiên
MS Tên/Địa chỉ IP Stratum Poll Reach LastRx Mẫu gần nhất
===============================================================================
#? NMEA 0 3 377 4 -18ms[ -18ms] +/- 100ms
#* PPS 0 3 377 3 +6ns[ +8ns] +/- 380ns
Hãy chú ý ký hiệu #* cạnh PPS. Chrony đã chỉ định xung nhịp phần cứng làm nguồn tham chiếu chính. Độ lệch đồng hồ (clock offset) chỉ còn ở mức một chữ số nanosecond (+6ns) với độ phân tán ước tính dưới 400 nanosecond.
Sáu tháng trên Production: Những bài học đúc kết
Chúng tôi đã lắp ráp hai cụm máy Stratum 1 giống hệt nhau và đặt mỗi cụm ở một sảnh data center. Hiện tại, chúng chịu trách nhiệm đồng bộ thời gian cho 42 bare-metal hypervisor, 180 Kubernetes node và hàng chục switch top-of-rack của Arista. Dưới đây là những gì số liệu đo lường trong sáu tháng qua cho thấy:
- Độ lệch mạng LAN dưới 25 microsecond: Trên toàn bộ mạng 10GbE của chúng tôi, độ trôi dạt ở các client từ những đợt tăng vọt khó lường 15–40ms đã giảm xuống chỉ còn duy trì ổn định trong khoảng 18–24 microsecond. Các trường hợp rollback transaction phân tán do clock skew hoàn toàn biến mất.
- Failover WAN mượt mà: Khi tuyến cáp quang chính của chúng tôi gặp sự cố đứt suốt 4 tiếng do công trình đường bộ, hệ thống log nội bộ và nhịp heartbeat của Raft vẫn duy trì đồng bộ hoàn hảo. Không có bất kỳ node nào bị lệch nhịp.
- Vị trí đặt ăng-ten mang tính quyết định: Ban đầu chúng tôi gắn ăng-ten bên trong cửa sổ phòng máy chủ. Cốt thép bê tông cùng lớp kính phủ Low-E đã khiến số lượng vệ tinh bắt được tụt xuống chỉ còn 3 khi trời mưa ẩm. Sau khi dời ăng-ten ra lan can bên ngoài với tầm nhìn thoáng 360 độ, kết nối định vị đã ổn định liên tục ở mức 11 vệ tinh suốt 24/7.
Nếu bạn đang vận hành hệ thống lưu trữ phân tán, các cơ chế đồng thuận hoặc kiến trúc event-streaming đòi hỏi tính tuần tự nghiêm ngặt, đừng phó mặc sự ổn định của production cho các dịch vụ NTP công cộng trên internet. Một chiếc đầu thu GPS giá 85 USD, một buổi chiều cấu hình cùng với Chrony sẽ giải quyết triệt để và vĩnh viễn bài toán đồng bộ thời gian của bạn.

