20210605 缓存一致性方案

本文详细介绍了Redis的使用场景、速度优势及其背后的原理,包括单线程模型、内存操作和I/O多路复用。探讨了Redis的数据结构如String、Map、List、Set和SortedSet及其应用。接着分析了Redis的删除策略和内存淘汰策略,以及由此带来的数据一致性、缓存穿透、缓存雪崩和并发竞争问题。针对这些问题,提出了多种解决方案,如使用布隆过滤器、设置随机过期时间、消息队列确保最终一致性等。此外,还讨论了缓存更新策略,如先更新数据库再删除缓存以降低数据不一致风险。
部署运行你感兴趣的模型镜像

1,为什么要使用redis?

2,为什么redis速度快?

3,redis数据结构和使用场景?

4,redis的删除策略和内存淘汰策略

5,使用redis带来的问题?

1)数据一致性问题,2)缓存穿透问题,3)缓存雪崩问题,4)缓存并发竞争问题

 

1,为什么要使用redis?

性能和并发的角度:从缓存中读取,快速响应请求;使用缓存提高系统并发能力。

 

2,为什么redis速度快?

1)单线程操作redis,避免了频繁的上下文切换;

2)基于内存进行操作;

3)采用了非阻塞I/O多路复用机制;

 

3,redis数据类型和使用场景?

1)String 计数器,楼盘信息存储

2)Map 用户信息,用户id;

3)List集合 消息队列,先进先出特征;

4)Set集合功能:全局去重,通过redis做全局去重,集群模式部署,使用set集合,不太方便。利用交集、并集、差集等操作;

5)sorted set:权重,排行榜,可以按照评分进行排序。 对楼盘的访问频次进行统计,统计访问频次最高的哪些数据。

 

4,redis的删除策略和内存淘汰策略

Redis的过期删除策略(设置了过期时间的key)

1)惰性删除;访问删除。

2)定期删除;如果只采用定期删除策略,会导致很多key到时间没有删除。

过期策略的缺点:如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效,这样,Redis的内存会越来越高。那么就应该采用内存淘汰机制。

 

内存淘汰策略

如果没有设置 expire 的key,把这几种内存淘汰策略背下来。

1)noeviction:[ɪˈvɪkʃn] 当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。

2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。

3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。

4)volatile-lru:[ˈvɒlətaɪl]当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐

5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐

6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐

 

5,使用redis带来的问题?

缓存不一致问题

产生原因

1)多线程中,写和读是并发的,没法保证顺序。

2)如果是redis集群,或者主从模式,写主读从,由于redis复制存在一定的时间延迟,也有可能导致数据不一致。

实际业务上,我们更多的还是以DB数据为准,这种读取到旧数据的业务影响可能比读取到为未更新到DB的数据影响要小。

更新DB和操作缓存两个动作之间原则上是非原子性的,一个是更新DB,一个是更新redis。但是,通常我们使用一个妥协的方案,类似于分布式事务最终一致性的实现,这里也可以使用消息队列实现最终一致性的消息保证。

如果对数据不一致容忍度比较低,那么建议是采用先更新DB,后淘汰缓存方案。

这里只是简单方案分析,如果复杂点的场景,还需要考虑DB读写分离时,主从数据同步延时导致的缓存不一致。

1)Redis引起的缓存不一致问题(数据一致性问题)。缓存一致性其实是使用Redis造成的问题,这个是数据一致性问题,redis 可以做到最终一致性,而不是强一致性。

Redis保证的是最终一致性,不是强一致性。有强一致性的数据不能放缓存。

保证数据一致性的方案:

(1)先删除缓存,在更新数据库;但是存在事务没有提交,读取到旧数据的问题,高并发情况下这种情况出现的概率很高。

(2)先更新数据库,在删除缓存,但是存在缓存失效的问题;可以为缓存设置过期时间,并且可以使用消息队列进行补偿,保证数据的最终一致性。

针对不用的场景,使用不同的策略保证缓存的最终一致性。

(1)读取数据的场景(读取操作) 先读缓存,缓存不存在从数据库读取,然后在写入缓存响应数据。

(2)更新数据的场景(更新操作)先更新数据库,再删缓存。另外,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。(删除失败,数据不一致,需要补偿机制)

