Redis学习1

一、Redis概述

Redis是一种基于键值对(key-value)的NoSQL数据库,与许多其他键值对数据库不同之处在于,Redis中的值可以采用多种数据结构和算法组成,包括字符串、哈希、列表、集合、有序集合、位图、HyperLogLog、地理信息定位等。因此,Redis可以满足许多不同的应用场景。由于Redis将所有数据存储在内存中,因此具有出色的读写性能。此外,Redis还可以通过快照和日志的形式将内存中的数据保存到硬盘上,以防止数据丢失,这对于处理类似断电或机器故障的情况至关重要。除了上述功能外,Redis还提供了诸如键过期、发布订阅、事务、流水线、Lua脚本等附加功能

二、为什么要用Redis

在单机系统中,直接通过定义变量来存储数据可能是更好的选择,但是在分布式系统中,各个节点都有自己的内存空间,无法直接共享变量,而Redis是一个分布式数据存储系统,提供了分布式特性,可以在多个节点之间共享数据,并提供了数据持久化、高可用性、数据结构丰富等功能

三、Redis为什么这么快

1、数据存放在内存中:内存的读写速度远快于磁盘存储

2、采用C语言实现:C语言实现的程序与操作系统之间的接口更为紧密,执行速度更快

3、单线程架构:Redis采用单线程架构,避免了多线程可能产生的竞争和同步问题

4、优化的数据结构和算法:Redis在设计和实现过程中采用了一些高效的数据结构和算法

5、异步操作:Redis支持异步操作:例如异步持久化和异步复制,这些操作不会阻塞主线程的执行,从而提高了系统的并发能力和响应速度

6、网络通信机制和使用了IO多路复用(epoll):

高效的网络通信:

  1. TCP协议: Redis采用TCP/IP协议进行网络通信。TCP协议是一种可靠的、面向连接的传输层协议,它提供了数据的可靠传输、流量控制、拥塞控制等功能,适用于对数据传输有较高要求的场景。通过使用TCP协议,Redis能够保证数据的可靠性和稳定性。
  2. 异步非阻塞IO: Redis使用异步非阻塞IO模型进行网络通信。在传统的同步阻塞IO模型中,每个连接都需要一个线程来处理,当连接数量较多时,会导致系统资源消耗过大。而采用异步非阻塞IO模型,可以利用少量的线程处理大量的连接,提高系统的并发处理能力和资源利用率。
  3. 事件驱动模型: Redis基于事件驱动模型进行网络通信。通过监听和处理事件,当有数据到达时立即进行处理,而不是等待数据准备好后才进行处理。这样可以最大程度地减少系统的等待时间,提高了系统的响应速度和吞吐量。

IO多路复用机制:

IO多路复用是一种在单个线程中管理多个输入/输出通道的技术,它允许一个线程同时监听多个输入流(例如网络套接字、文件描述符),并在有数据可读或可写时进行相应的处理,而不需要为每个通道创建一个独立的线程

epoll:

epoll是Linux特有的IO多路复用机制,它使用一个内核事件表来管理和监听多个IO事件的就绪状态。应用程序需要将需要监听的文件描述符添加到内核事件表中,然后调用epoll_wait函数进行监听。当有文件描述符就绪时,epoll_wait函数会返回,并告知哪些文件描述符已经准备好进行读取或写入操作。与select和poll不同的是,epoll使用回调函数来处理就绪的IO事件,而不需要应用程序遍历事件列表。

四、Redis可以用来做什么

缓存、排行榜系统、计数器应用、社交网络、session存储、消息队列系统

五、Redis常用命令

1、GET 命令:

语法:GET key

用于获取指定key的值,如果key不存在则返回nil(在Redis中,nil表示键不存在或键值为空)

2、SET 命令

语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]

保存键值对到Redis中,key为键,value为值(string类型),EX和PX用于设置键的过期时间,EX是秒级,PX是毫秒级,不设置时默认过期时间是-1,NX表示只有在键不存在时才设置值,XX表示只有在键存在时才设置值,他们都是可选参数

3、KEYS 命令

语法:KEYS pattern

pattern表示匹配规则,*表示匹配零个或多个字符,?匹配一个字符,[]匹配括号内的任意字符,类似于正则表达式

4、EXISTS 命令

语法:EXISTS key [key ...]

检查给定的键是否存在,可一次性检查多个key

5、DEL 命令

语法:DEL key [key ...]

一次性删除一个或多个key

6、EXPIRE 命令

语法:EXPIRE key seconds

设置过期时间,秒级

