redis基础

1.什么是redis?

Redis(Remote Dictionary Server)是一个开源的、基于内存的、可选持久化的日志型Key-Value数据库编写,支持网络操作,并提供多种语言的API。Redis支持多种数据结构,包括字符串(string)、列表(list)、集合(set)、有序集合(zset)和哈希(hash),并且这些数据类型都支持丰富的操作,如push/pop、add/remove以及取交集、并集和差集等,这些操作都是原子性的。

Redis将数据存储在内存中,以保证高速的读写操作,同时支持将数据周期性地写入磁盘或记录追加操作,以实现持久化。它还支持主从同步,允许数据从主服务器复制到多个从服务器,以确保数据的高可用性和备份。

Redis的性能非常高,它在某些测试中实现了每秒读取110,000次和写入81,000次的速度。为了实现高并发性能,Redis使用非阻塞I/O和IO多路复用技术,如epoll(在Linux上)。

此外,Redis还提供了多种特性,如发布/订阅、Lua脚本、事务、管道、位图、键过期和哨兵监控机制等。它的一些优势包括简单稳定的源码、单线程模型、快速的单节点读写速度、丰富的数据类型、数据持久化能力、数据备份功能以及原子性操作。

总的来说,Redis是一个高性能、多功能的Key-Value数据库,适用于多种应用场景,如数据库、缓存和消息中间件,并且在计时器、消息队列、排行榜、社交网络等领域有广泛的应用。

2.redis为什么这么快?

(1) redis是单线程执行,在执行时顺序执行

redis单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。

也就是在执行操作这一阶段进行单线程操作,按执行顺序执行就可以避免并发所带来的问题。

(2) Redis的多路复用

从redis6.x开始采用io多路复用,让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。

NIO多路复用程序的底层实现参考深度解析Java NIO底层实现原理(初探服务器端程序)_sun.nio.ch.net native jvm-CSDN博客

(3)高效的数据结构

Redis支持五种主要数据结构:字符串(Strings)、列表(Lists)、哈希表(Hashes)、集合(Sets)和有序集合(Sorted Sets)。这些数据结构为开发者提供了灵活的数据操作方式,满足了不同场景下的数据存储需求。

字符串(Strings):最基本的数据类型,可以包含任何数据,如数字、字符串、二进制数据等。在Redis中,字符串是二进制安全的,这意味着它们可以有任何长度,并且不会因为包含空字符而被截断。

列表(Lists):简单的字符串列表,按照插入顺序排序。你可以添加一个元素到头部(左边)或者尾部(右边)。

哈希表(Hashes):是键值对的集合,是字符串类型的字段和值的映射表。适合存储对象。

集合(Sets):是字符串类型的无序集合。它是通过哈希表实现的,可以做到添加、删除、查找的时间复杂度都是O(1)。

有序集合(Sorted Sets):和Sets相似,但每个字符串元素都会关联一个浮点数类型的分数。元素的分数用来排序,如果两个成员有相同的分数,那么他们的排名按照字典序计算。

字符串的底层实现

创建一块内存空间,len是总长度,free是剩余的可用长度,char就是记录着我字符串字节码的情况

优势

预分配:SDS会为buf分配额外的未使用空间(通过free字段记录),这意味着当你向一个SDS字符串追加内容时,如果未使用空间足够,Redis就不需要重新分配内存。这减少了内存分配次数,从而提高了性能。

常数时间复杂度获取字符串长度:由于SDS结构内部维护了一个len字段来记录字符串的当前长度,获取字符串长度的操作可以在常数时间复杂度O(1)内完成,而不需要像C语言的原生字符串那样遍历整个字符串。

二进制安全:SDS可以存储任意二进制数据,包括空字符\0。C语言的原生字符串以空字符作为结束标志,这限制了它们不能包含空字符。而SDS则通过len字段来明确字符串的长度,因此不受此限制。

兼容C语言字符串函数:尽管SDS提供了自己的一套API来进行字符串操作,但它的buf字段实际上就是一个普通的C字符串(以\0结尾),这意味着在必要时,可以直接使用标准的C语言字符串处理函数来操作buf字段(尽管通常不推荐这样做,因为可能会破坏SDS结构的完整性)。

