做网站 阿里云和百度云哪个好,软文写作经验,成都网站制作售后,做绿化生意有什么网站目录
一、为什么要用缓存
二、使用 Redis有哪些好处
三、什么是 redis#xff1f;
四、redis和memcached区别
五、为什么redis单线程模型效率也能那么高
六、redis的线程模型
七、redis 6.0 引入多线程
八、为什么Redis需要把所有数据放到内存中#xff1f;
九、Red…目录
一、为什么要用缓存
二、使用 Redis有哪些好处
三、什么是 redis
四、redis和memcached区别
五、为什么redis单线程模型效率也能那么高
六、redis的线程模型
七、redis 6.0 引入多线程
八、为什么Redis需要把所有数据放到内存中
九、Redis 的同步机制了解是什么
十、pipeline 有什么好处为什么要用 pipeline
十一、redis缓存刷新策略有哪些
十二、redis写的最佳实践
十三、Redis持久化方式有哪些以及有什么区别
十四、Redis实现消息队列
十五、Redis事务
十六、熟悉哪些Redis集群模式
十七、是否使用过Redis Cluster集群集群的原理是什么
十八、Redis Cluster集群方案什么情况下会导致整个集群不可
十九、集群架构模式有哪几种
二十、Redis 常见性能问题和解决方案有哪些
二十一、假如 Redis 里面有 1 亿个 key其中有 10w 个 key 是 以某个固定的已知的前缀开头的如果将它们全部找出来
二十二、如果有大量的 key 需要设置同一时间过期一般需要注意什么吗
二十三、什么情况下可能会导致Redis阻塞
二十四、Redis 怎么提高缓存命中率
二十五、Redis 如何解决 Key 冲突
二十六、Redis 报内存不足怎么处理
二十七、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题 一、为什么要用缓存
使用缓存的目的就是提升读写性能。而实际业务场景下更多的是为了提升读性能带来更好的性 能带来更高的并发量。 Redis 的读写性能比 Mysql 好得多我们就可以把 Mysql 中的热点数据 缓存到 Redis 中提升读取性能同时也减轻了 Mysql 的读取压力。
二、使用 Redis有哪些好处
读取速度快因为数据存在内存中所以数据获取快
支持多种数据结构包括字符串、列表、集合、有序集合、哈希等
支持事务且操作遵守原子性即对数据的操作要么都执行要么都不支持
还拥有其他丰富的功能队列、主从复制、集群、数据持久化等功能
三、什么是 redis
Redis 是一个开源BSD 许可、基于内存、支持多种数据结构的存储系统可以作为数据库、 缓 存和消息中间件。它支持的数据结构有字符串strings、哈希hashes、列表lists、 集合 sets、有序集合sorted sets等除此之外还支持 bitmaps、hyperloglogs 和地理 空间 geospatial 索引半径查询等功能。 它内置了复制Replication、 LUA 脚本Lua scripting、 LRU 驱动事件LRU eviction、 事 务Transactions和不同级别的磁盘持久化persistence功能并通过 Redis 哨兵哨 兵和 集群Cluster保证缓存的高可用性High availability。
四、redis和memcached区别
Redis和Memcached的主要区别在于数据持久化、数据类型、线程模型、内存使用效率、数据操作性能、数据备份能力、系统扩展性以及数据安全性。 数据持久化Redis支持将数据从内存持久化到硬盘通过RDB快照和AOF日志两种主要策略实现持久化而Memcached不支持数据持久化操作服务器重启后数据会丢失。 数据类型Redis支持多种数据结构类型如列表、集合和哈希表等而Memcached主要在内存中维护一张大型哈希表进行数据的存储仅支持基本的键值对数据类型。 线程模型Memcached采用多线程模型处理请求基于IO多路复用技术而Redis采用单线程模型处理请求虽然Redis 6.0后引入了多线程处理性能有所提高但基本操作仍以单线程为主。 内存使用效率对于简单的键值对存储Memcached在内存利用率上具有优势。但如果Redis使用哈希结构来存储键值对数据其由于使用了组合式的压缩可能使得内存利用率超过Memcached。 数据操作性能在数据的读取操作上Redis和Memcache的性能大致相当。但在处理小数据时Redis的性能可能略高于Memcached而在处理大数据时Memcached的性能可能优于Redis。 数据备份能力Redis具备数据备份的能力通过其主从备份模式实现。相反Memcached因其不支持数据持久化从而无法实现数据的备份。 系统扩展性两者都需要通过集群的方式进行扩展包括主从模式和哈希模式。但在实现更高的处理能力方面Redis和Memcached的具体扩展方式有所不同。 数据安全性由于Memcached把所有数据存储在内存中当服务器发生故障并重启后存储在其中的数据会完全丢失。而Redis能够将数据周期性地保存到硬盘以实现持久化存储保证在必要时数据的可恢复性。
综上所述Redis和Memcached各有其优势和适用场景。如果需要数据持久化、支持多种数据结构、高可用性和可扩展性Redis是更好的选择。而如果需要简单的高速缓存系统对数据持久化和复杂的数据结构需求不高Memcached可能更适合。
五、为什么redis单线程模型效率也能那么高
1. C 语言实现效率高
2. 纯内存操作
3. 基于非阻塞的 IO 复用模型机制
4. 单线程的话就能避免多线程的频繁上下文切换问题
5. 丰富的数据结构全称采用 hash 结构读取速度非常快对数据存储进行了一些优化比如亚索表跳表等
六、redis的线程模型 Redis 基于 Reactor 模式开发了自己的网络事件处理器 - 文件事件处理器file event handler后文简称为 FEH而该处理器又是单线程的所以 redis 设计为单线程模型。 文件事件分派器从队列中接收 I/O 多路复用程序传来的socket并根据socket产生的事件类型调用相应的事件处理器。当上一个socket产生的事件被对应事件处理器执行完后文件事件分派器才会向队列拉取下一个要处理的socket保证socket操作一定不会并发的执行保证线程安全。Redis所谓的单线程并不是所有工作都是只有一个线程在执行而是指Redis的网络IO和键值对读写是由一个线程来完成的Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理。 这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。由于Redis在处理命令的时候是单线程作业的所以会有一个Socket队列每一个到达的服务端命令来了之后都不会马上被执行而是进入队列然后被线程的事件分发器逐个执行。
文件事件处理器的几个组成部分: 七、redis 6.0 引入多线程 redis处理接受客户端请求后可以简化为三部分操作 read 读区请求parse-respcommand excute 解析请求到命令执行write 相应请求 redis 6.0之前以上三个步骤依次执行
6.0之后read和write两部分支持多线程第二部处理指令依然是单线程。
6.0版本优化之后主线程和多线程网络IO的执行流程如下 具体步骤如下
主线程建立连接并接受数据并将获取的 socket 数据放入等待队列通过轮询的方式将 socket读取出来并分配给 IO 线程之后主线程保持阻塞一直等到 IO 线程完成 socket 读取和解析I/O 线程读取和解析完成之后返回给主线程 主线程开始执行 Redis 命令执行完Redis命令后主线程阻塞直到IO 线程完成 结果回写到socket 的工作主线程清空已完成的队列等待客户端新的请求。
本质上是将主线程 IO 读写的这个操作 独立出来单独交给一个I/O线程组处理。这样多个 socket 读写可以并行执行整体效率也就提高了。同时注意 Redis 命令还是主线程串行 这里举个生活中的例子展示IO读写多线程如何提高效率的 车站买票和上车买票对应IO读写上车对应redis操作 假设没有多线程也就是相当于只有一个买票窗口那么人太多买票窗口就会聚集大堆人一个人买到票才轮到下一个买票时间随着人数的增多而增多多线程就是多开几个窗口解决买票排队情况降低大家总的买票时间。可能你会问上车不还是一个一个按顺序上吗,哪怕你全部人一下子买好票了我上车的速度还是不变啊对但上车几乎是不花费时间的基于内存也就是不管你现在是1个人买票了还是1000个人买票了都可以秒上车所以买票和上车的瓶颈在买票提高买票效率则提高整体效率。 写操作支持多线程 // 这里说有三个IO 线程还有一个线程是main线程main线程负责IO读写和命令执行操作io‐threads 4 读操作支持多线程 // 将支持IO线程执行 读写任务。
io‐threads‐do‐reads yes Redis6.0 为什么要引入多线程呢
可以充分利用服务器CPU的多核资源而主线程明显只能利用一个多线程任务可以分摊 Redis 同步 IO 读写负荷降低耗时
Redis 将所有数据放在内存中内存的响应时长大约为 100 纳秒对于小数据包Redis 服务器可以处理 80,000 到 100,000 QPS这也是 Redis 处理的极限了对于 80%的公司来说单线程的 Redis 已经足够使用了。
随着越来越复杂的业务场景有些公司动不动就上亿的交易量因此需要更大的 QPS. 常见解决方案是分布式架构中对数据进行分区并采用多个服务器。这种方式 维护代价大某些命令失效数据分区无法解决热点读/写问题数据偏斜重新分配和放大/缩小变得更加复杂等等。
从 Redis 自身角度来说因为读写网络的 read/write 系统调用占用了 Redis执行期间大部分 CPU 时间瓶颈主要在于网络的 IO 消耗. redis6.0充分利用多核cpu的能力分摊 Redis 同步 IO 读写负荷。
八、为什么Redis需要把所有数据放到内存中
Redis 将数据放在内存中有一个好处那就是可以实现最快地对数据读取如果数据存储在硬盘 中磁盘 I/O 会严重影响 Redis 的性能。而且 Redis 还提供了数据持久化功能不用担心服务 器重 启对内存中数据的影响。其次现在硬件越来越便宜的情况下Redis 的使用也被应用得越来 越多 使得它拥有很大的优势
九、Redis 的同步机制了解是什么
Redis 支持主从同步、从同步。如果是第一次进行主从同步主节点需要使用 bgsave 命令再将 后续修改操作记录到内存的缓冲区等 RDB 文件全部同步到复制节点复制节点接收完成后将 RDB 镜像记载到内存中。等加载完成后复制节点通知主节点将复制期间修改的操作记录同步到 复 制节点即可完成同步过程
十、pipeline 有什么好处为什么要用 pipeline
使用 pipeline管道的好处在于可以将多次 I/O 往返的时间缩短为一次但是要求管道中执行 的 指令间没有因果关系。 用 pipeline 的原因在于可以实现请求/响应服务器的功能当客户端尚未读取旧响应时它也可 以 处理新的请求。如果客户端存在多个命令发送到服务器时那么客户端无需等待服务端的每 次响应 才能执行下个命令只需最后一步从服务端读取回复即可。
十一、redis缓存刷新策略有哪些 十二、redis写的最佳实践
一致性问题:
在Redis的key值未过期的情况下用户修改了个人信息我们此时既要操作数据库数据也要操作Redis数据。从本质上讲无论是先写数据库还是先写缓存都是为了保证数据库和缓存的数据一致也就是我们常说的数据一致性。
操作缓存和数据库时需要考虑的三个问题:
1. 删除缓存还是更新缓存
更新缓存每次更新数据库都更新缓存无效写操作较多
删除缓存更新数据库时让缓存失效查询时再更新缓存
结论推荐直接使用「删除」操作。
2. 如何保证缓存与数据库的操作的同时成功或者失败
对于单体系统将缓存与数据库操作放在一个事务中
对于分布式系统利用TCC等分布式事务方案
3. 先操作缓存还是先操作数据库?
3-1. 先删除缓存再操作数据库
这种方式可能存在以下两种异常情况:
1. 删除缓存失败这时可以通过程序捕获异常直接返回结果不再继续更新数据库所以不会出现数据不一致的问题
2. 删除缓存成功更新数据库失败。在多线程下可能会出现数据不一致的问题 这时Redis中存储的旧数据数据库的值是新数据导致数据不一致。这时我们可以采用 延时双删 的策略即更新数据库数据之后再删除一次缓存。 用伪代码表示就是:
/*** 延时双删* author*/
public void update(String key, Object data) {// 首先删除缓存redisCache.delKey(key);// 更新数据库db.updateData(data);// 休眠一段时间时间依据数据的读取耗费的时间而定Thread.sleep(500);// 再次删除缓存redisCache.delKey(key);
}
3-2. 先操作数据库再删除缓存
这种方式可能存在以下两种异常情况:
1. 更新数据库失败这时可以通过程序捕获异常直接返回结果不再继续删除缓存所以不会出现数据不一致的问题
2. 更新数据库成功删除缓存失败。导致数据库是最新数据缓存中的是旧数据数据不一致
这里, 我们有两种方式来解决数据不一致问题失败重试 和 异步更新。
方式1. 失败重试
如果删除缓存失败我们可以捕获这个异常把需要删除的 key 发送到消息队列。自己创建一个消费者消费尝试再次删除这个 key直到删除成功为止。
这种方式有个缺点首先会对业务代码造成入侵其次引入了消息队列增加了系统的不确定性。
方式2. 异步更新
因为更新数据库时会往 binlog 中写入日志所以我们可以启动一个监听 binlog变化的服务比如使用阿里的 canal开源组件然后在客户端完成删除 key 的操作。如果删除失败的话再发送到消息队列。 总之对于删除缓存失败的情况我们的做法是不断地重试删除操作直到成功。无论是重试还是异步删除都是最终一致性的思想。
十三、Redis持久化方式有哪些以及有什么区别
在Redis中有两种常见的持久化方式 RDBRedis Database和AOFAppend-Only File。它们都用于将Redis中的数据持久化到磁盘上以便在Redis重启后能够恢复数据。
RDB持久化方式 RDB是Redis默认的持久化方式它会将Redis在某个时间点的数据以二进制格式保存到磁盘上。RDB持久化方式通过fork一个子进程来完成持久化操作该子进程会将数据写入到一个临时文件中当持久化完成后再用这个临时文件替换原来的RDB文件。RDB文件是一个紧凑的二进制文件它保存了Redis在某个时间点的数据快照。
优点 RDB文件紧凑占用的磁盘空间相对较小。 RDB文件的恢复速度比AOF方式快适用于大规模的数据恢复。
缺点 RDB方式是定期保存数据快照如果Redis在定期保存之前发生故障可能会丢失最后一次快照之后的数据。 RDB方式需要fork一个子进程来进行持久化操作如果数据量较大fork操作可能会导致Redis的性能下降。
AOF持久化方式 AOF持久化方式会将Redis的写操作以日志的形式追加到文件中Append-Only File当Redis重启时会重新执行这些写操作来恢复数据。AOF文件是一个文本文件它以易读的方式记录了Redis的写操作。
优点 AOF文件记录了Redis的所有写操作可以确保数据的完整性和持久性。 AOF文件是一个文本文件易于阅读和理解。
缺点 AOF文件相对于RDB文件来说占用的磁盘空间较大。 AOF文件的恢复速度比RDB方式慢适用于小规模的数据恢复。
在实际应用中可以根据需求选择适合的持久化方式。如果对数据的完整性和持久性要求较高可以选择AOF方式如果对磁盘空间和数据恢复速度要求较高可以选择RDB方式也可以同时使用RDB和AOF方式进行持久化以兼具数据恢复速度和数据完整性的优势。
下面是一个使用Java操作Redis的示例代码演示了如何配置和使用RDB和AOF持久化方式
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;public class RedisPersistenceExample {public static void main(String[] args) {// 创建Jedis连接池JedisPoolConfig config new JedisPoolConfig();JedisPool jedisPool new JedisPool(config, localhost, 6379);// 从连接池中获取Jedis实例try (Jedis jedis jedisPool.getResource()) {// 设置RDB持久化方式jedis.configSet(save, 3600 1); // 每隔3600秒如果至少有1个key发生变化则保存RDB快照// 设置AOF持久化方式jedis.configSet(appendonly, yes); // 开启AOF持久化// 执行Redis操作jedis.set(key1, value1);jedis.set(key2, value2);jedis.set(key3, value3);// 保存RDB快照jedis.save();// 执行Redis重启操作模拟Redis重启jedis.flushAll(); // 清空数据// 恢复RDB快照jedis.restore(key1, 0, jedis.dump(key1)); // 恢复key1的值// 查看恢复后的数据System.out.println(jedis.get(key1)); // 输出value1// 查看AOF文件路径System.out.println(jedis.configGet(dir).get(1) / jedis.configGet(appendfilename).get(1));}// 关闭Jedis连接池jedisPool.close();}
}十四、Redis实现消息队列 一般使用 list 结构作为队列lpush生产消息 rpop消费消息。当 rpop 没有消息的时候要适当sleep一会再重试。
可不可以不用 sleep 呢?
list 还有个指令叫brpop在没有消息的时候它会阻塞住直到消息到来。
能不能生产一次消费多次呢
使用 pub / sub 主题订阅者模式可以实现 1:N 的消息队列。
pub / sub 有什么缺点
在消费者下线的情况下生产的消息会丢失得使用专业的消息队列。
Redis 如何实现延时队?
使用 sortedset 拿时间戳作为 score 消息内容作为 key 调用 N 秒之前的数据轮询进行处理。
十五、Redis事务
什么是 redis事务原理是什么
Redis 中的事务是一组命令的集合是 Redis 的最小执行单位。它可以保证一次执行多个命令 每个事务是一个单独的隔离操作事务中的所有命令都会序列化、按顺序地执行。服务端在执行 事务 的过程中不会被其他客户端发送来的命令请求打断。 它的原理是先将属于一个事务的命令发送给 Redis 然后依次执行这些命令。
redis事务的注意点有哪些
需要注意的点有
Redis 事务是不支持回滚的不像 MySQL 的事务一样要么都执行要么都不执行
Redis 服务端在执行事务的过程中不会被其他客户端发送来的命令请求打断。直到事务命令全部执行完毕才会执行其他客户端的命令。
redis事务为什么不支持回滚
Redis 的事务不支持回滚但是执行的命令有语法错误Redis 会执行失败这些问题可以从程序 层 面捕获并解决。但是如果出现其他问题则依然会继续执行余下的命令。这样做的原因是回滚 需要增加很多工作而不支持回滚则可以保持简单、快速的特性。
十六、熟悉哪些Redis集群模式
1.Redis Sentinel
体量较小时选择单机模式
2.Redis Cluster
官方提供的集群化方案体量较大时选择Cluster通过分片使用更多内存
3.Twemprox
Twemprox是Twtter开源的一个Redis和Memcached代理服务器主要用于管理Redis和Memcached集群减少与 Cache 服务器直接连接的数量。
4.Codis
Codis 是一个代理中间件,当客户端向Codis发送指令时, Codis负责将指令转发到后面的Redis来执行并将结果返回给客户端。 一个Codis实例可以连接多个Redis 实例也可以启动多个Codis实例来支撑每个Codis节点都是对等的这样可以增加整体的QPS, 起到容灾功能。
5.客户端分片
现在基本很少使用自己在业务代码层实现。
十七、是否使用过Redis Cluster集群集群的原理是什么
使用过 Redis 集群它的原理是
所有的节点相互连接集群消息通信通过集群总线通信集群总线端口大小为客户端服务端口 10000固定 值节点与节点之间通过二进制协议进行通信客户端和集群节点之间通信和通常一样通过文本协议进行集群节点不会代理查询数据按照 Slot 存储分布在多个 Redis 实例上集群节点挂掉会自动故障转移可以相对平滑扩/缩容节点
Redis 集群中内置了 16384 个哈希槽当需要在 Redis 集群中放置一个 key-value 时redis 先 对 key 使用 crc16 算法算出一个结果然后把结果对 16384 求余数这样每个 key 都会对 应一个编号 在 0~16383 之间的哈希槽 redis 会根据节点数量大致均等地将哈希槽映射到不同的节点
十八、Redis Cluster集群方案什么情况下会导致整个集群不可
Redis 没有使用哈希一致性算法而是使用哈希槽。 Redis 中的哈希槽一共有 16384 个计算给 定 密钥的哈希槽我们只需要对密钥的 CRC16 去取 16384。假设集群中有 A、B、C 三个集群 节点 不存在复制模式下每个集群的节点包含的哈希槽如下
节点 A 包含从 0 到 5500 的哈希槽节点 B 包含从 5501 到 11000 的哈希槽节点 C 包含从 11001 到 16383 的哈希槽
这时如果节点 B 出现故障整个集群就会出现缺少 5501 到 11000 的哈希槽范围而不可用。
十九、集群架构模式有哪几种
Redis 集群架构是支持单节点单机模式的也支持一主多从的主从结构还支持带有哨兵的集群 部 署模式。
二十、Redis 常见性能问题和解决方案有哪些
常见性能问题和解决方案如下
Master 最好不要做任何持久化工作如 RDB 内存快照和 AOF 日志文件如果数据比较重要某个 Slave 开启 AOF 备份数据策略设置为每秒同步一 次为了主从复制的速度和连接的稳定性Master 和 Slave 最好在同一个 局域网内尽量避免在压力很大的主库上增加从库主从复制不要用图状结构用单向链表结构更为稳定即Master - Slave1 - Slave2 - Slave3…. 这样的结构方便解决单点故障问题实现 Slave 对 Master 的替换。如果 Master 挂 了可以立刻启用 Slave1 做 Master 其他不变。
二十一、假如 Redis 里面有 1 亿个 key其中有 10w 个 key 是 以某个固定的已知的前缀开头的如果将它们全部找出来
我们可以使用 keys 命令和 scan 命令但是会发现使用 scan 更好。
1.直接使用 keys 命令查询但是如果是在生产环境下使用会出现一个问题keys 命令是遍历查询 的查询的时间复杂度为 O(n)数据量越大查询时间越长。而且 Redis 是单线程keys 指令会 导 致线程阻塞一段时间会导致线上 Redis 停顿一段时间直到 keys 执行完毕才能恢复。这 在生产 环境是不允许的。除此之外需要注意的是这个命令没有分页功能会一次性查询出 所有符合条 件的 key 值会发现查询结果非常大输出的信息非常多。所以不推荐使用这个命令。
2.scan 命令可以实现和 keys 一样的匹配功能但是 scan 命令在执行的过程不会阻塞线程并且 查 找的数据可能存在重复需要客户端操作去重。因为 scan 是通过游标方式查询的所以不会导致 Redis 出现假死的问题。 Redis 查询过程中会把游标返回给客户端单次返回空值且游 标不为 0则 说明遍历还没结束客户端继续遍历查询。 scan 在检索的过程中被删除的元素是 不会被查询出来 但是如果在迭代过程中有元素被修改 scan 不能保证查询出对应元素。相对来说 scan 指令 查找花费的时间会比 keys 指令长。
二十二、如果有大量的 key 需要设置同一时间过期一般需要注意什么吗
如果有大量的 key 在同一时间过期那么可能同一秒都从数据库获取数据给数据库造成很大的 压力导致数据库崩溃系统出现 502 问题。也有可能同时失效那一刻不用都访问数据库 压力不够大的话那么 Redis 会出现短暂的卡顿问题。所以为了预防这种问题的发生最好给 数据的过期时间加一个随机值让过期时间更加分散。
二十三、什么情况下可能会导致Redis阻塞
Redis 产生阻塞的原因主要有内部和外部两个原因导致
内部原因
如果 Redis 主机的 CPU 负载过高也会导致系统崩溃数据持久化占用资源过多对 Redis 的 API 或指令使用不合理导致 Redis 出现问题。
外部原因
外部原因主要是服务器的原因例如服务器的 CPU 线程在切换过程中竞争过大内存出现问题、 网 络问题等。
二十四、Redis 怎么提高缓存命中率
提前加载数据到缓存中增加缓存的存储空间提高缓存的数据调整缓存的存储数据类型提升缓存的更新频率。
二十五、Redis 如何解决 Key 冲突
Redis 如果 key 相同后一个 key 会覆盖前一个 key。如果要解决 key 冲突最好给 key 取 好名区分开可以按业务名和参数区分开取名避免重复 key 导致的冲突
二十六、Redis 报内存不足怎么处理
Redis 内存不足可以这样处理
修改配置文件 redis.conf 的 maxmemory 参数增加 Redis 可用内存设置缓存淘汰策略提高内存的使用效率使用 Redis 集群模式提高存储
二十七、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题
一、缓存雪崩
我们可以简单地理解为由于原有缓存失效新缓存未到其间 例如我们设置缓存时采用了相 同的 过期时间在同一时刻出现大面积的缓存过期 所有原本应该访问缓存的请求都去查询数 据库了 而对数据库 CPU 和内存造成巨大压力严重的会造成数据库宕机。从而形成一系列连 锁反应造成 整个系统崩溃。 解决办法 大多数系统设计者考虑用加锁 最多的解决方案 或者队列的方式保 证来保证不会有大量的线程对数据库一次性进行读写从而避免失效时大量的 并发请求落到底层存 储系统上。还有一个简单方案就是时间缓存失效时间分散开。
二、缓存穿透
缓存穿透是指用户查询数据在数据库没有自然在缓存中也不会有。这样就导致 用 户查询的时候在缓存中找不到每次都要去数据库再查询一遍然后返回空相当于进行了 两次 无用的查询。这样请求就绕过缓存直接查数据库这也是经常提的缓存命中率问题。 解 决办法 最常见的则是采用布隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中一个一定不 存在的数据会被这个 bitmap 拦截掉从而避免了对底层存储系统的查询压力。 另 外也有一个更为 简单粗暴的方法如果一个查询返回的数据为空不管是数据不存在还是系 统故障我们仍然 把这个空结果进行缓存但它的过期时间会很短最长不超过五分钟。通 过这个直接设置的默认值 存放到缓存这样第二次到缓冲中获取就有值了而不会继续访问数据 库这种办法最简单粗暴。
5TB 的硬盘上放满了数据请写一个算法将这些数据进行排重。如果这些数据是一些 32bit 大小 的数 据该如何解决如果是 64bit 的呢
对于空间的利用到达了一种极致那就是 Bitmap 和布隆过滤器Bloom Filter)。 Bitmap 典型 的就 是哈希表 缺点是Bitmap 对于每个元素只能记录 1bit 信息如果还想完成额外的功能恐 怕只能靠 牺牲更多的空间、时间来完成了。
布隆过滤器推荐
就是引入了 k(k1)k(k1个相互独立的哈希函数保证在给定的空间、误判 率 下完成元素判重的过程。 它的优点是空间效率和查询时间都远远超过一般的算法缺点是 有一定 的误识别率和删除困难。 Bloom-Filter 算法的核心思想就是利用多个不同的 Hash 函数来 解决“冲 突”。 Hash 存在一个冲突碰撞的问题用同一个 Hash 得到的两个 URL 的值有可能相同。为 了减 少冲突我们可以多引入几个 Hash如果通过其中的一个 Hash 值我们得出某元素不在集 合中那 么该元素肯定不在集合中。只有在所有的 Hash 函数告诉我们该元素在集合中时才 能确定该元素存 在于集合中。这便是 Bloom-Filter 的基本思想。 Bloom-Filter 一般用于在大数 据量的集合中判定某 元素是否存在。
三、缓存预热
缓存预热这个应该是一个比较常见的概念相信很多小伙伴都应该可以很容易地理 解缓存预热就是系统上线后将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户 请 求的时候先查询数据库然后再将数据缓存的问题用户直接查询事先被预热的缓存数据
解决思路 1、直接写个缓存刷新页面上线时手工操作下 2、数据量不大可以在项目启动的 时候 自动进行加载 3、定时刷新缓存
四、缓存更新
除了缓存服务器自带的缓存失效策略之外Redis 默认的有 6 种策略可供选择 我们 还可以根据具体的业务需求进行自定义的缓存淘汰常见的策略有两种
定时去清理 过期的 缓存当有用户请求过来时再判断这个请求所用到的缓存是否过期过期的话 就去底层系 统得到新数据并更新缓存。 两者各有优劣第一种的缺点是维护大量缓存的 key 是比较麻烦的第 二种的缺点就是每次用户请求过来都要判断缓存失效逻辑相对比较复杂
具体用哪种方案大家 可以根据自己的应用场景来权衡。
五、缓存降级
当访问量剧增、服务出现问题如响应时间慢或不响应或非核心服务影响到核心 流 程的性能时仍然需要保证服务还是可用的即使是有损服务。系统可以根据一些关键数据进 行自 动降级也可以配置开关实现人工降级。 降级的最终目的是保证核心服务可用即使是有 损的。而 且有些服务是无法降级的如加入购物车、结算。 以参考日志级别设置预案
一般比如 有些服务偶尔因为网络抖动或者服务正在上线而超时可以自动降级 警告 有些服务在一 段时间内成功率有波动如在 95%~100%之间可以自动降级或人工降级并发 送告警错误比如可用率低于 90%或者数据库连接池被打爆了或者访问量突然猛 增到系统能承受的最大 阈值此时可以根据情况自动降级或者人工降级严重错误比 如因为特殊原因数据错误 此时需要紧急人工降级。
服务降级的目的是为了防止 Redis 服务故障导致数据库跟着一起发生雪崩问题。因此对于不 重 要的缓存数据可以采取服务降级策略例如一个比较常见的做法就是Redis 出现问题不 去数据 库查询而是直接返回默认值给用户。