服务器时间偏差是基础设施里最容易被忽视、出问题后最难排查的故障来源之一。HTTPS 握手失败、Kerberos 认证拒绝、JWT 提前过期——这些表面上看起来毫无关联的问题,根源可能都是一台时钟偏了几分钟的服务器。
时间敏感型协议速览
| 协议 / 组件 | 时间容忍阈值 | 超出后果 |
|---|---|---|
| Kerberos | ±5 分钟(300秒) | Clock skew too great,认证完全失败 |
| TLS/HTTPS | 取决于证书有效期 | 证书报”尚未生效”或”已过期” |
| JWT | 由 exp 字段决定 | Token expired,需重新登录 |
| TOTP(动态验证码) | ±30 秒(一个时间窗口) | 验证码不匹配,登录失败 |
| AWS/阿里云签名 | ±5 或 ±15 分钟 | RequestTimeTooSkewed,API 调用被拒 |
| 日志时序 | 无硬性限制 | 多机日志时序乱,排查困难 |
国内公共 NTP 服务器
| 提供商 | 服务器地址 |
|---|---|
| 阿里云 | ntp.aliyun.com(推荐) |
| 腾讯云 | time1.cloud.tencent.com |
| 中国授时中心 | ntp.ntsc.ac.cn |
| 国家授时中心 | cn.ntp.org.cn |
| 国家标准时间 | time.windows.com(Windows 默认) |
配置时建议至少用 3 个服务器,NTP 协议用多数原则剔除异常节点。
chrony 配置(推荐)
/etc/chrony.conf:
# 至少配 3 个 NTP 服务器
server ntp.aliyun.com iburst
server time1.cloud.tencent.com iburst
server ntp.ntsc.ac.cn iburst
# 允许本地时钟作为最后备选(离线时不至于完全失效)
local stratum 10
# 记录时钟漂移
driftfile /var/lib/chrony/drift
# 允许的最大偏差(超过则拒绝同步,防止时间跳变)
maxdistance 1.0
常用命令:
# 查看同步状态
chronyc tracking
# 输出示例:
# Reference ID : 203.107.6.88 (ntp.aliyun.com)
# Stratum : 3
# System time : 0.000123456 seconds fast of NTP time ← 偏差
# Last offset : +0.000012345 seconds
# RMS offset : 0.000034567 seconds
# Frequency : 12.345 ppm fast
# 强制立即同步
chronyc makestep
# 查看 NTP 源列表和状态
chronyc sources -v
ntpd 配置(传统系统)
/etc/ntp.conf:
server ntp.aliyun.com iburst
server time1.cloud.tencent.com iburst
server ntp.ntsc.ac.cn iburst
driftfile /var/lib/ntp/drift
# 查看同步状态
ntpq -p
# 输出示例(* 表示当前主同步源):
# remote refid st t when poll reach delay offset jitter
# *ntp.aliyun.com 10.137.38.86 2 u 45 64 377 12.345 0.012 0.045
# 手动同步一次(ntpd 停止状态下)
ntpdate ntp.aliyun.com
Kerberos 时间同步实践
Active Directory 环境(Linux 机器加域):
# 确认 DC 时间
net time -S 域控服务器地址
# 同步到 DC(临时)
ntpdate 域控服务器地址
# 永久配置:把 AD DC 作为 NTP 源
# /etc/chrony.conf 加入:
server dc.yourdomain.com iburst
Kerberos 排查:
# 查看当前 ticket
klist
# 报错 Clock skew too great 时,先检查时间差
date && curl -s --head http://time.windows.com | grep Date
# 超过 5 分钟就需要同步
chronyc makestep
JWT 时钟偏差处理
签发方和验证方可能在不同服务器,各自时钟偏差叠加:
签发方快 2 分钟 + 验证方慢 2 分钟 = 有效期实际缩短 4 分钟
代码侧应对方案(以 Python python-jose 为例):
# 验证时允许 ±30 秒误差
claims = jwt.decode(token, key, algorithms=["HS256"],
options={"leeway": 30})
不要把 leeway 设太大(>5 分钟),否则失去 exp 的意义。根本解法是让所有服务器时间精确同步。
TOTP(动态验证码)时间窗口
Google Authenticator 等 TOTP 应用每 30 秒生成一个新码,服务端默认接受当前码和前后各一个码(±30 秒窗口)。
如果用户手机时间偏了超过 30 秒,验证码会持续失败。常见于:
- 手机长时间飞行模式后恢复
- Android 关闭了”自动时间同步”
排查:手机设置 → 系统 → 日期和时间 → 开启”自动设置时间”。
容器和虚拟机注意事项
容器(Docker):直接用宿主机时钟,不需要在容器内配 NTP
虚拟机(VMware/KVM):宿主机配 NTP,虚拟机通过 VMware Tools / virtio-ptp 同步
跨时区部署:所有服务器统一用 UTC,应用层处理时区显示
# 查看系统时区
timedatectl
# 设置为 UTC(推荐服务器统一使用)
timedatectl set-timezone UTC
# 设置为上海时间(面向用户的前端服务器)
timedatectl set-timezone Asia/Shanghai
配套工具
- 公共 DNS 速查 — NTP 走 UDP 123 端口,DNS 解析 NTP 域名走 53 端口
- TCP/UDP 端口表 — NTP 使用 UDP 123 端口
- 时间戳 — Unix 时间戳和 UTC 时间互转,排查 JWT exp 字段