列表的底层实现:双向链表与压缩列表

压缩列表

当列表的元素数量较少且元素较小时,Redis会使用压缩列表(ziplist)作为底层实现来节省内存。压缩列表是一个紧凑的、连续的内存块,它按顺序存储了列表中的元素。

ZLBYTE: 压缩列表的头部信息,包含了特殊编码和压缩列表的长度信息。

LEN: 每个元素前的长度字段,用于记录该元素的长度或前一个元素到当前元素的偏移量。

‘one’, ‘two’: 实际的列表元素,它们被连续地存储在压缩列表中。

优势

内存利用率高,因为元素是连续存储的,没有额外的指针开销。

对于小列表,操作速度可以很快,因为所有数据都在一个连续的内存块中。

双向链表

当列表的元素数量较多或者元素较大时,Redis会选择使用双向链表作为底层实现。双向链表中的每个节点都保存了前一个节点和后一个节点的指针,这使得在列表的任何位置插入或删除元素都变得相对容易

优势

可以在O(1)时间复杂度内完成在列表头部或尾部的元素插入和删除。

当需要遍历列表时,可以从头部或尾部开始,沿着节点的指针依次访问。

哈希的底层实现:Redis中的字典与压缩列表

Redis的哈希(Hashes)类型允许用户在单个键中存储多个字段和对应的值。为了高效地支持这种数据结构,Redis在底层使用了两种主要的数据结构来实现哈希:字典(也称为哈希表)和压缩列表。

压缩列表

当哈希中的字段和值较少且较小时,Redis会使用压缩列表作为底层实现来节省内存。压缩列表是一种紧凑的、连续的内存块,它按顺序存储了哈希中的字段和值对。同上

字典(HASH表)

当哈希中的字段和值较多或者较大时,Redis会选择使用字典作为底层实现。字典是一种通过键(在Redis哈希中是字段)来直接访问值的数据结构,它能够在平均情况下提供O(1)时间复杂度的查找、插入和删除操作。

优势

提供了快速的字段查找、插入和删除操作。

哈希表的扩容机制可以保持较低的哈希冲突率,从而保证操作的效率

集合的底层实现:整数集合和字典

Redis的集合(Sets)是一个无序的、元素不重复的集合。为了高效地支持这种数据结构及其操作,Redis在底层使用了两种主要的数据结构:整数集合(intset)和字典(hashtable)。

整数集合(int set)

当集合中的元素都是整数,并且元素数量较少时,Redis会选择使用整数集合作为底层实现。整数集合是一个紧凑的数组,数组中的每个元素都是集合中的一个整数。

优势:

内存利用率高:整数集合将整数紧密地存储在一个连续的内存块中,没有额外的指针或元数据开销。

操作速度快:对于整数集合中的元素,Redis可以直接通过数组索引访问,这使得查找、添加和删除整数的操作非常快速。

然而,整数集合也有其局限性。由于它要求集合中的元素必须是整数,并且元素数量较少,因此在处理非整数元素或大量元素时,整数集合可能不是最优的选择。

有序集合的底层实现:跳表和压缩列表

Redis的有序集合(Sorted Sets)是一个有序的、元素不重复的集合,其中每个元素都关联了一个分数(score)。为了实现这种数据结构及其相关操作的高效性,Redis在底层主要使用了两种数据结构:压缩列表(ziplist)和跳表(skiplist)。

跳表(skiplist)

当有序集合的元素数量较多或元素的大小较大时,Redis会使用跳表作为底层实现。跳表是一种多层的有序链表,它通过维护多个层次的指针来加快查找、插入和删除操作的速度。

优势

查找效率高:通过维护多个层次的指针,跳表可以在平均情况下提供O(log N)时间复杂度的查找操作,其中N是元素的数量。

插入和删除操作快速:跳表的插入和删除操作只需要局部地调整指针,而不需要移动大量的数据。

支持范围查询:跳表可以方便地支持按照分数范围查询元素的操作

(3)redis中多线程使用

Redis中支持将数据异步写入磁盘,这种方式避免了每次写操作都要等待磁盘I/O完成,提升了写操作的速度

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值