DATE
背景
测一个mysql的mgr集群加入新的节点,但是系统时钟有差异的时候超过范围就拒绝该节点加入。
需要先了解下mysql的时间是怎么确认的。当服务器启动时,它会尝试自动确定主机的时区并使用它来设置 system_time_zone系统变量。全局 time_zone系统变量表示服务器当前运行所在的时区,初始time_zone 值为’SYSTEM’,表示服务器时区与系统时区相同。
我把实例部署在了docker上进行测试,容器中的时间和宿主机时间一致,但是拉起来之后容器用的是UTC时间,宿主机时间是CST。就是说看着就别扭,因此改了一下容器的时区。
登录容器执行
mv /etc/localtime localtime_bak
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
这样修改之后, 时区就会为CST的时区。下面还要介绍一些其他要用到的概念和命令。
-
linux 中的date命令
date命令的功能是显示和设置系统日期和时间。了解比较常用的参数就可以。需要特别说明的是,只有超级用户才能用date命令设置时间,一般用户只能用date命令显示时间。
如果需要以指定的格式显示日期,可以使用“+”开头的字符串指定其格式 date "+现在时间是: %Y-%m-%d %H:%M:%S" 还可以获取到微秒,但是无法到毫秒 date +%Y-%m-%d' '%H-%M-%S.%N 如果要获取毫秒可以cut一下 date +%Y-%m-%d' '%H-%M-%S.%N | cut -b 1-23 #date //显示当前日期 #date -s //设置当前时间,只有root权限才能设置,其他只能查看。 #date -s 20061010 //设置成20061010,这样会把具体时间设置成空00:00:00 #date -s 12:23:23 //设置具体时间,不会对日期做更改 #date -s “12:12:23 2006-10-10″ //这样可以设置全部时间
-
UNIX_TIMESTAMP()
Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)
是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.
一个小时表示为UNIX时间戳格式为:3600秒;一天表示为UNIX时间戳为86400秒,闰秒不计算。在mysql中,select UNIX_TIMESTAMP(); 可以看到当前实例的unix的时间戳。
select FROM_UNIXTIME(1623290216); 将 Unix 时间戳格式化为日期
-
LD_PRELOAD
LD_PRELOAD,是个环境变量,用于动态库的加载,动态库加载的优先级最高,一般情况下,其加载顺序为LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib>/usr/lib
程序中我们经常要调用一些外部库的函数,以rand为例,如果我们有个自定义的rand函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用rand函数时,调用的其实是我们自定义的函数。
这个命令:LD_PRELOAD=$PWD/unrandom.so ./random_nums
使用ldd可以查看在程序所加载的动态库。ldd random
man手册介绍
<span style="color:#000099;">A whitespace-separated list of additional, user-specified, ELF shared libraries to be loaded before all others.
This can be used to selectively override functions in other shared libraries. For set-user-ID/set-group-ID ELF binaries, only libraries in the standard search directories that are also set-user-ID will be loaded.
-
linux中各个系统目录的作用
/
根目录。包含了几乎所的文件目录。相当于中央系统。进入的最简单方法是:cd /。
/boot引导程序,内核等存放的目录。
/sbin超级用户可以使用的命令的存放目录。存放大多涉及系统管理的命令。
/bin普通用户可以使用的命令的存放目录。作为基础系统所需要的最基础的命令就是放在这里。
/lib根目录下的所程序的共享库目录。此目录下包含系统引导和在根用户执行命令时候所必需用到的共享库。类似于Windows上面的system32目录。这里存放的文件应该是/bin目录下程序所需要的库文件的存放地,也不排除一些例外的情况。类似的目录还/usr/lib,/usr/local/lib等等。
/dev设备文件目录。在Linux中设备都是以文件形式出现,这里的设备可以是硬盘,键盘,鼠标,网卡,终端,等设备。
/usr/local安装本地程序的一般默认路径。
/opt可择的文件目录。这个目录表示的是可择的意思,些自定义软件包或者第方工具
/var内容经常变化的目录。
/lib一般存放对于用户和系统来说“必须”的库(二进制文件)。
/usr/lib一般存放的只是对用户和系统来说“不是必需的”库(二进制文件)。
-
修改容器的时间
一般想到的就是登录容器,然后date -s 命令来修改时间,不过通过这种方式修改容器的时间,事实上同时把宿主机的时间也会修改了。如果这个宿主机上同时运行了其他的容器,那么这些容器的时间也会产生变化。这样无法实现单一容器时间差。可以使用libfaketime来“欺骗”一下系统。
LIBFAKETIME
libfaketime 可以安装在linux和macOS系统。它使用操作系统的预加载library机制,因此对于静态链接或setuid程序是不适用的。libfaketime在系统中使用信号量和共享内存,以便在父子进程中同步faketime设置。
看名字就知道属于lib,作用就是fake the time。libfaketime是一个库,用于修改docker容器时间而不影响宿主机的。它能够“覆盖”应用程序用来检索当前日期或时间的系统调用,并给这些调用提供伪造的值。它发布于github。
github地址
https://github.com/wolfcw/libfaketime
安装
git clone https://github.com/wolfcw/libfaketime
cd libfaketime
make make install
或者下载zip包,也可以
yum -y insall make gcc g++
wget https://github.com/wolfcw/libfaketime/archive/master.zip```
unzip master.zip
cd libfaketime-master
make && make install
使用
libfaketime有一个名叫faketime 的命令行wrapper,这样使用起来更方便,但是没有打开所有libfaketime的功能。如果你想使用的功能,faketime无法实现的话,可以具体查看使用说明来确认是否可以直接使用libfaketime来直接实现。
关于faketime的用法可以参考readme
https://github.com/wolfcw/libfaketime/blob/master/README
faketime可以用于和时间相关的各种场景:
1. 调试时间相关问题,如SSL证书过期等
2. 在未来的一个时间进行合规性测试,比如2038年
3. 固定构建过程会需要用到
-
基础的命令
faketime [options] timestamp program [arguments…]
-m use the multi-threading variant of libfaketime.
-f use the advanced timestamp specification format.
使用时候要确认两点
- 确认系统的加载器已经加载了libfaketime
- 定义好了想要fake到的时间
比较简单的一些用法
a) 如果你想固定系统时间,不让时间继续,需要指定完整的时间格式 “YYYY-MM-DD hh:mm:ss”
b) 如果你想指定系统时钟从某个时间开始,那么可以写成"@YYYY-MM-DD hh:mm:ss"
c) 如果和当前时间作比,那么可以以下可以参考
设置当前系统时钟为当前时间之后的1.5小时
FAKETIME=“+1,5h”
设置系统时钟为下一年,并且时间流逝x2
FAKETIME=“+1y x2”
设置系统时钟为下一年,并且时间流逝x0.5
FAKETIME=“+1y x0,5”
设置系统时钟为下一年,一次流逝2秒
FAKETIME=“+1y i2,0”
如果你不想设置时间,就想让时间流逝x2
可以设置 “+0 x2”,需要注意的是,使用x和i做偏移量设置时候,不能单独使用,需要指定时间,如果是当前时间,就设置为0就可以了。
设置系统时钟为当前时间之前的2.1s
export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1 FAKETIME="-2.1"
设置当前系统时钟为当前时间之后的1.5小时
FAKETIME=“+1,5h” 有的系统是逗号,有的是点号,根据具体情况设置
具体使用
在启动mysql服务之前,可以先设置docker内部的系统时钟,使用以下命令
export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1 FAKETIME="-1d"
改完查看系统时钟已经更改
[root@255eeda42cfd ~]# date
Fri Jun 11 17:00:26 CST 2021
[root@255eeda42cfd ~]# export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1 FAKETIME="-1d"
[root@255eeda42cfd ~]# date
Thu Jun 10 17:00:31 CST 2021
此时启动mysql节点,发现时间已经改变
[root@255eeda42cfd ~]# ps -ef|grep 3306
root 17114 13937 0 Jun11 pts/10 00:00:00 grep --color=auto 3306
[root@255eeda42cfd ~]# /usr/local/greatdb/bin/greatsqld_safe --defaults-file=/etc/greatdb/3306.cnf &
[1] 17115
[root@255eeda42cfd ~]# greatsqld_safe Adding '/usr/local/greatdb-cluster-5.0.6-28ab19eb10c-Linux-glibc2.17-x86_64/lib/mysql/libjemalloc.so.1' to LD_PRELOAD for greatsqld
2021-06-10T09:03:28.210448Z greatsqld_safe Logging to '/var/lib/greatdb/3306/255eeda42cfd.err'.
2021-06-10T09:03:28.234679Z greatsqld_safe Starting greatsqld daemon with databases from /var/lib/greatdb/3306
[root@255eeda42cfd ~]#
[root@255eeda42cfd ~]#
[root@255eeda42cfd ~]#
[root@255eeda42cfd ~]# h=`hostname -i`;p=3306;/usr/local/greatdb/bin/greatsql -h$h -ugreatdb -pgreatdb -P$p
greatsql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.25-15-greatdbcluster5.0.6-rc GreatDB Cluster, Release rc, Revision 28ab19eb10c
Copyright (c) 2009-2021 BEIJING GREAT OPENSOURCE SOFTWARE TECHNOLOGY CO.,LTD.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
GreatDB Cluster[(none)]> select now();
+---------------------+
| now() |
+---------------------+
| 2021-06-10 17:03:44 |
+---------------------+
1 row in set (0.00 sec)
------------分割线-------------------------------------------------------------
LIBFAKETIME 有很多人贡献了补丁来实现更多的功能。想要更复杂的实现可以在github上阅读readme文档。