NTP 时间同步

words: 2.9k    views:    time: 12min

Network Time Protocol时间同步协议,运行NTP服务的设备可以作为客户端从NTP服务器同步时间,也可以作为服务器供其他NTP客户端来同步时间。

时间同步 ntp

ntp是NTP的一种实现,ntpdate是ntp中的一个工具,也可以用来从外部时间服务器同步时间,但是会造成时间的突变,对于线上环境不是一个很理想的方式;ntp则采用平滑的方式,但是缺点是慢,而且对于超过17分钟的间隔会拒绝更新。

ntpdate和ntp服务都使用udp123端口,同一时间只能有一个在跑。所以通常的做法是开机时使用ntpdate进行一次时间校准,然后使用ntpd服务进行持续的对齐。当然也可以关掉ntpd服务,直接使用crontab每分钟执行一次ntpdate操作。

Linux中安装ntp,可以下载离线安装包:https://pkgs.org/download/ntp ,然后主要就是修改下配置文件:/etc/ntp.conf

ntp.conf
  • driftfile /var/lib/ntp/drift

系统时间与BIOS时间的偏差记录,将自己主机的bios芯片震荡频率与上层的Time server频率比较,将误差记录在这个文件里

  • restrict address [mask mask] [flag][…]

address地址参数可以是IP或者域名,mask是子网掩码(默认:address 0.0.0.0,mask 0.0.0.0),其中IP也可以是default,表示所有的IP

通常配置是先禁止所有的权限,然后再开放指定的权限,比如

1
2
3
4
5
6
7
8
9
10
11
## restrict    default ignore
## restrict -6 default ignore
restrict default nomodify notrap nopeer noquery
restrict -6 default nomodify notrap nopeer noquery

## 开放本地环回接口所有权限
restrict 127.0.0.1
restrict ::1

## 允许192.168.1.0/24网段内主机进行时间同步
restrict 192.168.141.0 mask 255.255.255.0 nomodify notrap
  • server 时间源IP/域名 参数

fudge表示时间服务器的层次,stratum 0 表示为顶级;如果要向别的NTP服务器更新时间,请不要把它设为0

1
2
3
## 127.127.1.0表示以本机时间作为时间服务(内网服务一定要加上),prefer表示优先级最高
server 127.127.1.0 prefer
fudge 127.127.1.0 stratum 0
示例
  • server 192.168.141.13

根据上面的描述,修改服务端/etc/ntp.conf如下,然后重启:systemctl restart ntp

1
2
3
4
5
6
7
8
9
10
11
12
driftfile /var/lib/ntp/ntp.drift

server 127.127.1.0 prefer
fudge 127.127.1.0 stratum 0

restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited

restrict 127.0.0.1
restrict ::1

restrict 192.168.141.0 mask 255.255.255.0 nomodify notrap

通过netstat可以查看ntp服务的监听

1
2
3
4
5
6
7
8
9
root@ubuntu:~# netstat -nulp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 192.168.141.13:123 0.0.0.0:* 4401/ntpd
udp 0 0 127.0.0.1:123 0.0.0.0:* 4401/ntpd
udp 0 0 0.0.0.0:123 0.0.0.0:* 4401/ntpd
udp6 0 0 fe80::20c:29ff:fea2:123 :::* 4401/ntpd
udp6 0 0 ::1:123 :::* 4401/ntpd
udp6 0 0 :::123 :::* 4401/ntpd
  • client 192.168.141.21

对于客户端,只要改一下ntp服务的指向地址即可

1
server 172.16.141.22

如果觉得ntp同步时间太慢,可以关掉ntp,然后手动执行同步命令

1
ntpdate 192.168.141.13

也可以添加cron定时任务,每分钟执行一次

corntab -e
1
* * * * * /sbin/ntpdate 192.168.141.13

然后通过日志来查看定时任务执行情况

vim /var/log/cron
1
2
3
4
5
Nov 14 09:26:01 bogon CROND[2393]: (root) CMD (/sbin/ntpdate 192.168.141.13)
Nov 14 09:27:01 bogon CROND[2474]: (root) CMD (/sbin/ntpdate 192.168.141.13)
Nov 14 09:28:01 bogon CROND[2535]: (root) CMD (/sbin/ntpdate 192.168.141.13)
Nov 14 09:29:01 bogon CROND[2598]: (root) CMD (/sbin/ntpdate 192.168.141.13)
Nov 14 09:30:01 bogon CROND[2661]: (root) CMD (/sbin/ntpdate 192.168.141.13)

时间同步 chrony

chrony官网:https://chrony.tuxfamily.org

Chrony是NTP网络时间协议的另一种实现,与ntpd不同,它可以更快更准确地同步系统时钟,最大程度的减少时间和频率误差。ntpd的同步时间并不理想,有可能需要几小时来同步时间,而chrony只需要几分钟。并且chrony兼容ntp监听在udp123端口上,自己则监听在udp的323端口上。如果在chrony配置文件中指定了ntp服务器的地址,那么chrony就是一台客户端,会去同步ntp服务器的时间,如果在chrony配置了允许某些客户端来向自己同步时间,则chrony也充当了一台服务器。

  • chrony.conf
vim /etc/chrony.conf
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
29
30
31
32
33
34
35
36
37
38
# 时间服务器,这里127.0.0.1表示自己
# ibust 会在chrony启动的2秒内,去快速poll服务器4次来矫正当前系统时间
# prefer 优先使用指定的服务器
# minpoll 最小轮询时间服务器的时间间隔,比如6是2的6次方,也就是64秒
# maxpoll 同上,比如10,表示最大轮询时间间隔是1024秒
server 127.0.0.1 iburst