为什么是删除而不是更新缓存?

为什么最后是把缓存的数据删掉,而不是把更新的数据写到缓存里。这么做引发的问题是,如果A,B两个线程同时做数据更新,A先更新了数据库,B后更新数据库,则此时数据库里存的是B的数据。而更新缓存的时候,是B先更新了缓存,而A后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据也不一致。

解决方案大概有以下几种: 删除失败了怎么处理? 如何保证数据的一致性?

1. 对删除缓存进行重试,数据的一致性要求越高,我越是重试得快。

2. 定期全量更新,简单地说,就是我定期把缓存全部清掉,然后再全量加载。

3. 给所有的缓存一个失效期。这样最差的情况是在超时时间内,内存存在不一致。

第三种方案可以说是一个大杀器,任何不一致,都可以靠失效期解决,失效期越短,数据一致性越高。但是失效期越短,查数据库就会越频繁。因此失效期应该根据业务来定。

 

缓存穿透问题

1)使用bloomfilter解决。每秒百万级别的请求,一定要考虑这个问题。请求所携带的Key是否合法有效。如果不合法,则直接返回。

 

缓存雪崩问题

即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。

给缓存的失效时间,加上一个随机值,避免集体失效。

如何解决redis的并发竞争key问题?

消息队列,时间顺序

 

https://blog.youkuaiyun.com/hukaijun/article/details/81010279

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

### 关于缓存一致性的实现方案 在分布式系统中,缓存一致性是一个重要的挑战。为了确保数据的一致性并减少性能损失,可以采用多种技术和策略。 #### 1. 使用缓存一致性协议 缓存一致性协议是解决分布式环境中数据不一致的关键工具之一。这些协议通过协调不同节点之间的状态更新来维护全局一致性[^1]。常见的缓存一致性协议包括: - **MSI 协议**:适用于多处理器环境中的缓存管理,定义了三种状态(Modified, Shared, Invalid),用于描述缓存在内存中的状态。 - **MESI 协议**:扩展自 MSI 协议,增加了 Exclusive 状态,进一步优化了读写操作的效率。 上述协议虽然主要用于硬件层面的缓存控制,但在软件层面上也可以借鉴其设计思路,应用于分布式缓存场景。 #### 2. 应用一致性哈希算法 一致性哈希算法是一种有效的技术手段,在分布式缓存系统中被广泛使用。该算法通过将键空间映射到一个环形结构上来实现负载均衡和高可用性[^2]。具体来说: - 它允许新加入或移除的节点只影响一小部分数据,而不会导致大规模的数据重分布。 - 虚拟节点机制进一步提升了系统的稳定性和可靠性,降低了单点故障的风险。 这种算法特别适合动态变化频繁的大规模集群环境。 #### 3. 权衡一致性级别 对于某些应用场景而言,并不需要严格的实时一致性。此时可以根据业务需求选择适当的一致性模型,比如最终一致性或者因果一致性[^4]。例如: - 如果对数据一致性要求较低,则可以直接采取简单的失效模式(Cache Aside Pattern),即先查询缓存;如果没有命中再访问数据库并将结果放入缓存中[^5]。 - 对于更高的一致性需求,可考虑引入双删机制或其他补偿措施以保障数据同步准确性。 需要注意的是,任何增强一致性的尝试都可能带来额外的时间延迟成本以及资源消耗。 #### 4. 双删方案与其他优化方法 针对特定情况下可能出现的异常状况(如网络分区),还可以实施一些专门的设计改进: - 当检测到潜在冲突时执行双重删除动作——既清除本地副本也通知远程实例做相应清理工作; - 利用版本号标记每条记录的历史变更轨迹以便后续验证真伪关系; - 借助消息队列异步传递修改事件给订阅者们知晓最新变动情况. 以上提到的各种办法各有优劣之处,实际部署过程中应当综合考量各方面因素做出合理取舍。 ```python def cache_update(key, value): # 更新数据库的同时刷新关联缓存db.update({key: value}) cache.set(key, value) def delete_with_double_check(key): # 执行两次确认式的删除流程 if cache.exists(key): cache.delete(key) db.delete(key) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值