关于时区的概念,其实初中地理课已经涉及,很多人都多少了解一些,可能只是细节搞不太清楚。为什么会将地球分为不同时区呢?因为地球总是自西向东自转,东边总比西边先看到太阳,东边的时间也总比西边的早。东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算。整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal Time Coordinated)。UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同。
关于时间的几个标准,如下所示,具体可以Google、Baidu搜索一下。
CST:中国标准时间(China Standard Time),这个解释可能是针对RedHat Linux。
JST:日本标准时间(Japan Standard Time)。
UTC:协调世界时,又称世界标准时间,简称UTC,从英文国际时间/法文协调时间”Universal Time/Temps Cordonné”而来。中国大陆、香港、澳门、台湾、蒙古国、新加坡、马来西亚、菲律宾、澳洲西部的时间与UTC的时差均为+8,也就是UTC+8。
GMT:格林尼治标准时间(旧译格林威治平均时间或格林威治标准时间;英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。
关于时区分布图,大家可以参考http://www.timedate.cn/time/timezone.htm,我们国家跨越了东五区、东六区、东七区、东八区、东九区五个时区,一般都统一采用东八区计时时间。
Linux系统如何查看设置所在的时区呢?
1 2 3 4 |
$ date Wed Mar 29 10:31:55 CST 2017 $ date -R Wed, 29 Mar 2017 10:31:56 +0800 |
上面命令输出了+0800表示东八区,也就是我们国家的时间。相反,如果是-0800表示美国旧金山所在的时区,西八区。
我们在安装系统的时候,如果地区选择了Asia/Shanghai,那么系统的时区就是东八区。
Linux系统如何设置系统所在的时区呢?
方法一:使用tzselect设置时区
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
$ tzselect Please identify a location so that time zone rules can be set correctly. Please select a continent or ocean. 1) Africa(非洲) 2) Americas(美洲) 3) Antarctica(南极洲) 4) Arctic Ocean(北极洋) 5) Asia(亚洲) 6) Atlantic Ocean(大西洋) 7) Australia(大洋洲) 8) Europe(欧洲) 9) nIndian Ocea(印度洋) 10) Pacific Ocean(太平洋) 11) none - I want to specify the time zone using the Posix TZ format. #? 5 #这里选择亚洲 Please select a country. 1) Afghanistan 18) Israel 35) Palestine 2) Armenia 19) Japan 36) Philippines 3) Azerbaijan 20) Jordan 37) Qatar 4) Bahrain 21) Kazakhstan 38) Russia 5) Bangladesh 22) Korea (North) 39) Saudi Arabia 6) Bhutan 23) Korea (South) 40) Singapore 7) Brunei 24) Kuwait 41) Sri Lanka 8) Cambodia 25) Kyrgyzstan 42) Syria 9) China 26) Laos 43) Taiwan 10) Cyprus 27) Lebanon 44) Tajikistan 11) East Timor 28) Macau 45) Thailand 12) Georgia 29) Malaysia 46) Turkmenistan 13) Hong Kong 30) Mongolia 47) United Arab Emirates 14) India 31) Myanmar (Burma) 48) Uzbekistan 15) Indonesia 32) Nepal 49) Vietnam 16) Iran 33) Oman 50) Yemen 17) Iraq 34) Pakistan #? 9 #选择中国 Please select one of the following time zone regions. 1) Beijing Time 2) Xinjiang Time #? 1 #选择北京 The following information has been given: China Beijing Time Therefore TZ='Asia/Shanghai' will be used. Local time is now: Wed Mar 29 10:59:45 CST 2017. Universal Time is now: Wed Mar 29 02:59:45 UTC 2017. Is the above information OK? 1) Yes 2) No #? yes Please enter 1 for Yes, or 2 for No. #? 1 You can make this change permanent for yourself by appending the line TZ='Asia/Shanghai'; export TZ to the file '.profile' in your home directory; then log out and log in again. Here is that TZ value again, this time on standard output so that you can use the /bin/tzselect command in shell scripts: Asia/Shanghai |
注意:tzselect命令只告诉你选择的时区的写法,并不会生效。你可以在.profile、.bash_profile或者/etc/profile中设置正确的TZ环境变量并导出。 例如在.bash_profile里面设置 TZ=’Asia/Shanghai’; export TZ并使其生效。
例子,将系统时区设置为东九区(日本时间)
1 2 3 4 5 |
$ export TZ="Asia/Tokyo" $ date Wed Mar 29 12:05:46 JST 2017 $ date -R Wed, 29 Mar 2017 12:05:57 +0900 |
方法二:复制相应的时区文件,替换系统时区文件或者创建链接文件
在/usr/share/zoneinfo/下面有很多时区文件(跟tzselect显示的一样),可以复制这些时区文件覆盖/etc/localtime文件,或修改符号链接/etc/locatime对应的文件。
1 2 3 4 |
$ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime cp: overwrite ‘/etc/localtime’? y $ date Wed Mar 29 12:09:49 JST 2017 |
注意如果有时候,执行了上面命令后,使用date -R发现时区设置没有生效,有可能是因为你在profile或.bash_profile里面设置了TZ。
MySQL时区问题?
当MySQL的二进制日志格式为statement时,主从复制会因为时区的问题而造成数据不一致的的情况,具体可以参考一下这篇文章:故障案例–binlog_format不为row模式下关于时区设置的一个坑
首先查看MySQL的当前时区,用time_zone参数。
1 2 3 4 5 6 7 8 |
mysql> show variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | SYSTEM | +------------------+--------+ 2 rows in set (0.00 sec) |
可以看出MySQL默认是根据系统时区来的。
在线修改时区。
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 |
# 查看当前时间; mysql> select now(); +---------------------+ | now() | +---------------------+ | 2017-03-29 11:23:13 | +---------------------+ 1 row in set (0.01 sec) # 设置时区为东九区; mysql> set time_zone="+9:00"; Query OK, 0 rows affected (0.00 sec) mysql> show variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | +09:00 | +------------------+--------+ 2 rows in set (0.00 sec) # 查看当时时间; mysql> select now(); +---------------------+ | now() | +---------------------+ | 2017-03-29 12:23:24 | +---------------------+ 1 row in set (0.00 sec) |
配置修改时区
1 |
default-time-zone = '+8:00' |
修改完了记得记得重启MySQL。
关于时区的调优?
网上有两篇文章是说在默认time_zone=system下,使用timestamp字段在大量请求时引发的CPU SYS高的问题。
大概意思就是讲,对于使用timestamp的场景,MySQL在访问timestamp字段时会做时区转换,当time_zone设置为system时(默认),MySQL访问每一行的timestamp字段时,都会通过libc的时区函数,获取Linux设置的时区,在这个函数中会持有mutex,当大量并发SQL需要访问timestamp字段时,会出现mutex竞争。MySQL访问每一行都会做这个时区转换,转换完后释放mutex,所有等待这个mutex的线程全部唤醒,结果又会只有一个线程会成功持有mutex,其余又会再次sleep,这样就会导致context switch非常高但qps很低,系统吞吐量急剧下降。
总结下文章,就是当time_zone=system的时候,查询timestamp字段,会调用系统的时区做时区转换,有全局锁__libc_lock_lock的保护,导致线程并发环境下,系统性能受限。如果将time_zone=’+8:00’则不会调用系统时区,则不会触发系统时区转换,使用mysql自身转换,大大提高了性能。