# chronyd程序的主要行为之一,根据实际时间计算出计算机增减时间的比率,然后记录到一个文件中,在系统重启后为系统做出最佳时间补偿调整。
driftfile /var/lib/chrony/drift

# 一般如果系统时钟跟时间服务器不一致,chrony调整的方式是慢慢增加,或慢慢减少,不会一步到位,直接去跟时间服务器对齐
# makestep 1.0 3 表示如果时间服务器跟系统时间相差超过1秒,那么就在下3个时钟更新中追上时间服务器,这样能快速追平时间,但会带来时间跳跃。
makestep 1.0 3

# 表示将系统时钟同步到主板的硬件时钟去,缺省情况下是11分钟同步一次
rtcsync

# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2

# Allow NTP client access from local network.
#allow 192.168.0.0/16

# Serve time even if not synchronized to a time source.
#local stratum 10

# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
#log measurements statistics tracking
  • chronyc

可以通过chronyc命令来查看时间同步情况

1
2
3
4
5
6
7
8
[root@bogon ~]# chronyc sources
210 Number of sources = 4
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- electrode.felixc.at 2 7 367 63 -2108us[-2493us] +/- 165ms
^- ntp6.flashdance.cx 2 7 377 8 -2077us[-2077us] +/- 85ms
^- ntp1.flashdance.cx 2 6 377 11 +1057us[+1057us] +/- 96ms
^* time.neu.edu.cn 1 6 377 13 -462us[ -896us] +/- 29ms

字段含义:

M:时钟源类型,^表示服务器,=表示二级时钟源,#表示本地连接的参考时钟

S:时钟源状态,*表示当前同步的源,+表示其他可接受的源,?表示连接丢失的源,x表示一个认为是falseticker时钟(即它的时间与大多数其他来源不一致),~表示其时间似乎具有太多可变性的来源

Name/IP address:时钟源地址

Stratum:时钟源层级,1表示本地连接的参考时钟,2表示通过第1层级计算机的时钟实现同步,依此类推。

Poll:时钟同步频率,以秒为单位,值是基数2的对数,不过chronyd会根据当时的情况自动改变轮询频率

Reach:时钟源的可达性的锁存值,当接收或丢失一次时进行一次更新,值377表示最后八次传输都收到了有效的回复

LastRx:从时钟源同步的最近一次时间,通常是几秒钟

Last sample:本地时间与时钟源的偏移量,方括号中的数字表示实际测量的偏移值,括号左侧表示原始测量值,这个值是经过调整以允许应用于本地时钟的任何偏差;括号右侧表示偏差值,+/-指示器后面的数字表示测量中的误差范围,+表示本地时钟快于时钟源

FAQ

date命令
  • 格式化时间:
1
date "+%Y-%m-%d %H:%M:%S"
  • 修改时间
1
2
3
4
## 修改时间
date -s 11:12:00
## 修改日期
date -s 07/13/2011
  • 查看时区
1
date -R
  • 修改时区

在/usr/share/zoneinfo/下面有很多时区文件,可以复制这些时区文件覆盖/etc/localtime,或修改链接/etc/locatime对应的文件

1
2
3
cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
cron表达式
  • 命令格式
1
{minute} {hour} {day-of-month} {month} {day-of-week} command

字段含义

1
2
3
4
5
minute:      4个合法字符:,.*/      取值范围:0~59
hour: 4个合法字符:,.*/ 取值范围:0~23
day-of-month:8个合法字符:,.*/?LWC 取值范围:0~31
month : 4个合法字符:,.*/ 取值范围:1~12,或JAN-DEC
day-of-week: 8个合法字符:,.*/?LWC 取值范围:1~7,或SUN~SAT,1表示周日,2表示周一,以此类推

字符含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
*:表示任意值,比如在{minute}域使用*, 就表示每分钟都会触发事件

?:只能在{day-of-month}和{day-of-week}两个域使用,也是匹配任意值,但实际不会。因为{day-of-month}和{day-of-week}会相互影响。
比如想在每月20日执行,不管20日到底是星期几,则表达式应该这样:13 13 15 20 * ? 其中最后一位只能用?,而不能使用*,如果使用*就表示不管星期几都会触发,但实际上并不想这样

-:表示范围,比如在{minute}域使用5-20,表示从5到20分钟每分钟触发一次

/:表示起始触发时间,然后每隔固定时间触发一次。比如在{minute}域使用5/20,表示第一次触发是在第5分钟,然后每20分钟触发一次,所以将在第25和45分别执行一次

,:表示枚举值,比如在{minute}域使用5,20,就表示在5和20分钟各触发一次

L:表示最后,只能在{day-of-month}和{day-of-week}两个域使用。如果在{day-of-week}域使用5L,就表示在最后一个星期四触发

W:表示有效工作日(周一到周五),只能在{day-of-month}域使用,系统将在离指定日期的最近的有效工作日触发事件。
例如:在{day-of-month}域使用5W,
如果5日是星期六,则将在最近的工作日,也就是星期五,4日触发。如果5日是星期天,则在6日(周一)触发;
如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。

LW:可以连用,表示在某个月最后一个工作日,即最后一个星期五

#:用于确定每个月第几个星期几,只能出现在{day-of-month}域,比如在4#2,表示某月的第二个星期三。


参考:

  1. https://www.zhaowenyu.com/ntp-doc/ntpd-conf.html
  2. https://blog.csdn.net/Victor2code/article/details/114091429
  3. https://rumenz.com/rumenbiji/linux-date-format.html
  4. https://www.mineor.xyz/posts/linux_cron/
  5. https://bajie.dev/posts/20211020-chrony/
  6. https://www.jianshu.com/p/303ff208f174