NTP 校时
2024-09-30 08:00:49 # Technical # NTP

什么是 NTP

NTP(Network Time Protocol)网络时间协议,是由 RFC 1305 定义的时间同步协议,用来在分布式时间服务器和客户端之前进行时间同步。NTP 是基于 UDP 报文进行传输,默认端口为 123

NTP 工作原理

现假设有客户端 A 和 B,同一时刻,A 的时间为:00:00:00 am,B 的时间为:01:00:00 am,A 需要将自己的时间与 B 的时间同步,同步过程如下:

  1. A 发送一个 NTP 报文给 B,报文带有它离开 A 时的时间戳,假设:00:00:00 am(T1)
  2. B 收到了 A 发送的 NTP 报文,B 加上收到报文时的时间戳,假设:01:00:01 am(T2)
  3. B 将 NTP 报文返回给 A,并加上报文离开 B 时的时间戳,假设:01:00:02 am(T3)
  4. A 收到 B 返回的报文,A 记录自己收到响应报文的时间,假设:00:00:03 am(T4)

此时,A 可以计算出 NTP 的发送延时以及与 B 的时间偏差:

NTP Delay = (T4 - T1) - (T3 - T2) = 2s

NTP Offset = ( (T2 - T1) + (T3 - T4) ) / 2 = 1h

实际过程中,A,B 之间会多次发送并响应 NTP 报文,以消除网络波动带来的影响

Java NTP 校时

Java 中可以通过 Apache Commons Net 库封装的 NTP 客户端进行请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class NTPTest {

public static void main(String[] args) {
// 微软网络时间服务器
String ntpServer = "time.windows.com";
NTPUDPClient client = new NTPUDPClient();
// 设置超时时间 10s,防止一直阻塞
client.setDefaultTimeout(1000);
client.open();
try {
InetAddress inetAddress = InetAddress.getByName(ntpServer);
TimeInfo timeInfo = client.getTime(inetAddress);
timeInfo.computeDetails();
TimeStamp timeStamp = timeInfo.getMessage().getTransmitTimeStamp();
Date date = timeStamp.getDate();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
// 网络时间
System.out.println(simpleDateFormat.format(date));
// 网络时间与本地时间的偏移
System.out.println(timeInfo.getOffset());
// 请求过程的延时
System.out.println(timeInfo.getDelay());
} catch (IOException e) {
// ...
}
client.close();
}
}

这里仅通过 Java 对本地时间与目标时间做一个偏移校验,不会将目标时间同步到本地时间,也不推荐使用 Java 同步操作系统的时间。

Ubuntu 配置 NTP

修改 NTP 配置文件

1
vim /etc/ntp.conf
1
2
3
4
5
6
# 指定阿里 ntp 服务器
server ntp.aliyun.com
# 当无法访问外网时,以当前服务器为时间同步服务器
server 127.127.1.0
# 设置层级关系
fudge 127.127.1.0 stratum 10

重启 NTP 服务

1
2
service ntp stop
service ntp start

查看 NTP 状态

1
ntpq -p

手动同步 NTP

1
2
# 手动同步微软网络时间
ntpupdate time.windows.com

:手动同步前需要停止 NTP 服务,否则报错:ntpdate[15310]: the NTP socket is in use, exiting

ntp.conf 配置释义

  1. pool :ntp 服务池,池中的服务器可以参与或不参与校时,由 ntpd 自己决定
  2. ***server host [ key n ] [ version n ] [ perfer ] [ mode n ] [ minpoll n ] [ maxpoll n ] [iburst]***:ntp 服务器
    • key: 所有发往服务器的报文包含有秘钥加密的认证信息,n是32位的整数,表示秘钥号
    • version: 表示发往上层服务器的报文使用的版本号,n默认是3,可以是1或者2
    • perfer: 如果有多个server选项,具有该参数的服务器优先使用
    • mode: 指定数据报文mode字段的值
    • minpoll: 指定与查询该服务器的最小时间间隔为2的n次方秒,n默认为6,范围为4-14
    • maxpoll: 指定与查询该服务器的最大时间间隔为2的n次方秒,n默认为10,范围为4-14
    • iburst: 当初始同步请求时,采用突发方式接连发送8个报文,时间间隔为2秒
  3. ***restrict [ default ] [ host ] [ mask ] [ ignore ] [ nomodiy ] [ notrap ] [ notrust ] [ nopeer ] [ kod ]***:限制
    • default: 对所有的计算机进行控制
    • host:对指定 host 的计算机控制
    • mask:对指定 ip 掩码的计算机控制
    • ignore: 拒绝连接到NTP服务器
    • nomodify: 客户端不能更改服务端的时间参数,但是客户端可以通过服务端进行网络校时
    • noquery: 不提供客户端的时间查询
    • notrap: 不提供trap远程登录功能,trap服务是一种远程时间日志服务
    • notrust: 客户端除非通过认证,否则该客户端来源将被视为不信任子网
    • nopeer: 提供时间服务,但不作为对等体
    • kod: 向不安全的访问者发送Kiss-Of-Death报文

ntpq -p 参数释义

ntpq -p

  • remote: 响应请求的NTP服务器的名称(IP地址或域名),带“*”的表示本地NTP服务器与该服务器同步
  • refid: 远程NTP服务器使用的上一级ntp服务器的IP地址
  • st: 远程NTP服务器的级别,由于NTP是层级结构,有顶端的服务器,多层的Relay Server再到客户端。所以服务器从高到低,级别可以设定为1~16级。为了减缓负荷和网络堵塞,原则上应该避免直接连接到级别为1的服务器
  • t: 本地NTP服务器与远程NTP服务器的通信方式。u:单播;b:广播;I:本地
  • when: 上次成功请求后到现在的秒数
  • poll: 本地NTP服务器与远程NTP服务器同步的时间间隔
  • reach: 这是一个八进制的值,用来测试衡量前八次查询是否成功和服务器连接。377表示都成功,0表示不成功
  • delay: 网络延时,单位为微秒(μs)
  • offset: 本地NTP服务器与远程NTP服务器的时间偏移,单位为毫秒(ms)。offset越接近于0,主机与NTP服务器的时间越接近
  • jitter: 查询偏差的分布值,用于表示远程NTP的网络延时是否稳定,单位为微秒(μs)