前提介绍:
电商网站系统为了追求高并发性能,离不开缓存的设计,本文主要介绍系统中Redis的组件能力设计,介绍Redis缓存部分热点问题和解决方案。
Redis组件功能模块涉及Redis查询加载、逻辑过期时间设计、快速清理缓存、缓存数据库最终一致性、缓存预热等。
缓存热点问题有缓存穿透、缓存击穿、缓存雪崩、缓存热key问题、缓存快速扩缩容等方案。
某些业务场景会应用到全量缓存,Redis全量缓存组件设计含以下功能模块,避免章节过长,后续单独整理文章。
- 全量缓存应用背景介绍
- 全量缓存方案
- 全量缓存加载及进度监控
- 全量缓存异常监控及异常降级
- 全量缓存快速扩缩容
目录
一、Redis组件逻辑架构简单介绍
在介绍缓存功能之前,先简单介绍下Redis高可用架构设计,下图逻辑架构是结合Sentinel一起使用,实现Redis高可用,同时可支持多组Redis数据分片、同组Redis读写分离的功能。
- 业务系统初始化组件框架时会先去zookeeper平台上解析配置文件,并且跟zookeeper建立监听连接。
- 组件框架根据配置文件中的Sentinel信息,访问Sentinel集群,获取Redis服务器信息,完成框架连接池的搭建。此外,框架还与Sentinel集群建立监听连接,用于主从切换后,框架及时调整连接池。
- Sentinel集群中的每台Sentinel服务器会监听所有Redis服务器,当Redis主服务器出现网络异常或者宕机情况后,Sentinel成员之间通过投票协议,完成主从切换。
- 系统在访问Redis服务器时,框架会先路由到所在分片(shard),并根据读写分离策略,选择对应Redis服务器,通过连接池访问。
服务高可用:高可用方案采用“主从+Sentinel”模式。 框架则利用Redis中成熟的订阅功能去监听Sentinel集群中的消息,一旦出现主从切换,框架就会自动做出配置调整,保障服务的高可用性。
框架通过Sentinel来实现故障转移的整体方案说明:
应用的Redis服务器会以主-从(master-slave)为一组分为多组(shard),每组通过shardName注册到Sentinel集群系统中加以监控。框架初始化时,会通过配置文件中Sentinel的IP/Port信息与Sentinel系统建立连接,通过shardName从Sentinel中取到Redis的IP、端口、主从关系等信息,完成连接池的创建。当Sentinel 检测到某个主(master)停止服务后会启用从(slave)为新的主 (master),框架会通过与Sentinel的连接监听到主(master)的变化接着对连接池做一些处理,保证缓存服务高可用。
备注:虽然提供了高可用方案,但在故障转移时应用可能会抛异常,不可避免。此时写数据会出异常,但是数据不会丢失。由于在连接池主从信息重新初始化完成之前,写数据还是向原来的主机写入,但是此时Sentinel上这个机器已经是从机的角色。
二、Redis缓存查询加载、有数据更新的处理流程。
1、缓存查询加载通用的处理流程,是先查询Redis缓存,缓存没有从db查询并加载到缓存中,如果数据库查询的数据为空,避免频繁透库,也需要在Redis设置一个空标识(缓存穿透解决方案),缓存不存在设置的空标识过期时间需要单独控制,避免大量刷无效的数据导致内存使用率告警。
2、在新增更新数据的时候,要清理缓存,保证数据库和缓存一致,处理的方法是使用事务控制,在事务提交前删除redis缓存,如果是全量缓存,是在事务提交前设置缓存。
由于存在删除redis缓存之后,事务提交成功之前,有并发查询存在,导致加载脏数据,处理方案之一是新增缓存同步待处理表,在事务提交之前,插入一条缓存同步待处理数据,异步再清理一次缓存,保证缓存最终一致性。
其他处理方案:监听数据库binlog日志删除缓存;事务之外直接推送MQ监听删除;
三、Redis缓存结构设计注意点
设计Redis缓存结构,有一些注意项,要提前考虑好,避免后续业务量上升后再重构。常见的设计规范网上都有说明,不详细列出,下面只列出容易忽略的点。
缓存结构设计注意项:
- key长度在含义清晰的前提下尽量短,减少redis内存消耗。
- key前缀设计减少包含关系,避免在dump分析具体key占比的时候,不易区分。以下是举例,实际业务地址可能都是通用的。
缓存名称
缓存前缀
实例
主站地址缓存
ADR:
ADR:001
X业态地址缓存
XADR:
XADR:001
Y业态地址缓存
YADR:
YADR:001
- 缓存value存放的信息尽量少,非必须的基础字段,例如操作IP、更新时间等,无需加载到缓存中,缓存设计的目是高性能高并发,同时要考虑降低缓存内存占用,提升资源利用率。
- 缓存key的命名规范,可以参考网上阿里redis命名规范,要可读性好、简洁。
- 避免大hash,例如个人信息缓存是hash结构,field有基本资料、地址、头像、注册信息等,如果缓存内存占用上升,无法快速分析;并且不同field对应的场景不一样,需要设置的缓存过期时间也可能不一样。
…..
四、Redis逻辑过期时间的设计思路及解决的问题
Redis热点缓存key会有一个过期时间,到期后需要重新从数据库加载,但是由于业务版本迭代频繁,缓存也有可能出错,或者新增了业务,需要快速失效某个缓存key,在这种场景发生的时候,如何快速失效缓存,保证线上业务正常,我们引入了逻辑过期时间配置。
4.1 举例线上实际发生业务场景
系统有张第三方绑定关系表,该表存放的是所有第三方绑定关系,例如微信、头条、百度等,由于业务升级,原表结构模型已经不适合新的业务拓展,需要迁移到新表中。由于迁移数据量大,还涉及到很多的接口功能改造联调等,定的方案是根据第三方类型逐渐迁移改造。
使用大数据技术按照第三方类型迁移数据到新表,新表对应的Redis缓存value是所有第三方信息列表,如果当前的查询列表缓存的接口已经对外提供(同一个缓存key),缓存尚未过期,缓存和数据库是不一致的,切换开关后,缓存中没有新迁移的第三方类型绑定关系数据,就会导致缓存信息缺失,数据不准确,由于切换前没有考虑redis缓存和数据库数据不一致的问题,遇到这种问题后就无法及时处理,这种场景引入了缓存逻辑过期时间的设计,可以快速保障线上业务不中断。
4.2 缓存逻辑过期设计方案
4.3 缓存逻辑过期应用场景
场景A:快速处理生产缓存数据异常问题
- 逻辑过期时间设置为0,不经过Redis缓存,直接透库查询;
- 通过大数据快速清理缓存工具快速清理缓存;
- 重新懒加载或预热缓存,如果缓存加载代码也有问题,那只能修复代码后再加载了,前提是直接透库查询,系统能扛得住。
场景B:利用逻辑过期时间解决缓存雪崩问题
利用逻辑过期时间<缓存key过期时间,达到逻辑过期时间,当前请求正常返回,然后异步丢到线程池中,从db重新加载数据,线程池配置丢弃策略,控制db的压力,避免影响正常业务
五、Redis缓存大数据快速清理工具设计。
Redis缓存大数据清理工具,主要是为了可以快速清理缓存,有些业务迭代可能需要清理缓存,提供大数据清理的工具,可以快速清理。
六、Redis热点缓存预热
电商网站在大促活动节点,某些信息的调用量并发量大,需要提前把数据加载到缓存中,避免大促活动期间大量穿库导致db压力大而宕机,或者做某个抢购活动—例如抢茅台、抢华为手机,需要提前把活动资源加载到缓存中。