社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  DATABASE

MySQL:缓存算什么东西?!

码农翻身 • 7 年前 • 893 次点击  

十年前,我们还是一个企业内部的应用,用户不多,数据也不多。


Tomcat一天也处理不了多少请求,闲得无聊的时候只能和我聊天,这是没有办法的事情,因为整个系统只有我们两个:



没错,我就是大名鼎鼎的MySQL ,我和Tomcat位于不同的机器上,每次通信都是一次网络的请求。


这样的情况持续了三年,我们俩把话都快要说尽了的时候,人类终于送来了一个新家伙:缓存。


从外表看来,这个缓存就是一个Map而已, 保存的都是一些(key,value)这样的东西。


从内部看,他还真是个Map,是那个叫做张大胖的人类写的、一个线程安全的、可以设定过期时间的Map。


Tomcat和我都有点瞧不上他,觉得他实在是简陋,甚至难以成为一个独立的组件。


更让Tomcat不爽的是,这个简陋的家伙竟然和自己一起,共享JVM进程。



慢慢地事情发生了变化,张大胖改变了程序逻辑:在之前,用户的请求发到Tomcat这里,如果需要访问数据库的数据, Tomcat直接就把SQL语句扔给我来执行。


现在, 先要到那个Map,不,是缓存中查一下,看看有没有相关数据,如果有,直接就返回了,根本不用和我打交道; 如果缓存中没有,那才发出SQL查询,并且把缓存也给填充上,这样下次就不用访问数据库了。


Tomcat整天和缓存打交道,聊得热火朝天。 我观察了几天,终于明白这小子把我这个好基友给抛弃了。


Tomcat得意地对我说: “这缓存和我在一个进程中,访问起来速度快得很,立刻就能返回数据,哪里像你MySQL,慢慢悠悠地执行半天?! ”


说完他又做了一个总结:进程内调用就是好啊。


其实吧,缓存这小子的本质我比谁都清楚,我内部就有缓存啊,就是为了避免频繁地访问硬盘, 大家利用的都是序的局部性原理嘛,有什么神秘的?!


我耐心蛰伏,等待机会,准备一举把这个不知好歹的Map干掉。


从进程内到进程外


过了几个月,张大胖把系统的架构做了升级,为了应对高并发的访问,他用一个nginx来搞负载均衡,分发用户的请求,在后面搞了很多Tomcat和很多进程内的缓存,我们的系统变成了这个样子:


我一看就意识到我的机会来了:这缓存之间很容易出现不一致啊


比如: 用户的请求在JVM 1 中进行处理,MySQL做了更新,JVM 1中相关的缓存也做了更新或者被删除, 可是JVM 2和JVM 3中缓存的数据还是旧的啊。


不出我的所料,数据不一致的问题非常严重,用户频繁抱怨,缓存这小子这下要完蛋了!


可是缓存还想垂死挣扎,他说:”可以这样嘛,如果一个JVM中的缓存发生了变化,就通知其他JVM。”


可是通知总会有延迟,如果JVM 1还没来得及通知JVM 2和JVM 3, 而用户的请求已经在这两台机器上开始处理了,数据不一致还是存在。


特别是各个JVM之间需要来回交互,缓存的更新需要你通知我,我通知你,麻烦得要死。


Tomcat出了一个馊主意:“别让缓存互相更新,让缓存定时从MySQL那里更新!”


可是既然是定时更新,那缓存中的数据和我这里在某些时间段内还是会出现不一致。


除非数据的变化频率极低,否则这几乎是个无解的问题。


终于,张大胖如我所愿, 把进程内缓存给删除了!


我整打算好好跟Tomcat叙叙旧(这么多Tomcat啊!), 可是第二天他便弄来了一个新的家伙:Redis,还是缓存!


和之间那简陋的Map相比,Redis可是强大得太多太多了,这个缓存独自霸占了一台机器,让几个Tomcat都可以共享访问。


换句话说,缓存从进程内搬到了进程外!


我对Redis说:“你小子也需要网络才能访问了,和我差不多,有存在的必要吗?”


Redis说:“当然有了,虽然都是网络访问,但是我这里所有的数据可都在内存中啊,访问起来还是比你快。”


我承认,他说的是对的。


数据不一致


这天晚上,访问量突然间特别的大,是平时的百倍,不,千倍。 据Redis说,这是张大胖那家伙在搞压力测试了。


压力测试过后,一地鸡毛。 一盘点就发现,Redis的数据和我的数据居然发现了不一致。


Redis傻眼了,这是怎么回事?数据不一致,人类肯定以我MySQL的数据库数据为准啊。


Tomcat提示Redis:“估计是高并发惹的祸,我们看看是怎么更新数据的。”


Redis说:“简单啊,先更新MySQL,然后更新我的数据。”


Tomcat说:“这是两步操作,如果有两个线程都在这么干,就出问题了! 比如MySQL的有个值是100,现在线程1想把它改成200, 线程2想把它改成300。”


Redis说:“看来这里有个大漏洞啊,那怎么办?”


看着他们俩一筹莫展的样子,我忍不住说道:“这还不简单,当需要更新数据的时候,不要去更新缓存,把缓存中相关数据删除就行了。”



Redis说:“你这是官报私仇吧,把数据从我这里删除了,下次用户访问的时候没有,还得找你去要,对不对?”



我说:“是得找我要,但是能解决你的问题啊,两个线程同时写,不会出现数据库和缓存不一致啊。“


再说了,这其实不是我们能管的事情,咱们走着瞧,看看张大胖怎么做。”


第二天,张大胖果然按照我说的逻辑修改了程序,还美名其曰:Cache Aside Pattern


虽然我一直想把缓存干掉,可是,几天后的经历却深刻地教育了我,缓存还是必不可少的......


(唉,再挖个坑,主题估计你也想到了,就是缓存穿透,击穿,雪崩......)


(完)

码农翻身,用故事讲解技术本质, 更多精彩文章,请移步《码农翻身三年文章精华


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/axjoWwKYBs
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/25659