一. Redis简介

前言

最近,我从Redis入手,对分布式缓存进行了学习探究。为了记录我的学习成果,我将会写一系列博客来介绍Redis和分布式缓存。在学习过程中,我在网上查阅了一些关于Redis的资料,发现网上的资料比较零散,而且良莠不齐,让人很难纵观Redis的全局。同时,网上也有很多课程和专栏,它们也讲得很系统,但是不同专栏和课程间形成了一座座信息孤岛,有些知识点只是某些课程或者专栏有讲到,很难做到面面俱到。因此,我希望用一系列博客来纵观Redis,既总览Redis又不放过每一个重要原理和细枝末节。废话不多说,让我们一起开始Redis之旅吧^_^

1. Redis是什么

Redis是“Remote Dictionary Service”(即远程字典服务)的缩写,它是一个由ANSI C 语言开发的,开放源代码(BSD许可)的key-value存储组建。它的所有数据结构都在内存中,并且支持数据持久化,因此可用来做缓存、数据库和消息中间件。

2. Redis的数据类型

目前,Redis支持8种数据类型:String、List、Set、ZSet、Hash、Bitmap、Geo、Hyperloglog,针对每种数据类型,Redis提供了不同的操作指令进行数据操作。大多数人可能只对前五种比较熟悉,我在这里先简述下后面三种,接下来会有专门的博客来详细介绍各种数据类型。

Bitmap即位图,每一bit只能取值为为0或1,底层通过字节数组来存储,每个字节有8个bit。我们可以通过Bitmap来存储一系列YN标志,比如记录用户每天的签到情况,每个bit代表一天,0代表没签到,1代表已签到。


bitmap.png

Geo是Redis的地理位置模块,底层通过GeoHash算法将二维的地理坐标转换为一维的数值,再存储在ZSet中进行排序。我们可以通过Geo来计算两地距离、实现搜索附近的功能。

Hyperloglog是一个去重计数器,可以用于去重地统计数量,比如页面UV(用户浏览数量,每个用户多次浏览页面只算1个UV)。Hyperloglog的底层数据存储依然采用字节数组的形式,每6bit代表一个桶,用于存储这个桶的元素个数,Redis采用16384( 2^14 )个桶实现,因此一共占用2^14*8/6=12k的存储空间。Hyperloglog的存储方式跟String和Bitmap一样,之所以能实现去重统计,特殊之处在于它在计数时用到的Hyperloglog算法。

3. Redis能干什么

学习一门技术,最重要的是学以致用,我觉得了解一项技术的背景和作用是打开这项技术大门的必经之路。对于Redis而言,它的应用处取决于它的特性,以及它向我们提供了什么数据类型和操作指令。

  1. 缓存数据。从广义上来说,缓存是用于数据快速交换的存储介质。基于Redis的内存存储特性,我们可以使用它来缓存热点数据,从而实现数据的快速存取。

  2. 分布式锁。在分布式系统中,我们可以通过加锁的方式来限制共享资源的访问,同一时间允许一个系统来访问共享资源,因为在分布式系统中各个机器的内存隔离,所以需要一个中间件来协调资源访问,而Redis就可以充当这样一个角色。Redis提供了setnx和del指令,setnx指令可以原子性地实现“如果key不存在,就set这个key”的功能,如果set成功,就可以去访问共享资源;否则不断重试抢占锁。而当资源访问完毕后通过del指令来删除之前set的key,从而释放锁。


    分布式锁.png
  3. 延时队列。延时队列中的元素要到指定的事件后才能访问,因此可以实现定时任务。延时队列可以通过Redis的ZSet数据类型来实现,使用zadd(key, 目的执行时间, value)指令往延时队列添加任务,再通过zrangebyscore(key, 0, 当前时间)指令得到目的执行时间超过当前时间的任务,执行完后通过zrem(key, value)指令来删除已经执行的任务,从而保证延时队列里的每个任务只执行一次。

  4. 去重计数器。我们可以通过Redis的Hyperloglog实现去重计数器,使用pfadd指令往Redis里面添加元素,再通过pfcount指令获取元素个数。

  5. 布隆过滤器。Redis提供了布隆过滤器,我们可以通过bf.add指令往Redis里面添加元素,再通过bf.exists指令来判断某个元素是否存在,从而实现过滤的效果,比如过滤垃圾邮件。

  6. 限流。用Redis实现限流有两种方式:一种是可以通过ZSet数据类型实现简单限流;另一种是可以直接使用Redis-Cell模块,里面提供了漏斗限流的实现方式,我们可以直接使用指令cl.throttle [key] [capacity] [allowed_ops_num] [period] [now_ops_num]来判断操作是否允许执行,进而实现限流的效果。其中capacity为漏斗容量,periodallowed_ops_num代表时间段内允许的操作数(即漏水速率rate),now_ops_num代表本次执行的操作数。

    限流图解.png

  7. 消息队列。普通队列可通过Redis的list数据类型实现,lpush生产消息,rpop消费消息。消息多播可通过Redis的PubSub模块实现,publish指令发布消息,subscribe指令订阅消息,相比list实现而言,发布订阅机制支持多个消费者消费同一条消息。相比发布订阅机制而言,Redis的Stream模块更有消息持久化和消费组的特性,可通过xadd指令生产消息,通过xread指令消费消息。

