原创: 码农翻身刘欣

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

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。

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

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

如果你觉得文章不错,欢迎关注 微信公众号 你是心跳


来源:本文分享来自 你是心跳

MySQL:缓存算什么东西?!的更多相关文章

  1. MYSQL内存--------启动mysql缓存机制,实现命中率100% 转

    虽然这个标题夸张得过了头,但此文很完整,值得学习.转自 http://www.yy520.net/read.php?278 myql优化,启动MySQL缓存机制,实现命中率100% 配置你的mysql ...

  2. MySQL缓存参数优化(转)

    MySQL 数据库性能优化之缓存参数优化 数据库属于 IO 密集型的应用程序,其主要职责就是数据的管理及存储工作.而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个IO是在 ...

  3. mysql 缓存机制

    了解mysql缓存吗(顺丰) mysql缓存机制就是缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要在再去解析.优化.执行sql. ...

  4. MySQL缓存分类和配置

    读书笔记,待补充完善 MySQL缓存分类 InnoDB缓冲池 InnoDB日志文件和MyIsAM数据的操作系统缓存 MyIsAM键缓存 查询缓存 无法手工配置的缓存,二进制日志,表定义文件的操作系统缓 ...

  5. MySql 缓存查询原理与缓存监控 和 索引监控

    MySql缓存查询原理与缓存监控 And 索引监控 by:授客 QQ:1033553122 查询缓存 1.查询缓存操作原理 mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节 ...

  6. MySQL缓存命中率概述及如何提高缓存命中率

    MySQL缓存命中率概述 工作原理: 查询缓存的工作原理,基本上可以概括为: 缓存SELECT操作或预处理查询(注释:5.1.17开始支持)的结果集和SQL语句: 新的SELECT语句或预处理查询语句 ...

  7. Mysql缓存的配置和使用

    在mysql服务器高负载的情况下,必须采取一种措施给服务器减轻压力,减少服务器的I/O操作.一般采用的方法是优化sql操作语句,优化服务器的配置参数,从而提高服务器的性能.Mysql使用了几种内存缓存 ...

  8. 如何用redis/memcache做Mysql缓存层

    方法一:直接用MysqlMysql有缓存,实现了类似的功能,如果需要缓存的东西很多,可以把缓存的内存设置大一点.这样的好处就是不用去控制缓存的失效,确保数据一致性. 方法二:启用用DAO框架的缓存比如 ...

  9. mysql缓存、存储引擎

    一.         mysql查询缓存 查询缓存不是mysql的子系统,却是查询优化和执行子系统不可缺少的组成部分.它不仅可以缓存查询结果,还可以缓存查询结果本身.如果某个查询的结果就在缓存里, 系 ...

随机推荐

  1. django 三种缓存模式的使用及注意点

    Django 缓存模式的使用(主要针对RestFul设计模式的项目) 有三种模式: 全站使用缓存模式(整个项目每个接口都会使用缓存,缺点:所以接口都无法实时性获取数据) 单独视图缓存模式(单个接口使用 ...

  2. 值得推荐的五大敏捷PHP开发框架

    各位开发者,对于在HTML中混乱使用PHP的人来说,我们给大家推荐几款PHP敏捷开发的框架,以及它们为什么能够流行. 在我们开始之前,先了解敏捷开发是个什么东东. 敏捷是一种软件开发方法,每次开发计划 ...

  3. JavaScript:鼠标拖拽效果

    (之前的那个模板方法模式实在没搞懂...等几天再去研究8) 预览效果: 限制拖动范围在视口内.调整窗口时自动居中... <!DOCTYPE html> <html lang=&quo ...

  4. Bootstrap字体无法显示

    下载的font文件没有放进你的项目文件里.

  5. nodeJs 控制台打印中文显示为Unicode解决方案

    在使用 NodeJs 采集其他网站网页时遇到的,在获取源代码后发现里面原来的中文被转成了 Unicode(UTF8) 编码的中文(如:&# [xxx]),这当然不是真正想要的中文实体 解决方案 ...

  6. 深度学习原理与框架- tf.nn.atrous_conv2d(空洞卷积) 问题:空洞卷积增加了卷积核的维度,为什么不直接使用7*7呢

    空洞卷积, 从图中可以看出,对于一个3*3的卷积,可以通过使用增加卷积的空洞的个数,来获得较大的感受眼, 从第一幅图中可以看出3*3的卷积,可以通过补零的方式,变成7*7的感受眼,这里补零的个数为1, ...

  7. 日常杂记——C#验证码

    随机生成验证码,不能以图片的形式存在,所以需要将验证码图片以MemoryStream形式存储在内存的流当中,但是在使用时发现使用PictureBox控件无法显示内存流,所以需要先将流转化为图片,才可以 ...

  8. Lombok使用简介

    1.在maven中加入Lombok引入 2.在开发环境中加入Lombok插件 3.在实体类的类名上增加注释@Date即可使用所有get,set方法

  9. Linux命令:let

    语法 let  expr [expr ...] 说明 计算c的算术表达式.详细说明请参考<Bash参考指南-6.5 shell算术运算>

  10. whereis命令详解

    1.简介: whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b).man说明文件(参数-m)和源代码文件(参数-s).如果省略参数,则返回所有信息. 和find相比,whereis ...