Redis使用场景系列文章目录
目录
前言
本系列文章基本参考付磊、张益军的《Redis开发与运维》。同时参考了网上其他的一些资料。
缓存能够加速应用的速写速度、同时降低后端后端负载,应用非常广泛。但同时也会对架构造成影响。本文尝试从多个方面来说明缓存使用技巧和设计方案。
一、缓存的收益和成本分析
1. 收益
- 加速读写
- 降低后端负载
2. 成本
- 数据不一致性:缓存层和存储层的数据存在一定时间窗口的不一致性,时间窗口跟策略有关。
- 代码维护成本:同时处理缓存层和存储层的逻辑。
- 运维成本:如Redis Cluster。
3. 场景
在明白了收益和成本以后,我们就能大概知道什么样的场景适合使用缓存,是收益大于成本的,比如:
- 开销大的复杂计算:以MySQL为例,一些复杂的操作或计算(如大量链表操作、分组计算等),如果不加缓存,不但无法满足高并发量,同时也会给MySQL带来巨大负担。
- 加速请求响应:如果QPS要求非常高,那么即使查询单条后端数据足够快,也依然可以使用缓存,比如Redis每秒可以达到数万次读写,批量操作也可以优化整个IO链的响应时间。
二、缓存更新策略
缓存中的数据通常都具有生命周期,需要在指定时间后删除或更新,以保证缓存空间在可控的范围。但缓存数据会和数据源中的真实数据有一段时间窗口的不一致,需要利用某些策略进行更新。
1.LRU、LFU、FIFO算法剔除
- 使用场景:缓存使用量超过预设的最大值。
- 一致性:清楚哪些数据是有算法决定的,一致性最差。
- 维护成本:无需开发人员维护,配置最大缓存和策略即可。
2.超时剔除
- 使用场景:业务可以容忍一段时间内缓存层数据和存储层数据不一致。
- 一致性:过期时间内存在一致性问题。
- 维护成本:不高,设置过期时间即可。
3. 主动更新
- 使用场景:数据一致性要求高,需要在真实数据更新后立即更新缓存。
- 一致性:一致性最高。
- 维护成本:比较高,需要开发者完成更新并保证更新操作的正确性。
三、缓存粒度控制
缓存时是缓存全部属性还是只缓存部分重要属性,需要从以下几个角度考虑:
- 通用性
- 空间占用:内存、网络、序列化反序列化的CPU等开销
- 代码维护
四、穿透优化
缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中。每次穿透都会导致存储层查询,加大后端存储负载,甚至宕机。
一般导致穿透有两个原因:
- 自身业务代码或数据出现问题
- 恶意攻击、爬虫等
1. 缓存空对象
第一次发生穿透时在缓存中存储空对象,以保护后端数据源。但这也会导致新的问题:
- 浪费空间,如果是恶意攻击就更加严重。一种应对方法是设置较短的过期时间
- 可能存在一段时间窗口的数据不一致,影响业务。可以利用消息系统或其他方式清除空对象
2. 布隆过滤器拦截
类似白名单,将所有有效数据存放在过滤器中,查询缓存时先查询过滤器,通过才会继续查询。对于数据命中不高、但相对固定、实时性低的应用场景比较适用,代码维护成本较高。
五、无底洞优化
缓存的无底洞现象是指当存在大量节点时,继续添加节点性能不升反降。这是由于键值数据库采用哈希函数将key进行映射,如果节点过多,批量查询时就需要更多的网络操作,而且网络连接增多,也会影响节点性能。解决办法一般为以下几种:
- 命令本身的优化
- 减少网络通信次数
- 降低接入成本,如使用长连、连接池,NIO等
命令、客户端连接就不多说了,说说网络操作次数。假设Redis批量获取那个字符串:
- 客户端n次get:n次网络+n次get命令本身
- 客户端1次pipeline get:1次网络+n次get命令本身
- 客户端1次mget:1次网络+1次mget命令本身
显然,针对单个节点批量操作优化方式就是mget,那么如果是RedisCluster,则需要另外的思路。
1. 串行命令
由于n个key是较均匀地分布在各个节点上,无法使用mget一次性获取,简单的方式就是逐次执行n个get命令,时间上虽然不是最有,但实现简单。
2. 串行IO
使用CRC16算法计算出散列值,再对16383取余算出slot值,通过smart客户端保存的slot和节点对应关系,就可以得到每个节点的key子列表,从而对每个节点mget,操作时间=node次网络+node次命令时间。如果节点数太多,也会存在一定的性能问题。
3. 并行IO
将串行IO的最后一步改为多线程执行,可以将网络时间缩短为O(1),当然也会增加代码复杂度。
4. hash_tag实现
hash_tag将多个ke强制分配到一个节点上,我们就可以根据业务需要决定数据的节点分配策略,将所需数据集尽可能放在同一个节点上,这样就完全可以当做单节点使用。但是需要注意数据量均衡问题。
六、雪崩优化
如果缓存犹豫某些原因不能提供服务,那么多有请求都会到达存储层,存储层调用量保证,最终级联宕机,这种情况就叫做缓存雪崩。解决办法一般是预防和熔断。
1. 保证缓存层服务高可用性
无需多言,高可用保证即使个别节点、机器甚至机房宕机,依然可以提供服务,只要缓存层服务不宕机,自然不会发生雪崩。
2. 依赖隔离组件为后端限流并降级
降级机制在高并发系统中也是非常普遍的,基本原则就是保证系统不会因为个别资源出问题而整个停摆。当然这其中会涉及到很多问题,比如资源池的开启关闭,阈值管理等等,可以依赖现有的管理工具。
3. 提前演练
上线之前演练缓存层宕掉后,应用及后端负载情况及可能出现的问题,准备一些预案。
七、热点key重建优化
缓存+过期时间可以满足大部分情况,但如果当前key是一个热点key,并发量非常大,而且重建缓存不能在短时间内完成,可能是一个复杂计算,那么在缓存失效期间,也可能导致系统崩溃。
这个问题本身并不复杂,关键是不能在解决问题的同时给系统带来更多的麻烦,所以一般要求减少重建缓存次数,且数据尽可能一致,以减少潜在风险。
1. 互斥锁
一次只允许一个线程重建缓存,其余线程等待。
2. 永远不过期
缓存层面不为key设置过期时间,但是功能层面会为每个value设计一个逻辑过期时间,超过改时间,会使用单独线程去构建缓存。这也会导致在重构缓存时,会出现数据不一致。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
1190

被折叠的 条评论
为什么被折叠?