4. Redis高性能

Redis一般被看做单线程组件,因为它的网络IO和指令处理都在单个线程中执行,之所以Redis能达到单机10w TPS的处理量级与它优雅的设计密不可分:

  1. Redis采用单线程来处理用户请求,省去了加锁和上下文切换的开销。
  2. Redis的数据读写操作都在内存中,省去了持久化时磁盘寻址和磁盘读写的开销,相对硬盘而言,内存读写的开销低到可忽略不计。
  3. 处理网络IO时采用了IO多路复用机制,非阻塞地读写网络数据,单个线程就可以同时处理多个网络通道的事件。
  4. 处理重负荷任务时,Redis会fork一个子进程进行处理,如执行bgrewriteaof操作重写AOF文件,执行bgsave命令进行快照,以及master全量复制。除此之外,Redis服务器在启动时会启动三个BIO进程,分别处理文件关闭、AOF 缓冲数据刷盘,以及清理对象的操作。

5. Redis与Memcache

Redis和Memcache都是常用的缓存组件,那么Redis和Memcache相比,又有啥区别和优势劣势呢?只有明白各自的适用场合,才能更好地选择缓存组件:

  1. 网络IO模型:Redis和Memcache都采用了多路复用网络IO模型,但是Memcache将处理线程分为负责监听的主线程和负责请求处理的worker子线程,可以发挥多核计算机的优势,Redis的单线程处理模型能省去加锁和线程上下文切换的开销。
  2. 数据类型:Memcache只支持以key-value形式存储和访问数据,而Redis支持多种数据类型,如String、List、Set、ZSet和Hash。
  3. 内存管理机制:Memcached默认使用Slab Allocation机制管理内存,预分配一大块内存作为内存池,将其分为大小不同的chunk来管理内存,存储数据时根据数据大小选择合适的chunk来存储,这种方式虽然避免了内存碎片,但是会造成一定的空间浪费;Redis使用现场申请内存的方式来管理内存,会在一定程度上造成内存碎片。
  4. 数据持久化:Memcache不支持数据持久化,而Redis可采用RDB和AOF这两种方式持久化数据。
  5. 集群管理方式:Memcached本身并不支持分布式,只能在客户端通过像一致性哈希这样的分布式算法来实现Memcached的分布式存储。Redis则在服务器端构建分布式存储,它的Cluster集群管理方案将所有数据划分为16384个slots,每个节点对应一个slot,每个slot对应多个节点,每个节点都含有slot与所有节点的映射信息,客户端访问任何节点都可以重定向到正确的节点。

Redis学习都包含哪些知识点

到这里,这一节关于Redis的简介已经介绍完了。这里继续介绍一下Redis的学习脉络,同时为后续博客打一个预告:

  1. 详细学习Redis的数据类型以及内部的存储方式:Redis中的字符串采用SDS的结构来存储,对于String类型,当它为数值时采用int编码,当它为短字符串时采用embstr编码,只需一次内存申请,当它为长字符串时采用raw编码,需多次申请内存;对于List而言,其底层数据采用quicklist结构来存储,当元素多时采用链表实现;对于Set而言,它的底层采用hashtable实现;对于ZSet而言,当元素少时采用ziplist实现,元素多时采用hashtable+skiplist的方式实现;对于Hash而言,元素少时采用ziplist实现,元素多时采用hashtable实现。
  2. Redis的高级数据结构,如紧凑列表和基数树,及其在Redis中的应用。
  3. 跳出数据类型,纵观Redis数据库的整体存储方式,Redis总共有16个db,每个db包含两个dict,一个存储数据,一个存储过期时间。每个dict中包含两个dictht(即hashtable),一个用于日常存储数据,另一个在渐进式rehash时用到。再紧接着就是每个dictht中存储Redis中的key-value数据了,其中value可指向不同的Redis数据类型。
  4. Redis的过期键删除、内存回收、内存超限淘汰机制,是fork子进程异步执行还是在主线程中执行,是立即执行还是通过定时任务执行。
  5. Redis中的持久化机制,包括RDB和AOF的执行策略(主进程执行还是子进程执行,定时还是非定时、刷盘策略),持久化时对过期键的处理。
  6. Redis的客户端与服务器管理,安全使用Redis。
  7. Redis中的多机数据库的实现,包括主从同步(全量/增量以及实现方式)、Sentinel监控和故障转移、Cluster集群管理方案。
  8. Redis的高级功能及其实现,如发布订阅机制、Stream、事务、管道。
  9. 其他:Lua脚本、key操作、对象操作、数据库操作、排序、慢查询日志、监视器。
  10. 详细解说Redis的应用,如分布式锁、布隆过滤器...
  11. 从Redis到分布式缓存,解析分布式缓存的重点难点:如缓存失效、缓存穿透、缓存雪崩等等

读者如果有什么疑问或者建议可以在下方留言,我将会在看到的第一时间给予解答或者完善文章,提升自己也惠及他人

你可能感兴趣的:(一. Redis简介)