redis总结
一、Redis
(1)简介
Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对内存数据库。
(2)优点
1、读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
2、支持数据持久化,支持AOF和RDB两种持久化方式。
3、支持事务(一致性,隔离性),Redis的所有简单操作都是原子性的。同时Redis还支持对几个操作合并后的执行,不具有原子性。
4、数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
5、支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
(3)缺点
1、数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
2、Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
3、主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
4、Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
(4)、数据类型
1、string(512M)
存储结构:int(数值,长度20以内)、embstr(长度44以内)、raw
应用:缓存、计数器、分布式session、分布式锁
2、list
存储结构:ziplist(数量不超过512,值小于64字节)、linkedlist
应用:消息队列、异步队列(RPUSH、LPOP、BLPOP)
3、hash
存储结构:ziplist(数量不超过512,值小于64字节)、hashtable
4、set
存储结构:intset(64位整型、数量不超过512)、hashtable
5、zset
存储结构:ziplist(数量不超过128,值小于64字节)、skiplist
应用:排行榜、权重的队列、延时队列(ZADD、ZRANGEBYSCORE)
6、BitMap
存储结构:sting,最大 512 MB
应用:BloomFilter
7、HyperLogLog 2.8.9
存储结构:string
应用:去重基数计数(近似)、统计UV,PV、统计在线用户数量
PFADD PFCOUNT PFMERGE
8、Geospatial
存储结构:ZSET
9、Streams 5.0
存储结构:radix tree(基数树)
应用:内存版kafka(Consumer Groups)
10、pub/sub
pub/sub主题订阅模式实现一个生产者,多个消费者
缺点:消费者下线的情况下,生产的消息会丢失
二、键策略
(1)过期key策略
定期删除、定时删除、懒惰删除
(2)Redis过期key策略
惰性删除 + 定期删除
(3)内存驱逐/淘汰策略
noeviction
allkey-random
allkey-lru
volatile-random
volatile-lru
volatile-ttl
allkey-lfu(redis4.0)
volatile-lfu(redis4.0)
(4)key失效机制
定期 + 惰性 + 内存淘汰
三、持久化
(1)持久化
rdb(默认、全量、bgsave)、aof(日志、sync属性、BGREWRITEAOF)
(2)同步机制
第一次同步时主节点bgsave,增量数据通过AOF日志
(3)RDB
优点:
1、只有一个文件 dump.rdb,方便持久化。
2、容灾性好
3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO
最大化。
4.相对于数据集大时,比 AOF 的启动效率更高。
缺点:
1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生
故障,会发生数据丢失。
(4)AOF
优点:
1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 aof 文件中一次。
2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
缺点:
1、AOF 文件比 RDB 文件大,且恢复速度慢。
2、数据集大的时候,比 rdb 启动效率低。
(5)rdb与aof对比优缺点
1、AOF文件比RDB更新频率高,优先使用AOF还原数据。
2、AOF比RDB更安全也更大
3、RDB性能比AOF好
4、如果两个都配了优先加载AOF
(6)如何选择合适的持久化方式
一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。
有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF程序的bug。
如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
(7)Redis持久化数据和缓存怎么做扩容
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。
四、事务
(1)redis事务概述
一次性、顺序性、排他性的执行一个队列中的一系列命令
redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。
如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
如果在一个事务中出现运行错误,那么正确的命令会被执行
(2)Redis事务的三个阶段
事务开始 MULTI、命令入队、事务执行 EXEC
事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队
(3)Redis的事务特性
具有ACID中的一致性和隔离性,其他特性是不支持的。
当服务器运行在AOF持久化模式下,并且appendfsync选项的值为always时,事务也具有耐久性。
五、高可用
(1)高可用
主从同步、哨兵 sentinel(Raft 协议)、Cluster(16384slot CRC16)
(2)选主的策略
slave的priority越低、slave复制的数据越多、runid越小
六、分布式锁
(1)分布式锁
setNX + expire、multi/exec、set
(2)RedLock
Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全。它可以保证以下特性:
-
安全特性:互斥访问,即永远只有一个 client 能拿到锁
-
避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
-
容错性:只要大部分 Redis 节点存活就可以正常提供服务
七、Redis Java客户端
Redisson(官方推荐)、Jedis、lettuce 等等
Jedis 提供比较全面的 Redis 命令 的支持;
Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能
较为简单,不支持字符串操作,不支持排序、事务、管道、分区等 Redis 特性。
Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者能够将精力更
集中地放在处理业务逻辑上。
八、redis集群
(1)集群模式
1、群最大节点个数
16384
2、选择数据库
前无法做数据库选择,默认在 0 数据库
3、集群之间是如何复制
异步复制
4、主从复制模型
在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,每个节点都会有 N-1 个复制品
5、基本通信原理
集群元数据的维护有两种方式:集中式、Gossip 协议。
redis cluster 节点间采用 gossip 协议进行通信
6、优缺点
优点
-
无中心架构,支持动态扩容,对业务透明
-
具备Sentinel的监控和自动Failover(故障转移)能力
-
客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
-
高性能,客户端直连redis服务,免去了proxy代理的损耗
缺点
-
运维也很复杂,数据迁移需要人工干预
-
只能使用0号数据库
-
不支持批量操作(pipeline管道操作)
-
分布式逻辑和存储模块耦合等
(2)分区
1、分区目的
分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存
2、分区方案
基于客户端分配(Redis Sharding)
基于代理服务器分片(Twtter开源的Twemproxy、豌豆荚开源的Codis)
查询路由(Query routing) (Redis Cluster)
3、分区缺点
涉及多个key的操作通常不会被支持。
同时操作多个key,则不能使用Redis事务
分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集
当使用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF文件。
分区时动态扩容或缩容可能非常复杂。
(3)分布式寻址算法
1、hash 算法(大量缓存重建)
2、一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
3、redis cluster 的 hash slot 算法
(3)sentinel,中文名是哨兵
哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
1、集群监控:负责监控 redis master 和 slave 进程是否正常工作。
2、消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
3、故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
4、配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
九、缓存问题
(1)缓存穿透
原因:不存在数据,恶意攻击
解决方案:空对象进行标记、BloomFilter过滤器
(2)缓存击穿
原因:热点数据失效
解决方案:互斥锁更新、随机退避、多热点key同时失效,固定时间加上一个小的随机数
(3)缓存雪崩
原因:缓存挂掉
解决方案:快速失败的熔断策略、主从模式和集群模式
(4)缓存更新方式
纯异步更新、定时分批更新
(5)缓存不一致
耗时不敏感增加重试、耗时敏感异步补偿任务、短期的数据不一致不会影响业务,下次更新,最终一致性
(6)缓存热点key
Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
解决方案
对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询
(7)缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。
解决方案
直接写个缓存刷新页面,上线时手工操作一下;
数据量不大,可以在项目启动的时候自动进行加载;
定时刷新缓存
(8)缓存降级
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
十、问题
(1)Redis为什么不使用原生LRU算法
1、原生LRU算法需要 双向链表 来管理数据,需要额外内存;
2、数据访问时涉及数据移动,有性能损耗;
3、Redis现有数据结构需要改造;
(2)Redis近似LRU算法的优势
1、与原生LRU算法双向链表管理数据相比,不需要额外内存;
2、数据访问时不需要数据移动,无性能损耗;
3、Redis现有数据结构不需要改造;
(3)为什么Redis要使用自己的时钟
获取系统时间戳将调用系统底层提供的方法;
单线程的Redis对性能要求极高,从缓存中获取时间戳将极大提升性能。
(4)如何发现热点key
object freq key 命令支持 获取 key 的 counter,所以我们可以通过 scan 遍历所有key,再通过 object freq 获取counter。执行 object freq 的前提是 数据淘汰策略是 LFU。
Redis 4.0.3版本也提供了redis-cli的热点key功能,执行"./redis-cli --hotkeys"即可获取热点key。需要注意的是,hotkeys 本质上是 scan + object freq,所以,如果数据量特别大的情况下,可能耗时较长。
(5)LRU算法
LRU(Least Recently Used)最近最少使用。优先淘汰最近未被使用的数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
LRU底层结构是 hash 表 + 双向链表。hash 表用于保证查询操作的时间复杂度是O(1),双向链表用于保证节点插入、节点删除的时间复杂度是O(1)。
为什么是 双向链表而不是单链表呢?
单链表可以实现头部插入新节点、尾部删除旧节点的时间复杂度都是O(1),但是对于中间节点时间复杂度是O(n),因为对于中间节点c,我们需要将该节点c移动到头部,此时只知道他的下一个节点,要知道其上一个节点需要遍历整个链表,时间复杂度为O(n)。
(6)为什么Redis需要数据淘汰机制?
性价比;内存空间有限;
(7)Redis 内存满了怎么办
Redis占用内存大小、Redis的内存淘汰
(8)为什么要用 Redis 、为什么要用缓存
高性能:访问数据的时候直接从缓存中获取,速度快
高并发:直接操作缓存能够承受的请求是远远大于直接访问数据库的
(9)为什么要用 Redis 而不用 map/guava 做缓存
缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。
使用 redis 或 memcached 之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。缺点是需要保持 redis 或 memcached服务的高可用,整个程序架构上较为复杂。
(10)Redis为什么这么快
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路 I/O 复用模型,非阻塞 IO;
5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
(11)Redis的应用场景
计数器
缓存
会话缓存
全页缓存(FPC)
查找表
消息队列(发布/订阅功能)
分布式锁实现
共同好友
排行榜
(12)Redis有哪些优缺点
优点:
读写性能优异
支持数据持久化
支持事务
数据结构丰富
支持主从复制
缺点:
数据库容量受到物理内存的限制
Redis 不具备自动容错和恢复功能
主机宕机,切换IP后还会引入数据不一致的问题,降低了系统的可用性
Redis 较难支持在线扩容
(13)Redis常见性能问题和解决方案
1、Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。
2、如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
3、为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
4、尽量避免在压力较大的主库上增加从库
5、Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
6、为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<–Slave1<–Slave2<–Slave3…,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

浙公网安备 33010602011771号