7、TTL 命令

语法:TTL key

查看指定key的剩余过期时间

8、TYPE 命令

语法:TYPE key

返回指定键对应的数据类型

六、Redis的键过期机制和内存淘汰策略

键过期机制
  1. 设置ttl:通过使用expire命令,为指定的键设置生存时间,到期自动删除
  2. 过期检查:Redis通过定时任务来检查键是否已经过期,在每次访问键时,都会先检查键是否已经过期,如果过期立即删除,此外,Redis还会在后台周期的扫描过期键,并删除已过期的键
  3. 惰性删除:为了提高性能,Redis采用了惰性删除的策略,当某个键过期后,不会立即删除,而是等到下次访问该键时才会删除。这样避免频繁地进行删除操作,提高了性能
内存淘汰策略
  1. LRU(Least Recently Used): 最近最少使用策略,Redis会根据键的最近访问时间来选择要删除的键,即删除最近最少被访问的键。
  2. LFU(Least Frequently Used): 最不经常使用策略,Redis会根据键被访问的频率来选择要删除的键,即删除访问频率最低的键。
  3. TTL(Time To Live): 过期时间策略,Redis会优先删除已经过期的键。
  4. Random(随机删除): 随机选择要删除的键。

基于优先队列和定时器的方式(Redis并未采用):

1、创建优先级队列:将所有设置了过期时间的键加入到一个优先队列中,优先级规则是过期时间越早的键优先级越高,即越早过期的键越靠前

2、启动定时器线程:启动一个单独的定时器线程,该线程负责检查队首元素的过期时间,并执行响应的任务

3、定时器线程主循环:

定时器线程在一个循环中执行以下操作:

(1)检查队首元素过期时间:查看队首元素是否过期

(2)执行任务:如果队首元素过期,执行删除操作

七、Redis采用单线程模型的优势

  1. 短平快的命令处理: Redis 的核心业务逻辑是基于内存的快速数据存储和处理,大多数命令操作都非常简单且耗时短暂。例如,GET、SET、INCR 等命令通常只涉及简单的内存读写操作,不会消耗过多的 CPU 资源。
  2. 非阻塞 I/O 操作: Redis 使用了非阻塞的 I/O 模型,通过事件驱动的方式处理网络请求。这意味着当 Redis 在等待网络 I/O 时,主线程可以继续处理其他请求,而不会因为等待而阻塞,从而最大程度地利用了 CPU 资源。
  3. 单线程的简单性: 单线程模型相对于多线程或多进程模型来说,实现起来更加简单,减少了线程间的同步和通信的复杂性。这使得 Redis 的代码更易于维护和调试。
  4. 避免了多线程的竞态条件和锁等问题: 在多线程环境下,需要考虑线程安全性和并发控制,例如竞态条件、死锁、资源争用等问题,而单线程模型可以避免这些问题的出现。

八、Redis中常见数据结构和内部编码

1、String

内部编码

  • int:这种编码方式用于存储长整型数据。在内存中,长整型数据占用8个字节的空间。当存储的值可以表示为长整型时,Redis会使用这种编码方式。
  • embstr:这是一种优化的编码方式,用于存储长度小于等于39个字节的字符串。在内存中,该编码方式只会消耗刚好所需的内存空间,避免了额外的内存开销。当存储的字符串较短时,Redis会选择这种编码方式。
  • raw:当存储的字符串长度超过39个字节时,Redis会使用这种编码方式。它可以处理长度大于39个字节的字符串,但会占用更多的内存空间。

使用场景:缓存功能,计数功能,共享session,手机验证码,分布式锁,消息队列,分布式ID生成器,数据统计

2、Hash

内部编码

  • ziplist(压缩列表): 当哈希类型元素个数小于 hash-max-ziplist-entries 配置(默认 512 个)且所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 使用 ziplist 作为哈希的内部实现。Ziplist 使用更加紧凑的结构实现多个元素的连续存储,从而在节省内存方面优于 hashtable。
  • hashtable(哈希表): 当哈希类型无法满足 ziplist 的条件时,Redis 会使用 hashtable 作为哈希的内部实现。在这种情况下,ziplist 的读写效率会下降,而 hashtable 的读写时间复杂度为 O(1)。因此,当哈希元素较多或者元素值较大时,Redis会选择使用 hashtable。

使用场景:映射关系表示用户信息

3、List

内部编码

