# 《Seckill秒杀系统》第31章:混合型缓存通用模型设计与实现

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)
课程视频:https://t.zsxq.com/12FSKCmni (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★★☆☆
  • 本章重点:设计并实现本地缓存+分布式缓存的混合型缓存通用模型,将缓存的数据模型抽象成通用的类模型,在模型设计上,就需要尽最大程度避免缓存击穿、缓存穿透和缓存雪崩的问题,并且要掌握在实际项目中设计缓存数据模型的方法和注意事项。
  • 课程视频:https://t.zsxq.com/12FSKCmni (opens new window)

大家好,我是冰河~~

秒杀系统要想抗住瞬时高并发、大流量的冲击,除了前置的流量管控、流量清洗和限流等措施外,就需要使用缓存,但是使用缓存又会带来一定的风险,比如:缓存击穿、缓存穿透和缓存雪崩的问题。一旦缓存出现问题,在高并发、大流量场景下,会为秒杀系统带来致命的影响。至于缓存中到底要存储什么样的数据,什么样的数据结构,这些都是需要经过精心设计的。

# 一、前言

使用缓存不仅仅可以提升秒杀系统的并发和性能,还能为秒杀系统抗住进入系统内部的大部分流量,但是如果对缓存使用不当,极有可能会出现缓存击穿、缓存穿透和缓存雪崩的问题,轻则系统宕机不可用,重则会为公司带来巨大的经济损失。所以,在缓存设计上,一定要避免缓存出现严重的问题而导致的一系列事故。

# 二、本章诉求

像秒杀系统这种承载高并发、大流量的系统,只是简单的将数据存储的缓存是远远不够的,缓存的数据模型是需要精心设计的,一方面缓存的数据结构要非常方便后续的业务开发和维护扩展,另一方面也需要尽最大程度避免缓存击穿、缓存穿透和缓存雪崩的问题。

所以,本章,我们就单独对秒杀系统中混合型缓存通用模型进行设计与实现。

# 三、缓存模型设计

为了有效避免缓存击穿、缓存穿透和缓存雪崩的问题,一个最基本的缓存设计就是从数据库中查询数据时,无论数据库中是否存在数据,都会将查询的结果信息缓存起来,并设置一定的有效期。后续请求访问缓存时,如果缓存中存在指定Key时,哪怕对应的Value值为空,也会将数据返回给客户端,客户端根据具体情况进行处理。

在缓存模型的业务设计上,如果从数据库中未查询到对应的数据,直接将null或者空字符串等保存到缓存中,一方面是在代码的可能读性上比较差,不便于后期的维护,另一方面对于混合型缓存的实现上缺乏有效的逻辑处理能力。所以,对于缓存的数据模型需要进行精心的设计。

本节,会从缓存通用模型设计与缓存流程设计两个方面对缓存模型进行设计。

# 3.1 缓存通用模型结构设计

在缓存通用模型的设计上,除了最基本的业务数据外,还会提供缓存业务数据是否存在、缓存版本号,后续是否需要重试的通用字段,并且具体的业务数据会通过一个泛型进行设计,总体上做到通用化设计与实现。

缓存通用模型的类结构设计如图31-1所示。


可以看到,在秒杀活动列表的缓存模型类结构设计中,包含两个类,分别是SeckillCommonCache类和SeckillBusinessCache类。其中SeckillBusinessCache是一个泛型类,并且会继承SeckillCommonCache类。

  • exist:boolean类型,表示缓存中是否存在具体的业务数据,true:缓存中存在具体的业务数据,false:缓存中不存在具体的业务数据。
  • version:Long类型,表示缓存数据的版本号,当接收到客户端请求数据时的版本号大于缓存中的版本号,则说明当前缓存中的数据失效,需要从数据库查询数据后更新到缓存,否则直接返回缓存中的数据。
  • retryLater:boolean类型,表示是否需要重试,当服务出现异常时,将此值设置为true,告诉客户端需要刷新缓存,客户端接收到需要刷新缓存时,静默处理,稍后重新请求接口即可。
  • data:泛型T类型,表示具体的业务数据,当从数据库中查询出的数据为空时,此字段为空,exist字段为false,表示缓存中不存在具体的业务数据。

这种设计能够实现无论数据库中是否存在要查询的数据,缓存中都会存在通用模型结构的数据,能够有效避免缓存穿透的问题,再加上缓存数据失效时,在程序上能够保证同时只能有一个线程去更新缓存中的数据,这就有效避免了缓存击穿和缓存雪崩的问题。

# 查看完整文章

加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码