原创: 码农翻身刘欣

前言:上一篇《MySQL:缓存算什么东西?》里挖了一个坑,也有很多人说没看过瘾,今天接着写,把坑填上,不过得把视角换一下,让Redis上台发言。

我知道MySQL看我不顺眼,不就是他的好基友Tomcat不怎么搭理他了吗? 这能怪我? 谁让他那么慢?

张大胖把我Redis安排到这个系统中来,那就是为了提升系统的响应速度,我把数据都暂时放到了内存中,每当Tomcat需要的时候直接拿走就是了,都不用联系MySQL。只有我这里没有数据的时候Tomcat才会给MySQL说一句:“哥们,把这个SQL执行一下啊,把数据告诉我!”

MySQL不死心,不断使坏,总想着把我给干掉,恢复他昔日的荣耀和地位。可历史的车轮滚滚向前,想逆潮流而动,无异于螳臂挡车啊!

有时候我真想把我缓存中的数据删除,让高并发的访问都压到他那里去, 累死他! 可一想到自己的职业道德,尤其是张大胖那可怜样,还是忍了吧。

黑客攻击?

这一天中午,Tomcat发现流量有些异常,之前大部分的数据我都可以处理,这一次大量的请求在我Redis这里竟然获取不到数据! Tomcat被迫向MySQL求援:“哥们,这儿有一个SQL啊, 这儿还有一个, 又来一个......”

MySQL刚开始非常高兴,满心欢喜地去执行,可是他很快就发现事情不对, 执行完这些SQL,在数据库中也查不到数据。他不满地对Tomcat说:“兄弟,你这是在折腾我吗? 你看看你这个SQL中where ID = xxxx, 这些ID在数据库都不存在嘛。”

Tomcat头也不抬:“又来一个SQL, 还有一个......”

让我比较佩服的是, MySQL还是比较职业的,尽管有怨气,他还是不折不扣地执行,很快他就累到了。

整个系统慢如蜗牛,连正常的请求也处理不了。

张大胖赶紧介入,经过一番调查,他发现很多请求故意去查询那些一定不存在的数据,缓存中肯定没有,于是请求一定会发到MySQL去执行,在流量大时,MySQL就挂掉了。

换句话说:在黑客的精心算计之下,我这个缓存成了摆设,缓存被穿透了!

张大胖把此事定性为黑客攻击。

缓存空值

这一次,MySQL终于意识到了我的价值,他出了一个主意:“Redis同学,你把那些不存在的key和对应的空值也缓存下来不就行了?下次访问,就直接返回一个null给这些黑客,别再来找我了。”

我一听就知道这是个馊主意:“这些key在你那里都不存在,还让我缓存,那不就是要浪费我的空间吗? 张大胖给我分配的空间是有限的啊。”

“你不是可以设定数据的有效期嘛,比如过3分钟就过期,删除它,空间不就腾出来了。”

“那在这三分钟内,如果这个key对应的数据真的被加入到了你MySQL当中,那岂不就不一致了?!” 我问道。

MySQL说道:“如果发生这种情况,就可以想办法清除掉缓存中的数据,只是程序逻辑就变得复杂了......”

“退一步来说,假设我缓存了他们,那黑客完全可以换一些新的key来攻击啊!缓存中还是没有,还得去你那里查,这个办法不妥!”  我下了结论。

布隆过滤器

MySQL说:“如果能事先得知这个key是不是在数据库存在就好了,可是想知道是否存在,那就得把所有的key都放到缓存中,Redis,你能受得了吗?”

我当然受不了。

Tomcat眼前一亮:“你们听说过布隆过滤器没有?”

我说:“当然知道了,这是个神奇的数据结构,只需要极少的空间就可以判断一个元素是不是在一个集合之内,这正好是我们所需要的场景啊:判断key是否存在。”

(码农翻身注:布隆过滤器大家可以参考相关资料,这里不再展开。)

Tomcat说:“对,比如我们可以把所有的用户ID建立一个布隆过滤器,这样当那些黑客的请求过来以后,先用这个过滤器拦截一下,如果黑客要访问的用户ID不在这个过滤器中,我们就直接把他踢出去了。”

MySQL也是经验丰富:“可是这个Bloom Filter有误报啊,即使某个用户ID不在集合中,他也可能报告说在集合中。这个时候Tomcat就认为这是一个合法的用户ID,就去Redis中查,不存在,然后到我这里查,还是不存在。”

我说:“哎呀,一定的误报也是允许的,没有完美的事情,总要付出代价不是?”

大家都表示同意。

数据失效

黑客的攻击的威胁解除了,日子又恢复了平静,MySQL意识到了我的价值,也不再唠唠叨叨了。

我这个缓存的容量是有限的,不可能无限制地增加,所以张大胖添加到缓存的数据有一个有效期,过了有效期,我就会把他删除,腾出空间,让别的数据使用。

如果是普通的缓存数据失效,那就罢了,大不了从数据库中再去一次就是了。

可是这一次,有个超级热门的数据失效了,Tomcat组成的集群中有无数的线程都问我要数据,当我告诉他们这个数据已经失效以后,他们扭头便转向MySQL,疯狂地发出SQL语句,问MySQL要数据。

MySQL傻眼了,这么多的线程,每个要发出的SQL都是相同的,可是又不得不执行。

MySQL又一次累倒了,我想他再次体会到了我的重要性。

他对Tomcat说道:“兄弟,给我发这么多的一模一样的SQL,你想累死我啊! 你就不能控制一下?只让一个线程发查询过来,让其他的等待一下? 那个线程取到数据以后,其他线程就可以从缓存取了!”

Tomcat觉得很有道理,可是现在系统中有多个Tomcat,每个都是平等的,怎么去选出那个唯一的线程呢?

