Redis⑥ —— 缓存设计

1. 缓存雪崩

  • Redis会设置过期时间来保证缓存中的数据与数据库的数据一致性,当大量缓存数据在同一时间过期或Redis故障宕机,如果此时有大量用户请求都无法在Redis中处理,会直接全部请求访问数据库,导致压力骤增,从而形成一系列连锁反应造成整个系统崩溃

1.1 原因一:大量数据同时过期

  • 均匀设置过期时间
    • 可以在对缓存数据设置过期时间时,给这些数据的过期时间加上一个随机数,这样就保证数据不会在同一时间过期。
  • 互斥锁
    • 当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存,当缓存构建完成后,再释放锁。
  • 后台更新缓存
    • 业务线程不再负责更新缓存,缓存也不设置有效期,而是让缓存“永久有效”,并将更新缓存的工作交由后台线程定时更新
    • 缓存数据不设置有效期,并不是意味着数据一直能在内存里,因为当系统内存紧张的时候,有些缓存数据会被“淘汰”,而在缓存被“淘汰”到下一次后台定时更新缓存的这段时间内,业务线程读取缓存失败就返回空值,业务的视角就以为是数据丢失了。
      • 解决方法一:后台线程不仅负责定时更新缓存,而且也负责频繁地检测缓存是否有效
      • 解决方法二:在业务线程发现缓存数据失效后(缓存数据被淘汰),通过消息队列发送一条消息通知后台线程更新缓存
        • 在业务刚上线的时候,我们最好提前把数据缓起来,而不是等待用户访问才来触发缓存构建,这就是所谓的缓存预热,后台更新缓存的机制刚好也适合干这个事情

1.2 原因二:Redis故障宕机

  • 服务熔断或请求限流机制
    • 启动服务熔断机制,暂停业务应用对缓存服务的访问,直接返回错误,不用再继续访问数据库,从而降低对数据库的访问压力
    • 启用请求限流机制,只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到 Redis 恢复正常并把缓存预热完后,再解除请求限流的机制。
  • 构建Redis缓存高可靠集群

2. 缓存击穿

  • 缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮
  • 缓存击穿是缓存雪崩的一个子集
  • 解决方法:
    • 互斥锁
    • 不给热点数据设置过期时间,由后台异步更新缓存 或 在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间

3. 缓存穿透

  • 当用户访问的数据,既不在缓存中,也不在数据库中,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增。造成缓存穿透
  • 原因:
    • 业务误操作
    • 黑客恶意攻击

3.1 非法请求的限制

  • 当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在

3.2 缓存空值或默认值

  • 可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

3.3 使用布隆过滤器快速判断数据是否存在

  • 即使发生了缓存穿透,大量请求只会查询 Redis 和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis 自身也是支持布隆过滤器的。
  • 布隆过滤器由「初始值都为 0 的位图数组」和「 N 个哈希函数」两部分组成。查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据

4. 动态缓存热点数据的策略

  • 通过数据最新访问时间来做排名,并过滤掉不常访问的数据,只留下经常访问的数据
  • 以电商平台场景中的例子,现在要求只缓存用户经常访问的 Top 1000 的商品
    • 先通过缓存系统做一个排序队列(比如存放 1000 个商品),系统会根据商品的访问时间,更新队列信息,越是最近访问的商品排名越靠前;
    • 同时系统会定期过滤掉队列中排名最后的 200 个商品,然后再从数据库中随机读取出 200 个商品加入队列中;
    • 这样当请求每次到达的时候,会先从队列中获取商品 ID,如果命中,就根据 ID 再从另一个缓存数据结构中读取实际的商品信息,并返回。

5. 缓存更新策略

5.1 Cache Aside(旁路缓存)策略

  • 写策略:
    • 先更新数据库中的数据,再删除缓存中的数据
  • 读策略:
    • 如果读取的数据命中了缓存,则直接返回数据;
    • 如果读取的数据没有命中缓存,则从数据库中读取数据,然后将数据写入到缓存,并且返回给用户
  • Cache Aside 策略适合读多写少的场景,不适合写多的场景,因为当写入比较频繁时,缓存中的数据会被频繁地清理,这样会对缓存的命中率有一些影响。

5.2 Read/Write Through(读穿 / 写穿)策略

  • 应用程序只和缓存交互,不再和数据库交互,而是由缓存和数据库交互,相当于更新数据库的操作由缓存自己代理了
  • read through策略:
    • 先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用
  • write through策略:
    • 当有数据更新的时候,先查询要写入的数据在缓存中是否已经存在:
      • 如果缓存中数据已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中,然后缓存组件告知应用程序更新完成。
      • 如果缓存中数据不存在,直接更新数据库,然后返回;
  • 特点是由缓存节点而非应用程序来和数据库打交道

5.3 Write Back(写回)策略(Redis不适用,不能异步更新数据库)

  • 在更新数据的时候,只更新缓存,同时将缓存数据设置为脏的,然后立马返回,并不会更新数据库。对于数据库的更新,会通过批量异步更新的方式进行。
  • Write Back 策略特别适合写多的场景,因为发生写操作的时候, 只需要更新缓存,就立马返回了。
  • 问题是数据不是强一致性的,而且会有数据丢失的风险
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在使用Go语言中的Redis缓存时,可以按照以下步骤进行配置: 1. 首先,确保已经安装了Go Redis客户端库。可以使用"go get"命令安装: ``` go get github.com/go-redis/redis/v8 ``` 2. 在代码中导入Redis客户端库: ```go import "github.com/go-redis/redis/v8" ``` 3. 创建Redis客户端,并连接到Redis服务器: ```go client := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", // Redis服务器地址 Password: "密码", // Redis密码 DB: 0, // Redis数据库编号 }) ``` 4. 使用Redis客户端进行缓存操作。例如,设置缓存数据: ```go err := client.Set(ctx, "key", "value", 0).Err() if err != nil { // 处理错误 } ``` 5. 可以根据需要使用不同的Redis命令来操作缓存,比如获取缓存数据、删除缓存数据等: ```go value, err := client.Get(ctx, "key").Result() if err == redis.Nil { // 缓存数据不存在 } else if err != nil { // 处理错误 } else { // 处理缓存数据 } ``` 需要注意的是,以上是一个简单的示例,实际使用中可能需要更多的配置和处理。另外,为了提高性能和可靠性,可以考虑使用连接池、设置缓存过期时间等策略。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Golang Redis常用操作&结构体等缓存(redigo)](https://blog.csdn.net/weixin_44054396/article/details/120079694)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [Go项目优化——动态缓存Redis的使用](https://blog.csdn.net/weixin_52000204/article/details/127338089)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值