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,此种方式比原先的单节点的方法更安全。它可以保证以下特性:

  1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁

  2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区

  3. 容错性:只要大部分 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,其他不变。

posted @ 2021-05-29 20:53  茅坤宝骏氹  阅读(8)  评论(0)    收藏  举报  来源