Redis为什么这么快

  1. 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
  2. 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  4. 使用多路I/O复用模型,非阻塞IO;
  5. 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

Redis支持的数据类型和使用场景

  1. String 常规计数:微博数,粉丝数等。
  2. Hash 适合存储对象
  3. List 底层实现为双向链表,可反向查找和遍历。 应用场景:微博的关注列表,粉丝列表,消息列表等。
  4. Set 可以自动去重 应用场景:共同关注、共同粉丝等。
  5. Sorted Set 权重score使得集合中的元素可以按照score有序排列。 应用场景:礼物排行榜
  6. 5.0后Stream

Redis和Memecache的区别?

  1. 在数据类型支持方面 Redis在数据支持上要比memecache多,Redis不仅仅支持简单的k/v类型的数据结构,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型String.
  2. 在存储方式方面 Memecache把数据全部存在内存之中,不能持久化数据; Redis支持数据的持久化(RDB和AOF两种);
  3. 集群模式: Memecache没有原生的集群模式,需要依靠客户端实现往集群中分片写入数据;Redis原生支持cluster模式。
  4. Memecache是多线程的,非阻塞IO复用的网络模型;Redis使用单线程的多路IO复用模型。

Redis持久化

  1. 快照(snapshotting)持久化(RDB) RDB是在不同的时间点,将Redis某一时刻的数据生成快照并存储到磁盘上。
  2. AOF(append-only file)持久化 AOF是只允许追加不允许改写文件,是将Redis执行过的所有写指令记录下来,在下次redis重启的时候,只要把这些写指令从前到后重复执行一遍,就可以实现数据恢复。

Redis的缓存雪崩和缓存击穿

缓存雪崩 :缓存同一时间大面积失效,请求落到数据库上,短时间内数据库因承受大量请求而崩掉。

  • 事前:尽量保证Redis集群的高可用性,选择合适的内存淘汰策略。
  • 事中:本地ehcache缓存 + hystrix限流降级,避免数据库崩掉
  • 事后:利用Redis持久化机制保存的数据尽快恢复缓存。

缓存击穿: 大量请求的key不存在于缓存,导致大量请求不经过缓存这一层直接访问数据库。
解决方法:

  • 缓存无效key 若某个key缓存数据库都查不到,将其写入到redis并设置过期时间。
  • 布隆过滤器

为什么redis的操作是原子的?

原子性是数据库的事务中的特性。在数据库事务的情景下,原子性指的是:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。

对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。
Redis的操作之所以是原子性的,是因为Redis是单线程的。

Redis缓存淘汰策略

6种数据淘汰策略:

  • volatile-lru:从已设置过期时间的数据中挑选最近最少使用的数据淘汰;
  • volatile-ttl:从已设置过期时间的数据中挑选将要过期的数据淘汰;
  • volatile-random:从已设置过期时间的数据中任意选择数据淘汰;
  • allkeys-lru:从数据集中挑选最近最少使用的数据淘汰;
  • allkeys-random:从数据集中任意选择数据淘汰;
  • no-enviction(驱逐):禁止驱逐数据

注意这里的6种机制,volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。

建议使用策略规则:
 1. 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru
 2. 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random

BloomFilter的原理

它实际上是一个很长的二进制向量和一系列随机映射函数。

布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

Bloom Filter 是一种空间效率很高的随机数据结构,Bloom filter 可以看做是对 bit-map 的扩展, 它的原理是:

当一个元素被加入集合时,通过 K 个 Hash 函数将这个元素映射成一个位阵列(Bit array)中的 K 个点,把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它。

如果这些点有任何一个 0,则被检索元素一定不在;如果都是 1,则被检索元素很可能在。

zset底层存储结构

zset底层的存储结构包括ziplist或skiplist,在同时满足以下两个条件的时候使用ziplist,其他时候使用skiplist,
两个条件如下:

  1. 有序集合保存的元素数量小于128个
  2. 有序集合保存的所有元素的长度小于64字节

当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。

 当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。