服务器时间时间不一致导致的bug
产品中提供了一项“金币兑换的功能”,每天定时放出一部分奖品供用户兑换。程序运行一段时间后,发现每天都有20%左右的超额兑换。
服务器有两台Tomcat服务器和一台mysql 数据库组成。
发现问题后第一反应是: 兑换交易事务存在问题
检查发现数据库采用的时MyISAM表,这是一种不支持数据库事务的mysql引擎。
随后发现代码层的兑换功能采用了同步处理,那么理论上,超对数目应该不超过运行的JVM数量,这里就是tomcat实例的数量。
那么为什么超对了这么多呢?
软件工程师,单独重新部署了一套测试环境,开发人员和测试人员一起对测试环境进行了压力测试,但是均没有发生超对现象。
最后分析兑换的交易数据记录,发现有交易的兑换时间发生在兑换放开时间之前。
再结合代码,分析,有了以下发现:
- 兑换时,是通过查询已兑换记录条数来判断是否还有兑换额度的。
- 插入兑换记录时,兑换时间是以tomcat服务器的时间插入的。而上面查询兑换记录条数时,是按数据库时间来查询的。
服务器的时间比实际时间慢了10s,结果这十秒的兑换记录在数据库中变成了兑换开始之前的记录。最终导致库存超兑。
最后统一改为按数据库时间进行记录。随后的运行中再无发现超兑现象。当然,没有数据库的事务保证,多实例超兑一个的情况还是理论存在的。