上海个人医疗网站备案表,江阴公司做网站,宝塔无法安装wordpress,什么是网站评价一、Redis 基础
#xff08;一#xff09;为什么使用 Redis
速度快#xff0c;因为数据存在内存中#xff0c;类似于 HashMap#xff0c;查找和操作的时间复杂度都是 O(1)。支持丰富数据类型#xff0c;支持 string、list、set、Zset、hash 等。支持事务#xff0c;操…一、Redis 基础
一为什么使用 Redis
速度快因为数据存在内存中类似于 HashMap查找和操作的时间复杂度都是 O(1)。支持丰富数据类型支持 string、list、set、Zset、hash 等。支持事务操作都是原子性即对数据的更改要么全部执行要么全部不执行。丰富的特性可用于缓存、消息按 key 设置过期时间过期后将会自动删除。
二Redis 的常用数据类型有哪些
String 介绍string 数据结构是简单的 key-value 类型。Redis 没有使用 C 的字符串表示而是构建了一种简单动态字符串simple dynamic stringSDS。最大能存储 512MB。常用命令set、get、strlen、exists、decr、incr、setex 等等。应用场景计数、缓存文章标题、微博内容等。 List 介绍list 即是链表。特点是易于数据元素的插入和删除并且可以灵活调整链表长度但随机访问困难。最多可存储 2^32 - 1 元素4294967295每个列表可存储 40 亿。常用命令rpush、lpop、lpush、rpop、lrange、llen 等。应用场景发布与订阅或者说消息队列。 Hash 介绍hash 类似于 JDK1.8 前的 HashMap内部实现也差不多数组链表。Redis 的 hash 做了更多优化是一个 string 类型的 field 和 value 的映射表特别适合用于存储对象。每个 hash 可以存储 2^32 - 1 键值对40 多亿。常用命令hset、hmset、hexists、hget、hgetall、hkeys、hvals 等。应用场景系统中对象数据的存储。 Set 介绍set 类似于 Java 中的 HashSet。Redis 中的 set 类型是一种无序集合集合中的元素没有先后顺序。当需要存储一个列表数据又不希望出现重复数据时set 是一个很好的选择并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口。最大的成员数为 2^32 - 14294967295每个集合可存储 40 多亿个成员。常用命令sadd、spop、smembers、sismember、scard、sinterstore、sunion 等。应用场景需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景。 SortedSet(zset) 介绍SortedSet 和 set 相比SortedSet 增加了一个权重参数 score使得集合中的元素能够按 score 进行有序排列还可以通过 score 的范围来获取元素的列表。有点像是 Java 中 HashMap 和 TreeSet 的结合体。常用命令zadd、zcard、zscore、zrange、zrevrange、zrem 等。应用场景需要对数据根据某个权重进行排序的场景。比如在直播系统中实时排行信息包含直播间在线用户列表各种礼物排行榜弹幕消息等信息。
三跳表你了解吗
跳表SkipList首先是链表但与传统的链表相比有几点差异
结合了链表和二分查找的思想。元素按照升序排列存储。节点可能包含多个指针指针跨度不同。查找时从顶层向下不断缩小搜索范围。整个查询的复杂度为 O(log n)。 Redis 数据类型 Sorted Set 使用了跳表作为其中一种数据结构。
四Redis 可以用来做什么
缓存。排行榜。分布式计数器。分布式锁。消息队列。分布式 token。限流。
五Redis 为什么快
内存操作完全基于内存绝大部分请求是纯粹的内存操作非常快速。单线程省去线程切换、锁竞争的开销采用单线程避免了不必要的上下文切换和竞争条件也不存在多进程或者多线程导致的切换而消耗 CPU不用去考虑各种锁的问题不存在加锁释放锁操作没有因为可能出现死锁而导致的性能消耗。NIO 的 IO 多路复用模型使用多路 I/O 复用模型非阻塞 IO这里“多路”指的是多个网络连接“复用”指的是复用同一个线程。
六Redis 过期删除策略
惰性删除只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好但是可能会造成太多过期 key 没有被删除。定期删除每隔一段时间抽取一批 key 执行删除过期 key 操作。并且Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
定期删除对内存更加友好惰性删除对 CPU 更加友好。两者各有千秋所以 Redis 采用的是定期删除惰性/懒汉式删除。但是仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里然后就 Out of memory 了。解决这个问题的方法是 Redis 内存淘汰机制。
七Redis 内存淘汰策略
Redis 提供 6 种数据淘汰策略
volatile-lruleast recently used从已设置过期时间的数据集server.db[i].expires中挑选最近最少使用的数据淘汰。volatile-ttl从已设置过期时间的数据集server.db[i].expires中挑选将要过期的数据淘汰。volatile-random从已设置过期时间的数据集server.db[i].expires中任意选择数据淘汰。allkeys-lruleast recently used当内存不足以容纳新写入数据时在键空间中移除最近最少使用的 key这个是最常用的。allkeys-random从数据集server.db[i].dict中任意选择数据淘汰。no-eviction禁止驱逐数据也就是说当内存不足以容纳新写入数据时新写入操作会报错。这个应该没人使用吧4.0 版本后增加以下两种 volatile-lfuleast frequently used从已设置过期时间的数据集server.db[i].expires中挑选最不经常使用的数据淘汰。allkeys-lfuleast frequently used当内存不足以容纳新写入数据时在键空间中移除最不经常使用的 key。
二、持久化
一Redis 持久化机制 RDB 和 AOF 区别
在 Redis 中提供了两种数据持久化的方式RDB 和 AOF。
RDB 定期更新定期将 Redis 中的数据生成的快照同步到磁盘等介质上磁盘上保存的就是 Redis 的内存快照。优点数据文件的大小相比于 AOF 较小使用 RDB 进行数据恢复速度较快。缺点比较耗时存在丢失数据的风险。 AOF 将 Redis 所执行过的所有指令都记录下来在下次 Redis 重启时只需要执行指令就可以了。优点数据丢失的风险大大降低了。缺点数据文件的大小相比于 RDB 较大使用 AOF 文件进行数据恢复的时候速度较慢。
项目中的持久化配置选择RDB AOF。
二Redis 如何选择合适的持久化方式
如果是数据不那么敏感且可以从其他地方重新生成补回的那么可以关闭持久化。如果是数据比较重要不想再从其他地方获取且可以承受数分钟的数据丢失比如缓存等那么可以只使用 RDB。如果是用做内存数据库要使用 Redis 的持久化建议是 RDB 和 AOF 都开启或者定期执行 bgsave 做快照备份RDB 方式更适合做数据的备份AOF 可以保证数据的不丢失。
补充Redis4.0 对于持久化机制的优化 Redis4.0 相对与 3.X 版本其中一个比较大的变化是 4.0 添加了新的混合持久化方式。简单的说新的 AOF 文件前半段是 RDB 格式的全量数据后半段是 AOF 格式的增量数据。
优势混合持久化结合了 RDB 持久化和 AOF 持久化的优点由于绝大部分都是 RDB 格式加载速度快同时结合 AOF增量的数据以 AOF 方式保存了数据更少的丢失。
劣势兼容性差一旦开启了混合持久化在 4.0 之前版本都不识别该 aof 文件同时由于前部分是 RDB 格式阅读性较差。
三在生成 RDB 期间Redis 可以同时处理写请求么
可以的Redis 使用操作系统的多进程写时复制技术 COWCopy On Write来实现快照持久化保证数据一致性。Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程快照持久化完全交给子进程来处理父进程继续处理客户端请求。当主线程执行写指令修改数据的时候这个数据就会复制一份副本bgsave 子进程读取这个副本数据写到 RDB 文件。这既保证了快照的完整性也允许主线程同时对数据进行修改避免了对正常业务的影响。
三、主从和集群
一Redis 集群方案
在 Redis 中提供的集群方案总共有三种
主从复制 保证高可用性。实现故障转移需要手动实现。无法实现海量数据存储。 哨兵模式 保证高可用性。可以实现自动化的故障转移。无法实现海量数据存储。 Redis 分片集群 保证高可用性。可以实现自动化的故障转移。可以实现海量数据存储。
二Redis 主从同步
主从第一次同步是全量同步流程如下
从节点执行replicaof命令发送自己的replid和offset给主节点。主节点判断从节点的replid与自己的是否一致。如果不一致说明是第一次来需要做全量同步主节点返回自己的replid给从节点。主节点开始执行bgsave生成rdb文件。主节点发送rdb文件给从节点在发送的过程中。从节点接收rdb文件清空本地数据加载rdb文件中的数据。同步过程中主节点接收到的新命令写入从节点的写缓冲区(repl_buffer)。从节点接收到缓冲区数据后写入本地并记录最新数据对应的offset。
后期数据变化后则执行增量同步
主节点会不断把自己接收到的命令记录在repl_baklog中并修改offset。从节点向主节点发送psync命令发送自己的offset和replid。主节点判断replid和offset与从节点是否一致。如果replid一致说明是增量同步。然后判断offset是否一致。如果从节点offset小于主节点offset并且在repl_baklog中能找到对应数据则将offset之间相差的数据发送给从节点。从节点接收到数据后写入本地修改自己的offset与主节点一致。
增量同步的风险repl_baklog大小有上限写满后会覆盖最早的数据。如果slave断开时间过久导致尚未备份的数据被覆盖则无法基于log做增量同步只能再次全量同步。repl_baklog可以在配置文件中进行修改存储大小。
三Redis 分片集群中数据的存储和读取
Redis 集群引入了哈希槽的概念Redis 集群有 16384 个哈希槽每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽集群的每个节点负责一部分 hash 槽。 上图是存值的流程取值的流程类似:
例如set {aaa} name zhangsan计算 hash 是根据aaa计算的。取值的流程类似。
四Redis 主从架构数据会丢失吗为什么
有两种数据丢失的情况
异步复制导致的数据丢失因为 master - slave 的复制是异步的所以可能有部分数据还没复制到 slavemaster 就宕机了此时这些部分数据就丢失了。脑裂导致的数据丢失某个 master 所在机器突然脱离了正常的网络跟其他 slave 机器不能连接但是实际上 master 还运行着此时哨兵可能就会认为 master 宕机了然后开启选举将其他 slave 切换成了 master。这个时候集群里就会有两个 master也就是所谓的脑裂。此时虽然某个 slave 被切换成了 master但是可能 client 还没来得及切换到新的 master还继续写向旧 master 的数据可能也丢失了。因此旧 master 再次恢复的时候会被作为一个 slave 挂到新的 master 上去自己的数据会清空重新从新的 master 复制数据。
四、使用场景
一如何保存 Redis 数据与 DB 一致
方案 1同步双写即更新完 DB 后立即同步更新 redis。方案 2异步监听即通过 Canal 监听 MySQL 变化的表同步更新数据到 Redis。方案 3MQ 异步即更新完 DB 后生产消息到 MQMQ 消费者更新数据到 Redis。
二Redis 中什么是缓存预热
缓存预热是指系统上线后提前将相关的缓存数据加载到缓存系统。避免在用户请求的时候先查询数据库然后再将数据缓存的问题用户直接查询事先被预热的缓存数据。
如果不进行预热那么 Redis 初始状态数据为空系统上线初期对于高并发的流量都会访问到数据库中对数据库造成流量的压力。
缓存预热解决方案
数据量不大的时候工程启动的时候进行加载缓存动作。数据量大的时候设置一个定时任务脚本进行缓存的刷新。数据量太大的时候优先保证热点数据进行提前加载到缓存。
三什么是缓存降级
缓存降级是指缓存失效或缓存服务器挂掉的情况下不去访问数据库直接返回默认数据或访问服务的内存数据。降级一般是有损的操作所以尽量减少降级对于业务的影响程度。
在进行降级之前要对系统进行梳理看看系统是不是可以丢卒保帅从而梳理出哪些必须誓死保护哪些可降级比如可以参考日志级别设置预案
一般比如有些服务偶尔因为网络抖动或者服务正在上线而超时可以自动降级。警告有些服务在一段时间内成功率有波动如在 95% - 100%之间可以自动降级或人工降级并发送告警。错误比如可用率低于 90%或者数据库连接池被打爆了或者访问量突然猛增到系统能承受的最大阀值此时可以根据情况自动降级或者人工降级。严重错误比如因为特殊原因数据错误了此时需要紧急人工降级。
四什么是缓存穿透怎么解决
加入缓存以后的数据查询流程 缓存穿透概述指查询一个一定不存在的数据如果从存储层查不到数据则不写入缓存这将导致这个不存在的数据每次请求都要到 DB 去查询可能导致 DB 挂掉。例如get 请求api/v1/news/13。
解决方案
查询返回的数据为空仍把这个空结果进行缓存但过期时间会比较短。布隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中一个一定不存在的数据会被这个 bitmap 拦截掉从而避免了对 DB 的查询。
Redis 中使用布隆过滤器防止缓存穿透流程图如下所示
五什么是缓存击穿怎么解决
概述对于设置了过期时间的 key缓存在某个时间点过期的时候恰好这时间点对这个 Key 有大量的并发请求过来这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存这个时候大并发的请求可能会瞬间把 DB 压垮。
解决方案
使用互斥锁当缓存失效时不立即去load db先使用如 Redis 的setnx去设置一个互斥锁当操作成功返回时再进行load db的操作并回设缓存否则重试get缓存的方法。可以设置当前 key 逻辑过期大概是思路如下 优点线程无需等待性能较好。缺点不保证一致性有额外内存消耗实现复杂。解决方案 ①在设置 key 的时候设置一个过期时间字段一块存入缓存中不给当前 key 设置过期时间。②当查询的时候从 redis 取出数据后判断时间是否过期。③如果过期则开通另外一个线程进行数据同步当前线程正常返回数据这个数据不是最新。
两种方案对比
解决方案优点缺点互斥锁没有额外的内存消耗保证一致性实现简单线程需要等待性能受影响可能有死锁风险不保证一致性逻辑过期线程无需等待性能较好有额外内存消耗实现复杂
六什么是缓存雪崩怎么解决
概述设置缓存时采用了相同的过期时间导致缓存在某一时刻同时失效请求全部转发到 DBDB 瞬时压力过重雪崩。与缓存击穿的区别雪崩是很多 key击穿是某一个 key 缓存。
解决方案 将缓存失效时间分散开比如可以在原有的失效时间基础上增加一个随机值比如 1 - 5 分钟随机这样每一个缓存的过期时间的重复率就会降低就很难引发集体失效的事件。
七Redis 分布式锁如何实现
Redis 实现分布式锁主要利用 Redis 的setnx命令。setnx是SET if not exists如果不存在则 SET的简写。 加锁使用setnx key value命令如果 key 不存在设置 value加锁成功。如果已经存在 lock也就是有客户端持有锁了则设置失败加锁失败。
解锁使用del命令通过删除键值释放锁。释放锁之后其他客户端可以通过命令进行加锁。
八Redis 分布式锁的有效时长
第一种解决方案程序员自己去把握预估一下业务代码需要执行的时间然后设置有效期时间比执行时间长一些保证不会因为自动解锁影响到客户端业务代码的执行。第二种解决方案给锁续期。
锁续期实现思路当加锁成功后同时开启守护线程默认有效期是用户所设置的然后每隔 10 秒就会给锁续期到用户所设置的有效期只要持有锁的客户端没有宕机就能保证一直持有锁直到业务代码执行完毕由客户端自己解锁如果宕机了自然就在有效期失效后自动解锁。
上述的第二种解决方案可以使用 redis 官方所提供的 Redisson 进行实现。Redisson 分布式锁原理重要 注意Redisson 的watchDog不是每 10 秒做一次续期而是每隔(releaseTime / 3)的时间做一次续期。也就是锁自动释放时间的 1/3默认的锁释放时间是 30 秒因此默认每隔 10 秒续期。