中间件之Redis应用场景及常见问题

一、数据一致性

1.缓存使用场景

针对读多写少的高并发场景,我们可以使用缓存来提升查询速度。

使用Redis作为缓存的流程

  1. 如果数据在Redis中存在,客户端可以直接从Redis中拿到数据,不用直接访问数据库。


    在这里插入图片描述
  2. 客户端新增数据,只保存到数据库中,如果Redis中没有,先到数据库查询然后写入到缓存,再返回给客户端


    在这里插入图片描述

2.一致性问题

因为数据一定是以数据库为准的,如果Redis中没有数据,就不存在这个问题。当Redis和数据库都有同一条记录,而这条记录发生变化的时候,就可能出现一致性问题。

当缓存的数据发生变化(修改、删除)时,我们纪要操作数据库中的数据也要操作Redis缓存的数据,才能保证缓存和数据库的数据一致。所以问题出现了:

  1. Redis中的旧数据删除还是更新?
  2. 先操作Redis再操作数据库
  3. 先操作数据库再操作Redis

(1)删除/更新

当存储的数据发生变化,Redis的数据也要更新的时候,我们有两种方案,一直是直接更新Redis数据,调用set;还有一种时直接删除Redis中的数据,客户端下次查询的时候重新写入。

首先需要考虑,更新缓存前是否要经过其他的各种操作,最后才能得到最新的数据,而不是从数据库直接拿到的值?基于这种复杂场景的考量,建议还是直接删除缓存,这种方案更加简单,而且避免了数据库的数据和缓存不一致的情况。

(2)先数据库后缓存

正常情况
更新数据库:成功
更新缓存:成功

异常情况

  1. 更新数据库失败,抛出异常,缓存不更新,不会出现数据不一致的额情况
  2. 更新数据库成功,删除缓存失败。数据库是新数据,缓存是旧数据,发生了不一致情况。

(3)先缓存后数据库

正常情况
更新缓存:成功
更新数据库:成功

异常情况

  • 删除缓存,程序捕获异常,不会走到下一步,不会出现数据不一致的情况
  • 删除缓存成功,更新数据库失败。因为以数据库的数据为准,所以不存在数据不一致的情况。
    但是当并发情况下:
    • 线程A需要更新数据,首先删除了缓存

    • 线程B需要查询数据,发现缓存不存在,到数据库查询旧数据,然后写入Redis返回

    • 线程A更新数据库
      这时候,缓存中是旧数据,数据库中是新数据,造成了数据不一致


      在这里插入图片描述

      最终方案
      双删,先删除Redis,再更新数据库,再删除Redis。

二、高并发问题

再Redis存储的所有数据中,有一部分是被频繁访问的。有两种情况可能导致热点问题。一是用户集中访问的数据,比如抢购商品,热点新闻等。还有一个是再数据进行分片的情况下,负载不均衡,超过了单个服务的承受能力。热点问题的出现可能会引起服务的不可用,最终造成数据库压力过大。

1.热点数据发现

首先Redis中有缓存淘汰机制,能够留下一些热点的Key,不管是LRU还是LFU

除了自动的缓存淘汰机制,如何找出访问频率高的key?

(1)客户端

在客户端,我们可以统计热点数据的访问频率。比如再所有调用get、set方法的地方加上key 的计数。
会导致的问题:

  1. 对客户端的代码造成入侵
  2. 不知道要存多少个key,可能会出现内存泄漏的问题OOM
  3. 只能统计当前客户端热点key

(2)代理层

可以使用Spring的AOP动态代理,来完成上面客户端的操作。但是如果项目中没有用到支持代理相关功能的框架呢?

(3)服务层

Redis中有一个monitor命令,可以监控所有Redis执行的命令


在这里插入图片描述

Jedis中也封装了相关API

jedis.monitor(new JedisMonitor(){
    @Override
    public void onCommand(String command){
        System.out.println("#monitor:"+command);
    }
})

(4)机器层面

通过TCP协议进行抓包,也有一些开源的方案供使用。

2.缓存雪崩

(1)什么是缓存雪崩?

当Redis大量热点数据同时过期,此时请求量又特别大,就会导致所有请求打到数据库中。

(2)解决方案

  1. 查询写入Redis时,相同的查询操作只允许一条请求访问到数据库,其他的等待,并访问Redis。
  2. 缓存定时预先更新,避免同时失效
  3. 通过加随机数,使key再不同的事件过期(梯度过期)
  4. 热点缓存不设置过期时间

3. 缓存穿透

当请求访问不存在的数据,会直接跳过Redis访问数据库,此时数据库中也不存在。

解决方案:1. 缓存空数据。2.缓存自定义特殊字符串
当这个请求再次进入系统时,会访问到自定义的特殊字符串,这时候系统就知道访问的是不存在的数据,直接返回静态资源404给客户端。

如果有恶意请求,发送大量不重复请求到服务端,虽然我们已经要写入自定义特殊字符到Redis,但由于它每次请求的key都是不同的,还是会给数据库造成很大的压力,占用数据库资源。

(1)经典面试题

如何在海量数据中,快速判断一个key是否存在?

首先我们想到的是先放入客户端缓存,避免请求服务端数据库及Redis。那么我们的基本数据结构能支撑这么大数据量吗,会发生OOM,内存溢出。

最节省空间的数据结构—位图。位图是一个有序数组,只有两个值,0和1。0代表不存在,1代表存在。


在这里插入图片描述

如何使用位图来做这个需求呢?

  1. 可以先将key做hash,再取模,获取到一个索引下标,将位图中对应的下标元素变成1
  2. 如果这样做,哈希碰撞的几率相当大,比如多个key哈希取模后下标一致,那么这些key是否真正存在呢?
  3. 可以将存在的key多个哈希函数运算取模放入位图中,比如key=java,第一次取模放在index=1,第二次取模放在index=5,第三次取模放在index=23,当这三个index对应的元素都为1时,我才大概率确认这个key确实是存在的。
  4. 当一个key经过三次哈希函数的运算后,生成的三个index中只要有一个index对应元素为0,那这个key必不存在
  5. 当一个key经过三次哈希函数运算后,生成的三个index对应元素都为1,那这个key大概率存在(不是百分百存在)

布隆过滤器
谷歌的Guava中提供了一个现成布隆过滤器,实现原理大致如上所述。可以直接拿来使用。

使用在访问Redis之前:

在这里插入图片描述
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 1. 简单介绍一下 Redis 呗! 简单来说 Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不...
    前端三少爷阅读 1,571评论 0 1
  • Redis 简介 数据库 redis数据在内存中,读写速度快,广泛用于缓存方向为什么要使用缓存(redis) ->...
    上山走18398阅读 367评论 0 1
  • Redis的那些最常见面试问题 随笔:经过长达一周的奔波和面试,电话面试,回首今天终于成功的入职了,总共面试了大概...
    伐无道阅读 409评论 0 1
  • 一、Redis是什么? Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消...
    AC编程阅读 401评论 0 5
  • 什么是Redis? Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息...
    零一间阅读 477评论 0 0