如果是在同一个JVM中还好办,轻轻松松用一把进程内的锁搞定, 可是这分布式的Tomcat,每个都是一个JVM,每个都是一个进程, 怎么搞?

我说:“这很简单,我Redis这里可以提供一个分布式的锁,谁获得了这把锁,谁就可以访问数据库。”

MySQL佩服地说:“老弟真是不错,我服了你了,以后你一定要尽可能的把流量都给挡住,别往我这里发了,实在是太可怕了!”

Tomcat补充到:“是啊,这Redis缓存太重要了!”

突然间他注意到了我还只有一台机器: “你现在怎么还是单台机器? 一个实例? 万一挂了怎么办? 一定得像我一样,搞集群,提高可用性啊!”

MySQL说:“啊? 这多吓人,从今天开始,我将时时刻刻为你祈祷,上帝保佑,你千万别挂掉。”

与此同时,张大胖开始着手Redis集群了......

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


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

Redis:MySQL算老几?的更多相关文章

  1. 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建

    从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...

  2. 从零开始搭建框架SSM+Redis+Mysql(一)之摘要

    从零开始搭建框架SSM+Redis+Mysql(一)之摘要 本文章为本人实际的操作后的回忆笔记,如果有步骤错漏,希望来信307793969@qq.com或者评论指出. 本文章只体现过程,仅体现操作流程 ...

  3. 基于Redis+MySQL+MongoDB存储架构应用

    摘  要: Redis+MySQL+MongoDB技术架构实现了本项目中大数据存储和实时云计算的需求.使用MongoDB切片的水平动态添加,可在不中断平台业务系统的同时保障扩容后的查询速度和云计算效能 ...

  4. 现在 做java 构架(RabbitMQ redis mysql )之类的

    现在 做java 构架(RabbitMQ redis mysql )之类的

  5. mongodb,redis,mysql的区别和具体应用场景

    一.MySQL 关系型数据库. 在不同的引擎上有不同 的存储方式. 查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高. 开源数据库的份额在不断增加,mysql的份额页在持续增长. 缺点就 ...

  6. Spark如何写入HBase/Redis/MySQL/Kafka

    一些概念 一个partition 对应一个task,一个task 必定存在于一个Executor,一个Executor 对应一个JVM. Partition 是一个可迭代数据集合 Task 本质是作用 ...

  7. nodejs + redis/mysql 连接池问题

    nodejs + redis/mysql 连接池问题 需不需要连接池 连接池的作用主要是较少每次临时建立连接所带来的开销.初步一看,nodejs运行单线程上,它不能同时使用多个连接,乍一看是不需要连接 ...

  8. nginx+play framework +mongoDB+redis +mysql+LBS实战总结

    nginx+play framework +mongoDB+redis +mysql+LBS实战总结(一) 使用这个样的组合结构已经很久了,主要是实现web-server,不是做网站,二是纯粹的数据服 ...

  9. redis+mysql读写方案

    前言:在web服务端开发的过程中,redis+mysql是最常用的存储解决方案,mysql存储着所有的业务数据,根据业务规模会采用相应的分库分表.读写分离.主备容灾.数据库集群等手段.但是由于mysq ...

随机推荐

  1. golang初识4 - Go 并发

    Go的CSP并发模型实现:M, P, G Go实现了两种并发形式.第一种是大家普遍认知的:多线程共享内存.其实就是Java或者C++等语言中的多线程开发.另外一种是Go语言特有的,也是Go语言推荐的: ...

  2. 试用 Angular v6 的 Ivy compiler

    “Ivy” 是 Angular v6 的新一代渲染器.从 v6.0.0-beta.1 开始,Ivy 已经作为体验 API 发布. 作为下一代的 Angular 的视图引擎,重点在于彻底缩减代码尺寸并增 ...

  3. 通过SQLServer的数据库邮件来发送邮件

    前段时间需要做一个发送邮件的功能,于是就花了一点时间研究了一下.发现通过SQLServer就可以发送邮件,只需要配置一下就可以了,而且配置过程很简单.下面来说一下配置过程: 1.启用Database ...

  4. jQuery属性操作总结

    jquery属性包括以下几个: attr(name|pro|key,val|fn) removeAttr(name) prop(n|p|k,v|f)1.6+ removeProp(name)1.6+ ...

  5. Hexo+Github博客最简教程-Dockerfile自动搭建

    闲谈 拿出你的气质,打开你的电脑,借你半小时搭建好属于你的hexo博客,小生用dockerfile自动帮你搭建好:你只需要在你的mac或linux或windows上提前把docker安装好,如何安装不 ...

  6. Golang 包管理简介

    Golang 包管理 在一个项目里,如果想引用本地包,经常会把新手搞的莫名其妙.这里通俗记录一下. 首先先要知道几个默认的规则 必须定义环境变量GOPATH,GOPATH可以定义多个目录 所有项目代码 ...

  7. verilog 介绍

    Verilog HDL Verilog HDL是在C语言的基础上发展起来的一种硬件描述语言,语法较自由.VHDL和Verilog HDL两者相比,VHDL的书写规则比Verilog HDL烦琐一些,但 ...

  8. JMETER之socket接口性能测试

    公司的**产品经过换代升级,终于要上线了,纯java编码,包括POS(PC/安卓平板)版.WEB版.微信版,各终端通过 Webservice服务共享数据资源,因此Webservice各接口的性能测试就 ...

  9. rest_famework 认证与权限组件

    定义个一个认证类 from rest_framework import exceptionsfrom rest_framework.authentication import BaseAuthenti ...

  10. (转)Android 只开启一个Activity实例

    在一个Activity中,多次调用startActivity()来启动另一个Activity,要想只生成一个Activity实例,方法有两种. 方法一:设置起动模式 一个Activity有四种启动模式 ...