背景
最近在开发的过程中,遇见一个服务器时间不正确而导致的数据查询结果不正确的问题。代码(使用Springboot的web应用)大概如下:
......
......
......
private MessageCenterService messageCenterService;
public List<Message> getMessageInOneMonth(String userId) {
//现在
LocalDateTime now = LocalDateTime.now();
//一个月之前
LocalDateTime oneMonthBefore = now.minusMonths(1L);
return messageCenterService.getMessage(userId, oneMonthBefore, now);
}
......
......
......
MessageCenterService是另一个系统提供的服务,通过dubbo(使用zookeeper作为服务注册中心)来调用。getMessage方法定义如下:
interface MessageCenterService {
/**
* 获取指定用户某个时间范围内的消息
*
* @param userId 用户id(全局唯一)
* @param begin 时间下届
* @param end 时间上届
* @return
*/
public List<Message> getMessage(String userId, LocalDateTime begin, LocalDateTime end);
}
整个代码的逻辑就是调用第三方的dubbo接口来获取用户在某个时间段内的消息。
问题排查
在开发环境进行测试的时候发现调用getMessageInOneMonth获取某个用户最近一个月之内的消息时,能获取到较老的消息,但是刚刚创建的消息,无法用这个方法获取到。但是在我本地电脑进行测试的时候,刚刚创建的消息又是可以通过这个方法获取到的。
仔细检查了一遍自己的代码配置,自己本地电脑和开发环境用的配置文件都是一样的,都是配置的同一个zk,调用的MessageCenterService也是同一个,排除了被调用的第三方系统的影响。然后自己本地电脑中的项目代码和开发环境中的项目代码也是一致的,排除项目本身。
最后想来想去,代码中需要获取当前时间,可能就是在这个地方出了问题。查看LocalDateTime.now()的源码,获取当前时间,最终调用的是JDK的System.currentTimeMillis()来获取当前操作系统的时间,所以可能我们开发环境的LINUX服务器的操作系统时间不正确。
问题解决
登录到开发环境的LINUX服务器,执行date命令查看当前时间,确实比北京时间慢了4分钟左右,执行hwclock命令(hw是hardware,硬件的意思),查看服务器的硬件时间(即BOIS时间),和北京时间一致。
所以只要将Linux服务器操作系统的时间设置正确就行了,因为服务器的硬件时间是我们期望的北京时间,所以执行hwclock -s命令,将服务器的硬件时间同步到操作系统时间即可(如果要将操作系统时间同步到硬件时间可以执行hwclock -w,hwclock相关的更多命令,可以在linux上执行hwclock –help来查看)。