当前位置:C++技术网 > 资讯 > 经验分享:mysql数据库查询缓存引发的问题

经验分享:mysql数据库查询缓存引发的问题

更新时间:2017-10-11 23:06:29浏览次数:1+次

    我们做的系统使用了最新的安全机制,然而在实际测试中发现有一个很奇怪的问题,有时候登陆成功,有时候又登陆不成功。我们重启了nginx、重启了uwsgi、重启了mysql,但是这个问题一直都会存在。
    问题的基本现象就是,前几次(可能是1次)登陆能够成功,然后后续的就会偶尔失败。再次重试,又可以成功。
    我们的登陆机制大概是这样的,首先我们会动态生成一个登陆码,然后将登陆码存到数据库中,然后再使用密码解密登陆码,最后得到真正的数据,传给服务器。服务器再查询数据库比对,如果一致,就登陆成功,如果不一致就登陆失败。
    注意,我这里只是大致描述一下流程,实际的登陆过程很复杂,安全措施做的很多。查了很久没有查出来具体原因。但是我知道有一个大致的方向,那就是缓存问题。而我通过分析这个现象,重启各个服务之后,开始登陆是可以的,但是随后就出问题,很可能是缓存的锅。但是为了确定问题确实如此,我们不能靠猜测,还需要找更多证据支持我们的推测。
    方法很简单,就是大量的测试,得到可靠的现象,寻找规律。同时我们打印日志,将登陆过程产生的数据都记录到日志文件里。然后从日志里寻找突破口。
    我们从大量的测试里就发现前面说的问题现象。然后从日志里发现了一些现象。登陆失败的必然不是第一次登陆,而且登陆失败时的登陆码必然是前面登陆过产生的登陆码,不会凭空产生。而这个登陆码可能是很早登陆的,也可以是前一次登陆的。这也就可以进一步验证缓存的问题。为什么登陆失败时获取的是以前登陆过的登陆码?我们的登陆码不会存在数据库以外的任何地方,而且数据库中就一个字段存储,下次登陆就覆盖。现在能够获取以前登陆的验证码,必然不是从现在的数据库里查到的。那么99%的可能就是缓存的问题。
    我再查了数据库的数据,通过日志可以发现数据库已经存入了最新的登陆码,然后再查看数据库的数据,也是最新的登陆码了。如此一来,100%确定了是缓存引起的问题。
    那么是什么缓存引起的呢?浏览器缓存?nginx缓存?uwsgi缓存?mysql缓存?
    浏览器缓存一般是缓存前端页面数据的,而我们执行的代码是后台服务器的代码,所以这个可以排除。nginx缓存,则有可能对访问的url的数据进行缓存。uwsgi缓存自然也有可能。mysql缓存对数据的缓存,可能性最大。因为这个本来就是纯粹的数据库的数据的缓存问题。
    我们没有特别去配置缓存,缓存是这些服务自带的。通过查询资料得知,mysql是自带缓存机制的。下面可以使用语句来查询数据库的查询缓存是否开启(此语句就和一般的sql语句一样查询即可):
SHOW VARIABLES LIKE '%query_cache%'
    查询后的结果如下图所示:
    经验分享:mysql数据库查询缓存引发的问题
    从图中可以看到,have_query_cache的值为YES,表示已经开启了查询缓存。为什么是查询缓存,而没有显示非查询缓存?非查询就是增删改,这个没法使用缓存哦。而查询是可以反复的查询,数据都可能不变的,所以可以使用查询缓存来加快查询速度。
    另外,query_cache_size的值是0,网上的资料说值为0表示查询缓存预留的内存为0,无法使用查询缓存。然而实际的测试结果却不是这样的。我查出来的值就是0,但是数据库却仍然有查询缓存。网上的资料仅供参考,请勿全信,一定要经过自己的实际测试去验证。毕竟数据库的版本不断的更新,有些资料是很早就有的,也就不适应了,所以也是需要你去甄别的。
    query_cache_type的取值分别为0(OFF 关闭)、1(ON 开启)、2(DEMAND 按需使用)。我们在图中就可以看到,结果是ON。
    确定了mysql数据库确实开启了查询缓存,也就验证了我的推测。Nginx和uwsgi的缓存,应该不至于会细化到一个具体的url,毕竟我没有去配置。所以mysql的缓存嫌疑就是最大的。
    既然是mysql数据库的缓存问题,那么解决办法有两个,要么就是关闭mysql的缓存机制,要么就是再需要的时候,清空缓存,然后再查询,这样就可以确保是直接查询的。如果直接关闭缓存机制,那么有些地方将会降低效率。我们如果只是局部不需要缓存,那就再局部刷新一下缓存好了。
    刷新缓存的方法也就是执行一句SQL语句而已,如下:
reset query cache
    我们在函数中,要使用非查询函数执行此语句,不要用查询函数执行此语句哦。清空了缓存之后,然后就可以按照正常的操作去查询了。
    更多mysql数据库缓存的操作,相信网上有很多,就不在这里多说了。
    写出来这个项目经验,是想告诉大家,这样的奇怪的问题,要想到缓存上面去。我们做开发,不仅仅局限于代码之中。而代码之外的各种问题,都可能导致程序不正常运行,这些就需要积累经验了。而分享者这个经验,就是让大家可以快速积累一些实际的开发经验,让开发工作更加顺畅。
    这个经验是花了我不少时间调试分析,最后总结而来,看似没有什么特别高深的技术,但是这是一个踩坑的经验。当你踩坑的时候,虽然是一个简单的问题,但是却可以花掉你大量的时间,这样就不值了。所以别小看这些经验,发挥作用的时候,无形之中就省去了大量的时间哦。