• Redis做缓存的几种模式以及缓存雪崩、缓存击穿、缓存穿透分别是什么,怎么解决


    怎么做

    缓存可以建立在客户端也可以建立在服务端(注意这里是广义的客户端、服务端,服务A向服务B发请求,那么A就是客户端

    理论上来将每个服务端都应该给自己建立缓存,因为微服务要有一定的互不信任原则(请求先到你,你做过校验了,我不一定信)

    四种模式

    cache aside(旁路缓存)

    最常用方式,就是先去看缓存有没有,有就返回,没有就去数据库读。
    写的话直接写数据库去,然后删除缓存。
    为啥不更新缓存而是删除缓存? 因为更新容易造成时序性问题:
    thread1更新mysql为4 -> thread2更新mysql为2 -> thread2更新缓存为2 -> thread1更新缓存为4

    read through

    起一个中间服务,客户端就查你这个代理,不知道查的是缓存还是数据库。一切和缓存、数据库的交道都由这个代理来做。

    write through

    也是起了一个中间服务,只要发起写请求,代理就直接写数据库,然后同步更新redis。一般和read through搭配使用。
    但这个对缓存压力比较大,只要更新了数据就得一同更新redis,对比旁路缓存是删除缓存数据的

    write behind

    和write through一样,只不过写完数据库不立即写缓存,而是异步的写缓存(找一个合适时间点,比如低负载时候;或者累计几个一并写入)。

    缓存穿透

    缓存和数据库都没有这个数据,一般是被攻击了,有人频繁查询不存在的key。
    解决方法:

    • 接口层设置校验,key异常的直接拦截
    • 缓存和数据库都没有的数据,在缓存里写key-null,然后设置一个较短的过期时间,比如30s(防止之后真有这个key写进数据库了,缓存数据还是null)
    • 布隆过滤器。一个key会被多个hash函数映射,假设这些位置都被点亮认为这个数据可能是存在的,可以去数据库查一下。要是有的hash位置没被点亮,就是拒绝。这样对时间空间都好,就是不完全准确。

    缓存击穿

    缓存没有,数据库有。通常是某一时刻,一个热点数据过期,恰好此时并发用户特别多来访问这个数据,结果都打到数据库上了。
    解决方法:

    • 被持续访问的数据适当延长过期时间
    • 加互斥锁,多线程来发现缓存没有,就会竞争去数据库查。只有一个线程去查了,查完更新缓存,其他线程直接查缓存了就。

    缓存雪崩

    缓存没有数据库有。通常是缓存中大批数据同时过期了,而这时候大量查询过来了,让数据库压力过大甚至宕机。
    解决方法:

    • 设置随机过期时间,别一起过期
    • 加互斥锁,多线程来发现缓存没有,就会竞争去数据库查。只有一个线程去查了,查完更新缓存,其他线程直接查缓存了就。

    缓存一致性问题

    就是redis和mysql数据不一致了,主要有三种方式。但其实兜兜转转说一堆假设产品对一致性要求极高,尽量别用缓存

    mysql更新后不管redis,靠过期时间兜底

    实现起来成本低,但是这就得容忍一段时间的数据库和缓存不一致问题了。

    mysql更新后,操作redis

    操作分为两种一种是更新另一种是删除,更倾向于使用后一种。假设删除失败了,会退化成第一种方案。

    异步将mysql的更新同步给redis

    redis作为mysql一个slave,订阅mysql的binlog日志,解析日志后更新回redis。这种方式要搭建一个同步服务,成本大一点,但是解耦了,更新mysql后不需要做额外的工作,比较适合数据过期时间长甚至是不过期的场景(这是原因,是因为这种场景,才会用到这种订阅binlog模式)

  • 相关阅读:
    mysql操作
    View的绘制流程
    手机号码骚扰拦截
    基于Go语言Iris+Xorm搭建的Web项目框架
    一起看看Python中的迭代器&生成器
    域名解析常见问题(上)
    玩转Linux—如何在Linux环境中部署MySQL、Redis和nginx
    x64下隐藏可执行内存
    数据结构与算法八股文背诵版
    了解什么是JWT的原理及实际应用
  • 原文地址:https://blog.csdn.net/pige666/article/details/136249089