golang分布式服务部署的时区问题

场景:
发现部署在不同时区的服务对相同的数据库数据 返回不一致的结果

//结构体用的go的原生的time.Time 
//数据库存的是timestamp类型
type M struct {
    
    
	Description string    `gorm:"type:varchar(255)" json:"description" binding:"required"`
	Starttime   time.Time `gorm:"type:timestamp" json:"starttime" binding:"required"`
	Endtime     time.Time `gorm:"type:timestamp" json:"endtime" binding:"required"`
}

结构体用的go的原生的time.Time
数据库存的是timestamp类型


在对时间进行逻辑处理的时候 对用到的时间条件都进行了转UTC处理 心想不应该出现结果不一致的错误。

timeCondition := time.Now().UTC().String() > m.Starttime.UTC().String()

后来打印了一下m对象 发现从数据库读的m对象的时间字段都是CST的

{
    
      Description 2022-12-03 18:30:30 +0800 CST 2022-12-10 14:00:00 +0800 CST }

也就是说我再去将cst转为utc会减去8小时 这还得了,
于是考虑两个原因:一, 数据库时区设置有错,二, go程序读取数据库转为go对象的时候有错
由于我的数据库都是docker起的,在mysql和宿主机里都查了 就是UTC(mysql默认跟随宿主机时区)
(先决条件&知识:docker容器里的都是UTC时间)
那就是go程序读取数据库转为go对象的时候有错,为了验证这个猜想 决定在不同时区起服务进行实验:

实验数据库条件: 都是docker 起的数据库服务,且设置均为跟随系统时间 也就是docker容器的时区时间 都是UTC时间

实验后端服务条件:

墨西哥的服务:是用docker起的 为UTC时区时间

香港的服务:是用docker起的 手动将docker 容器时区修改为 毛里求斯+4 和 夏威夷 -10 进行测试

本地服务: goland里起的 也就是采用本地时区时间 即 北京时间 +8

测试结果:

墨西哥:在这里插入图片描述

夏威夷:
在这里插入图片描述

本机:在这里插入图片描述

实验结论:也就是说:读同一份相同的时间数据的时候 go程序会将其本身所运行在的系统的时区作为锚定时区,同样读一份时间数据,会将这份数据认为是其所在时区的此时此刻,也就产生了分裂和歧义。比如说实验中2022-12-02 16:38:14这串字符所代表的时间 本该是唯一的一个时刻,但是却被go程序误认为是其所在时区的2022-12-02 16:38:14这个时间,那么转换为UTC后 肯定就是不同的时间了。

对于跨时区分布式部署的服务器来说 这肯定是个大坑,除非你每个服务 都在docker容器里部署 或者 手动将不同时区的服务器调整成同一个时区时间,才能保证一致性。

另外 ,上边的实验和说法 也是建立在mysql数据库的时区是同一的情况下,假如go服务和数据库都是采用在服务器直接部署(而不是docker),各自为战,那么情况将更加混乱 ,连mysql中时间数据的字面值都会不一致,跟别说加上go程序的添乱。

解决方案:

1: 将全局时区修改为某一指定时区

//在main 函数里开头第一句 将全局时区修改为UTC时区
time.Local = time.UTC
//或者将全局时区修改为指定时区
loc, _ := time.LoadLocation("Asia/Shanghai")
time.Local = loc 

2: 或者采用另一种粗鄙却卓有成效的方式去记录时间:将时间戳存为int类型的值记录在数据库里!采用这种方式的公司大有人在。

猜你喜欢

转载自blog.csdn.net/qq_37106501/article/details/128168991