quciklist优点:

  1. 灵活性:可以根据列表的大小动态地调整节点的大小,以最大限度地减少内存消耗
  2. 性能:quicklist在处理大型列表时具有较低的内存消耗和较高的性能,而在处理小型列表时也能保持较高的效率
  3. 节点分割:quicklist将列表分割成多个节点,每个节点都是一个压缩列表,这样可以降低在执行插入和删除操作时的复杂度,并提高整体的性能
  4. 压缩列表优化:quicklist使用压缩列表作为节点的存储方式,这种紧凑的数据结构可以有效地节省内存空间,并提高数据访问的速度

使用场景:消息队列,微博Timeline

4、Set

内部编码

  • intset(整数集合):当集合中的元素都是整数,并且元素的个数少于 Redis 配置参数 set-max-intset-entries(默认为 512 个)时,Redis 会选择 intset 作为集合的内部实现。intset 是一种紧凑且高效的数据结构,可以有效地节省内存空间。它以有序的方式存储整数元素,并通过压缩和编码来减少内存占用。
  • hashtable(哈希表):如果集合中的元素不满足 intset 的条件,即包含非整数元素或元素个数超过了 set-max-intset-entries 的限制,Redis 就会使用 hashtable 作为集合的内部实现。hashtable 提供了更灵活的存储方式,适用于各种类型的元素以及大规模的集合数据。它采用哈希表的方式存储元素,通过哈希算法来实现快速的元素查找和插入,但相比于 intset,它会占用更多的内存空间。

使用场景:存储标签和用户画像;求交集,如共同好友,共同兴趣标签;统计UV

五、Zset

内部编码

  • ziplist(压缩列表):在ziplist内部实现中,元素个数小于配置的 zset-max-ziplist-entries(默认 128 个)且每个元素的值都小于配置的 zset-max-ziplist-value(默认 64 字节)时,Redis会选择使用ziplist作为有序集合的内部实现。Ziplist采用紧凑的数据结构,通过将多个小的元素合并在一起以节省内存空间。它是一种节省内存的方法,但在大型集合上的性能可能会受到影响。
  • skiplist(跳表):当ziplist的条件不满足时,即元素个数超过了配置值或者元素的值超过了配置大小,有序集合会使用skiplist作为内部实现。Skiplist是一种随机化的数据结构,用于在有序集合中维护元素的顺序,并支持快速的插入、删除和查找操作。它通过多层链表结构实现,每层链表都是元素的子集,从而加快了查找速度。

跳跃表skiplist:

是一种基于有序列表的数据结构,通过添加多层索引来加速查找操作,它是一种随机化数据结构,可以在平均情况下实现较快的搜索、插入和删除操作。跳跃表在Redis中被广泛应用于实现有序集合和其他数据结构的底层实现

结构特点:
  1. 多层索引:跳跃表通过维护多层索引来加速查找操作,每一层索引都是原始链表的一个子集,最底层索引包含所有元素,而上层索引 则包含部分元素,每个元素在不同层级的索引中出现的概率是随机的
  2. 升维结构:每个节点包含多个指针,指向同一层中的下一个节点,以及可能指向其他层级中的节点,这种升维结构使得跳跃表的查找操作可以跳过多个元素,从而实现快速查找
  3. 平衡性:跳跃表的高度是对数级别的,并且每一层的节点数量都尽量保持平衡,使得在平均情况下查找操作的时间复杂度为O(logN),其中N为跳跃表中的元素数量
操作:
  1. 查找:跳跃表的查找操作类似于二分查找,从顶层索引开始,逐层向下查找,直到找到目标元素或者到达原始链表的底层
  2. 插入:插入操作首先需要执行查找操作,待找到插入位置的前一个节点,然后在相应的层级上插入新节点,并更新相应的指针
  3. 删除:删除操作也需要执行查找操作,找到待删除节点中前一个节点,然后在相应的层级上删除该节点,并更新相应的指针
优点:
  1. 快速查找: 跳跃表的平均查找时间复杂度为 O(logN),比较适用于有序集合等需要频繁查找的场景。
  2. 简单高效: 跳跃表的实现相对简单,插入和删除操作的时间复杂度也是 O(logN),在实际应用中表现良好。
  3. 支持范围查询: 跳跃表可以方便地支持范围查询操作,例如查找某个范围内的元素或者统计某个范围内的元素数量。
缺点:
  1. 空间复杂度高:跳跃表的多层索引会占用较多的额外空间,对于存储空间较为敏感的场景可能不太合适。
  2. 不支持动态扩容:跳跃表通常需要预先确定最大层数,因此不支持动态扩容,需要根据实际情况预先分配足够的空间

使用场景:排行榜系统

 

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值