序:本周在工作中遇到了一些麻烦,解决过程比较曲折和辛苦,特此记录,留作经验供以后参考
发现问题:周一上班的时候,运营打电话来说,我们上个月做的一个活动感觉数据不对,商家过来投诉了。结果我数据库一查,数据还真有问题!这次的活动采用的是页面上使用缓存系统显示活动数值(总金额),同时在后台记录详细的每条活动数据的办法。每次用户发生业务行为的时候都会在后台的缓存的总金额上增加,同时记录这次行为发生的金额数。结果我周一把数据库的记录加一起来一算,发现和页面上缓存的总金额竟然差了将近一半!
解决的过程:
1.由于数据库记录了每次业务行为的具体数据,而且比缓存的总金额要多。我第一时间想到的就是缓存系统哪里出错了。于是我先去服务器上找日志,可惜的是活动时间过去太久,服务器上的日志已经没有当时的记录了(郁闷!)。于是我只能靠自己来找出当时的BUG了。
2.我想到在上线之前我已经在线下环境和预发环境做过测试,缓存的数据和数据库的数据是会保持一致的。难道是因为线上的环境有2台服务器,又或者是在高并发大数据的情况下,才会产生的错误,又或者是其中某一台服务器的缓存服务器发生故障了?(因为数值刚好差了近一半么,如果其中一台服务器的缓存出错了,数值就符合了)。于是我修改了代码,重现了当时的业务场景,结果发现在比较高的并发量的情况下,2台服务器均未出现缓存服务故障和数据库不一致的现象。之后我又询问了其它开发和缓存部门的人,确定了在当时的访问量下,缓存和服务器应该不会出现瓶颈。于是乎,我的假设失败了,BUG还是没找到。
3.在接下来的一天里,我详细检查了各个地方,进行了各种假设,均为能测出这个数据不一致的BUG。而且要命的是,我在服务器上模拟当时的场景也没有出现这个BUG。于是我想到,这个BUG可能是那种只有在特定时间或着条件下才会出现的状况。一般像这种情况的问题最难处置了,因为可能出问题的地方可能已经消失了,不知道什么时候又会出现。第二天,我正向运营主管反应这个情况打算放弃的时候,他告诉了我一个重要的线索!他说在活动结束前的时候,他发现活动的总金额有过突然减少的情况,这个情况是出乎我意料的。因为之前的一直以为是缓存系统哪里出问题,导致增加的计数器没起效果。但是他说总金额有突然变少过,我写的业务代码中根本没有减少金额的逻辑,也就不可能存在金额减少的情况。于是乎,我把侦查重点又转移到了缓存系统本身上去。因为既然我写的代码根本不可能导致总金额的减少,那就一定是缓存系统本身出了什么问题,才会出现这种金额减少的状况。
4.接来下,我与缓存系统的技术支持电话里确认。询问了到底什么情况下,缓存系统会有金额减少的状况发生。在给他展示了我的关键性代码之后,他告诉我,如果我存在缓存里的数值“丢失”的话,因为我在代码里没有做“防灾”处理,数值可能是会重新归零的。缓存数值的“丢失”!这是我在之前没有考虑过的情况,因为我之前询问过开发的前辈,他们说这套缓存系统十分的稳定,因此我就大胆的直接使用它进行了业务数值的展现。而且从缓存系统的监控里,我也找不到类似于缓存溢出的情况。后来这个缓存部门的技术支持告诉我,由于我使用的是一块公用的缓存服务器,即使我本身分配的缓存空间还很多,但是如果其它用户此时有很大的缓存进来的话,是有可能把我驻留在内存里的数值给“丢失”的。
5.到这里,我基本上就想通了。在我上个月活动的那几天里,由于缓存系统其它用户出现的某些大负载量的状况,把我保留在缓存系统里的业务数据(总金额)给弄“丢失”了。而我由于天真和大意,没有考虑到缓存系统数值丢失的状况,只是一味的往上加一,即使在缓存系统里的数值“丢失”归零之后。于是就出现了数值突然下降,最终和实际数值不一致的情况。找到了问题的原因,解决办法也很容易想到。就是在这个业务场景下,考虑到缓存可能“丢失”的情况,在每次给缓存加一的时候,先判断下缓存是否存在,如果不存在就去数据库里取当前记录的总值。
经验总结:
找BUG往往是程序员最痛苦的事情之一,而像我这次碰到的这种在某些情况下才会发生的BUG,就更是难以被发现和处理。这时往往就得像侦探办案似的,收集各种线索,进行各种假设。模拟业务场景,往往是程序员找出BUG,最常使用的手段,但当这次这种无法重现的场景出现的时候,就只能靠“线索”了。“线索”是指那些有用的信息,比如运营人员反映的数值突然下降过的事,比如日志和数据记录。这些平时看起来不重要的事物,在这时都有可能会变成有用的“线索”。所以平时保存日志和备份数据,还有监控记录,这些东西在分布式,大数据的系统下就变得很重要了。
另外,还有最重要的一点,就是对找“BUG'这件事本身的毅力也很重要,因为在找”BUG'的过程中,可能会四处碰壁,这时如果放弃了,那这个BUG就永远淹没成为过去了。但是如果你坚持下去,把他找出来,那你就能优化自己的代码和系统,对于自身也是技术的增长和经验的积累。