概述
Redis 优缺点
长处
- 读写性能优异。
- 反对数据长久化,反对 AOF 和 RDB 两种长久化形式。
- 反对事务,Redis 的所有操作都是原子性的,同时 Redis 还反对对几个操作合并后的原子性执行。
- 反对的数据结构丰盛。
- 反对主从复制,主机会主动将数据同步到从机,能够进行读写拆散。
毛病
- 数据库容量受到物理内存的限度。
- Redis 不具备主动容错和复原性能,主机从机的宕机都会导致前端局部读写申请失败,须要期待机器重启或者手动切换前端的 IP 能力复原。
- Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。
Redis 为什么这么快
- 齐全基于内存,绝大部分申请是纯正的内存操作,十分疾速。
- 数据结构简略,对数据操作也简略,Redis 中的数据结构是专门进行设计的。
- 采纳单线程,防止了不必要的上下文切换和竞争条件。
- 应用多路 I/O 复用模型,非阻塞 IO。
数据结构
Redis 反对的数据类型
数据类型 | 能够存储的值 | 操作 | 利用场景 |
---|---|---|---|
String | 字符串、整数、浮点数 | 对整个字符串或者其中一部分进行操作 <br/> 对整数和浮点数进行自增或者自减操作 | 做简略的键值对缓存 |
List | 列表 | 从两端压入或弹出元素 <br/> 对单个或多个元素进行修剪只保留一个范畴内的元素 | 存储一些列表型的数据结构,相似粉丝列表、文章的评论列表之类的数据 |
Hash | 蕴含键值对的无序散列表 | 增加、获取、移除键值对 <br/> 获取所有键值对 <br/> 查看某个键是否存在 | 存储结构化的数据,比方一个对象 |
Set | 无序汇合 | 查看一个元素是否存在于汇合中 <br/> 计算交加、并集、差集 <br/> 从汇合外面随机获取元素 | 能够利用交加把两个人的粉丝列表整一个交加 |
Zset | 有序汇合 | 依据分值范畴或者成员来获取元素 <br/> 计算一个键的排名 | 去重但能够排序,如获取排名前几名的用户 |
三种非凡的数据类型:
- Geospatial(天文空间)。该性能能够推算出地理位置信息,两地之间的间隔。
- HyperLogLog。是统计基数的利器,用于统计网站的 UV。
- bitmap(位图)。通过最小的单位 bit 来进行 0 或者 1 的设置。罕用于统计用户信息,比方沉闷粉丝和不沉闷粉丝、登录和未登录、是否打卡等。
zset 跳表的数据结构
利用场景
String 的利用场景
- 商品编号、订单号采纳 INCR(递增)命令生成
- 用 INCR 记录点赞数
- 文章的阅读数,只有点击了地址,阅读数就加一。
hash 的利用场景
相当于:Map<string, map>
- 购物车晚期
List 的利用场景
-
微信文章订阅公众号
- 公众号公布了文章别离是 11 和 22。
- 我关注了他们,只有他们公布了新文章,就会装置进我的 List:
lpush likeauthor:uid9543 11 22
- 查看本人订阅的全副文章,相似分页,上面 0~10 就是一次性显示 10 条:
lrange likeauthor:uid9543 0 10
Set 的利用场景
-
微信抽奖小程序
- 一个用户点击参加按钮:
SADD key 用户 ID
- 显示曾经有多少人参加:
SCARD key
-
抽奖(从 set 中任意选取 N 个中奖人)
SPOP key 3
,随机抽奖 3 人,元素 会删除SRANDMEMBER key 3
,随机抽奖 3 人,元素 不删除
- 一个用户点击参加按钮:
- 微信敌人圈点赞,并且显示所有点赞的用户
- 好友的独特关注(交加)
- 可能意识的人(差集)
Zset 的利用场景
- 依据商品销售对商品进行排序显示(分数是销量)
- 抖音热搜
长久化
长久化就是把内存的数据写到磁盘中去,避免服务器因为宕机,导致内存数据失落。Redis 反对 RDB(默认)和 AOF 两种长久化机制,当下次重启时利用之前长久化的文件即可实现数据恢复。
RDB (Redis DataBase) 和 AOF (Append-Only File)
RDB:依照肯定的工夫将内存的数据以快照的形式保留到硬盘中,对应产生的数据文件为 dump.rdb
,通过配置文件中的 save 参数来定义快照的周期。
AOF:只追加文件。将 Redis 执行的每次 写命令 记录到独自的日志文件中。
优缺点是什么?
- AOF 每条数据都写入文件中,比 RDB 更平安。
- 然而 AOF 文件比 RDB 文件大,且复原速度慢。
- RDB 性能比 AOF 好。RDB 应用
fork
子过程来实现写操作,让主过程持续解决命令,使 IO 最大化。
如果想数据的安全性更高,应该同时应用两种长久化性能。如果能够接受数分钟以内的数据失落,能够只应用 RDB 长久化。
也不肯定都只应用 AOP,应用 RDB 定时生成 RDB 快照(snapshot)十分便于进行数据库备份。
数据过期
Redis 数据过期的删除策略
过期策略通常有以下三种:
定时删除
- 含意:在设置 key 的过期工夫的同时,为该 key 创立一个定时器,到了过期工夫就会立刻革除该 key。
- 长处:保障内存尽快开释,对内存敌对。
- 毛病:会占用大量的 CPU 资源去解决过期的数据,性能影响重大。
惰性删除
- 含意:key 过期的时候不删除,每次从数据库获取 key 的时候去查看是否过期,若过期,则删除,并返回 null。
- 长处:能够最大化的节俭 CPU 资源
- 毛病:若大量的 key 在超出超时工夫后,很久一段时间内,都没有被获取过,那么可能产生内存泄露(无用的垃圾占用了大量的内存)
定期删除
- 含意:每隔一段时间执行一次删除过期 key 的操作。
- 长处和毛病都是介于下面两者之间。
-
能够设置删除的执行频率,值越大频率越快,对 Redis 性能损耗也更大。
能够设置 maxmemory 最大值,当以用内存超过这个值时,就被动触发删除策略。
tips:Redis 同时应用了惰性删除与定期删除。
集群计划
随着 Redis 应用场景越来越多,技术倒退越来越欠缺,在 Redis 整体服务上的容错、扩容、稳
定各个方面都须要一直优化。
分布式:一个业务分拆多个子业务,部署在不同的服务器上
集群:同一个业务,部署在多个服务器上
集群是解决高可用的,而分布式是解决高性能、高并发的
主从模式
为了 Redis 服务防止单点故障,通常的做法是将 Redis 数据复制多个正本以部署在不同的服务器上。这样即便有一台服务器呈现故障,其余服务器仍然能够持续提供服务。
Redis 服务器分为两类:一类是主数据库(Master),另一类是从数据库(Slave)。
主数据库能够进行读写操作,当写操作导致数据变动时会主动将数据同步给从数据库。而从数据库个别是只读的并承受主数据库同步过去的数据。一个主数据库能够领有多个从数据库,而一个从数据库只能领有一个主数据库。
长处:① 一个主,能够有多个从,并以非阻塞的形式实现数据同步;② 扩散主服务的压力,实现读写拆散
毛病:① 不具备容错和复原性能;② Redis 的主从复制采纳全量复制,须要服务器有足够的空余内存
哨兵模式
Redis 提供的哨兵机制,哨兵的作用就是监控 Redis 零碎的运行状况。基本原理是:心跳机制 + 投票裁决。哨兵模式主从能够切换,具备根本的故障转移能力。
它的性能包含以下两个:
- 监控主数据库和从数据库是否失常运行。
- 主数据库呈现故障时主动将从数据库转换为主数据库。
心跳机制:在命令流传阶段,从服务器默认以每秒一次的频率,向主服务器发送命令。用于检测主服务器的网络连接状态。
投票裁决:如果主库故障了,依据投票数主动将从库转换为主库。
如何保障缓存与数据库双写时的数据一致性?
- 读的时候,先读缓存,缓存没有的话,就读数据库,而后取出数据后放入缓存,同时返回响应。
- 更新的时候,先删除缓存,再更新数据库。如果数据库更新失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不统一。
内存相干
Redis 的内存淘汰策略
Redis 的内存淘汰策略是指在 Redis 的用于缓存的内存不足时,怎么解决须要新写入且须要申请额定空间的数据。
redis 为咱们提供了以下 8 种内存淘汰策略:
- no-eviction(没有被驱赶):当内存应用超过配置的时候会返回谬误,不会驱赶任何键。
- allkeys-lru:移除最久没有应用的键。
- volatile-lru:在设置了过期工夫的键中,移除最久没有应用的键。
- allkeys-lfu:移除应用频率起码的键。
- volatile-lfu:在设置了过期工夫的键中,移除应用频率起码的键。
- allkeys-random:随机删除。
- volatile-random:在设置了过期工夫的键中,随机删除。
- volatile-ttl:在设置了过期工夫的键中,优先删除马上过期的键。
Redis 的内存淘汰策略的选取并不会影响过期的 key 的解决。内存淘汰策略用于解决内存不足时的须要申请额定空间的数据,过期策略用于解决过期的缓存数据。
- MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保障 Redis 中的数据都是热点数据?
- Redis 的内存淘汰策略。
- Redis 的最大内存设置。
首先计算出 20w 数据所需的内存空间,设置最大内存,而后抉择适合的内存淘汰策略。
Redis 内存用完了会产生什么
如果达到设置的下限,Redis 的写命令会返回错误信息,读命令能够失常返回。
缓存异样
缓存雪崩
指缓存同一时间大面积生效,导致前面的申请都会落到数据库上,造成数据库短时间内接受大量申请而崩掉。
解决方案
- 优化缓存过期工夫。设置缓存数据的过期工夫时,减少一个随机工夫,避免同一时间大量数据过期。
- 放弃缓存层的高可用性。应用 Redis 哨兵模式或者 Redis 集群部署形式,即使个别 Redis 节点下线,整个缓存层仍然能够应用。
- 应用互斥锁重建缓存。依据 key 去缓存层查问数据,当缓存层为命中时,对 key 加锁,而后从存储层查问数据,将数据写入缓存层,最初开释锁。
缓存穿透
指查问一个基本不存在的数据,缓存层和存储层都不会命中,导致每次申请都要到存储层去查问,造成数据库短时间内接受大量申请而崩掉。
解决方案
- 接口层减少校验。例如用户校验,把 id<0 的间接拦挡。
- 缓存空对象。设为 key-null,缓存无效工夫能够设短些。
- 布隆过滤器拦挡。在拜访缓存层和存储层之前,将存在的 key 用布隆过滤器提前保存起来,做第一层拦挡。
缓存击穿
指缓存中没有,但数据库中有的数据(个别是缓存工夫到期),这时因为并发用户特地多,他们同时读缓存没有数据,又同时去数据库中取数据,导致数据库压力增大。
和缓存雪崩不同的是,缓存击穿指并发查同一条数据。而缓存雪崩是不同数据都过期了,很多数据查不到从而查数据库。
解决方案
- 设置热点数据永远不过期。
- 应用互斥锁重建缓存。
缓存预热
就是零碎上线后,将相干的缓存数据间接加载到缓存零碎。
缓存降级
就是缓存生效或者缓存服务挂掉的状况下,咱们也不去拜访数据库。咱们间接拜访内存局部数据缓存或者间接返回默认数据。
缓存降级的最终目标是保障外围服务可用,即便是有损的。
事务
Redis 事务相干命令
- MULTI 命令:用于开启一个事务,它总是返回 OK。
- EXEC 命令:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。
- DISCARD 命令:清空事务队列,放弃执行事务,并从事务状态中退出。
- WATCH 命令:是一个乐观锁,能够为 Redis 提供 CAS 行为。能够监控一个或多个键,一旦其中有一个键被批改或删除,之后的事务就不会执行。监控始终继续到 EXEC 命令。
- UNWATCH 命令:勾销 WATCH 命令 对所有 key 的监控。
Redis 事务特点
- redis 事务是一个队列中,一次性、程序性、排他性的执行一系列命令
Redis 在事务失败时不进行回滚,而是继续执行余下的命令。(不反对原子性)
如果在一个事务中的命令编译时呈现语法错误,那么所有的命令都不会执行。放入执行队列时就间接抛出异样。
如果在一个事务中呈现运行谬误,那么正确的命令会被执行。
RedLock
Redis 官网站提出了一种权威的基于 Redis 实现分布式锁的形式名叫 Redlock,此种形式比原先的单节点的办法更平安。
分布式问题
Redis 实现分布式锁
Redis 为单过程单线程模式,采纳队列模式将并发拜访变成 串行拜访,且多客户端对 Redis 的连贯并不存在竞争关系,能够应用 SETNX
命令实现分布式锁。
SETNX key value # key 不存在时,设置 key 的值。
- 应用
SETNX
命令获取锁,若返回 0(key 已存在,锁已存在)则获取失败,反之获取胜利。 - 为了避免获取锁后程序出现异常,导致其余线程 / 过程调用 SETNX 命令总是返回 0 而进入死锁状态,须要为该 key 设置一个“正当”的过期工夫
- 开释锁,则应用
DEL
命令将锁数据删除。
Redis 的分布式锁的缺点
Redis 高可用最常见的计划就是主从复制(master-slave),这种模式也给 redis 分布式锁挖了一坑。
Redis 集群环境下,如果当初 A 客户端想要加锁,他会依据路由规定抉择一台 master 节点写入 key,在加锁胜利后,master 节点会把 key 复制给对应的 slave 节点。
如果这个时候 master 节点宕机了,进行了主备切换。B 客户端在新的 master 节点上加锁胜利,而 A 客户端也认为本人胜利加了锁。
此时就会导致同一时间内,有多个客户端对一个分布式锁实现了加锁,导致各种脏数据的产生。