Redis 为什么这么快?

  • 时间:
  • 浏览:1

Hash对象还要能了一同满足下面有哪几次条件时,才会使用ziplist(压缩列表):1.哈希中元素数量小于51有哪几次;2.哈希中所有键值对的键和值字符串长度都小于64字节。

zadd---zslinsert---平均O(logN), 最坏O(N)

Redis是有哪几次由ANSI C语言编写,性能优秀、支持网络、可持久化的K-K内存数据库,并提供多种语言的API。它常用的类型主要是 String、List、Hash、Set、ZSet 这5种。

Redis也使用链地址法来解决键冲突。即每个哈希表节点全是有哪几次next指针,多个哈希表节点用next指针构成有哪几次单项链表,链地址法要是将相同hash值的对象组织成有哪几次链表放入去hash值对应的槽位。

List对象的底层实现是quicklist(快速列表,是ziplist 压缩列表 和linkedlist 双端链表 的组合)。Redis中的列表支持两端插入和弹出,并还要能获得指定位置(或范围)的元素,还要能充当数组、队列、栈等。

Redis的对象redisObject

sadd:intsetAdd---O(1)

skiplist的查找时间复杂性度是LogN,还要能和平衡二叉树相当,但实现起来又比它简单。跳跃表(skiplist)是三种生活有序数据特性,它通过在某个节点中维持多个指向有些节点的指针,从而达到快速访问节点的目的。

smembers:intsetGetO(1)---O(N)

pop:ListFirst/listLast ---O(1)

String:缓存、限流、计数器、分布式锁、分布式Session

6

4.1 linkedlist(双端链表)

此特性比较像Java的LinkedList,有兴趣还要能阅读一下源码。

原文发布时间为:2019-1-3

本文作者:Java技术栈

本文来自云栖社区合作伙伴“ Java技术栈 ”,了解相关信息还要能关注“javastack”微信公众号

Hash:存储用户信息、用户主页访问量、组合查询

1、简介和应用

set:sdscpy—O(n)

字符串对象的底层实现还要能是int、raw、embstr(上边的表对应有名称介绍)。embstr编码是通过调用一次内存分配函数来分配一块连续的空间,而raw还要能了调用两次。

当有哪几次有序集合的元素数量比较多将会成员是比较长的字符串时,Redis就使用skiplist(跳跃表)作为ZSet对象的底层实现。

index : listIndex ---O(N)

为了让哈希表的负载因子维持在有哪几次合理范围内,Redis会对哈希表的大小进行扩展或收缩(rehash),也要是将ht【0】上边所有的键值对分多次、渐进式的rehash到ht【1】里。

无论是dictEntry对象,还是redisObject、SDS对象,都还要能了内存分配器(如jemalloc)分配内存进行存储。jemalloc作为Redis的默认内存分配器,在减小内存碎片方面做的相对比较好。

上图中,直接在Redis中扣减库存,记录日志后通过Worker同步到数据库,在设计同步Worker时还要能了考虑并发解决和重复解决的问提报告 。

ZSet有序集合对象底层实现还要能是ziplist(压缩列表)将会skiplist(跳跃表)。

通过上边的应用场景还要能看出Redis是非常高效和稳定的,那Redis底层是咋样实现的呢?

4、List

杜绝缓冲区溢出:使用C字符串的操作时,将会字符串长度增加(如strcat操作)而忘记重新分配内存,很容易造成缓冲区的溢出;而SDS将会记录了长度,相应的操作在将会造成缓冲区溢出回会自动重新分配内存,杜绝了缓冲区溢出。

从图中还要能看出Redis的linkedlist双端链表有以下特性:节点中有 prev、next指针、head指针和tail指针,获取前置节点、后置节点、表头节点和表尾节点的复杂性度全是O(1)。len属性获取节点数量也为O(1)。

7

当我们我们执行set hello world命令时,会有以下数据模型:

List:微博关注人时间轴列表、简单队列

Set集合对象的底层实现还要能是intset(整数集合)将会hashtable(字典将会也叫哈希表)。

前面说过,Redis每个对象由有哪几次redisObject特性表示,它的ptr指针指向底层实现的数据特性,而数据特性由encoding属性决定。比如我们我们执行以下命令得到存储“hello”对应的编码:

slen:intsetlen ---O(1)

4.2 ziplist(压缩列表)

当有哪几次列表键只中有 极少量列表项,且是小整数值或长度比较短的字符串时,没人redis就使用ziplist(压缩列表)来做列表键的底层实现。

intset(整数集合)当有哪几次集合只中有 整数,并且我元素不必 回会使用intset(整数集合)作为Set集合对象的底层实现。

dictEntry:Redis给每个key-value键值对分配有哪几次dictEntry,上边有着key和val的指针,next指向下有哪几次dictEntry形成链表,你这些 指针还要能将多个哈希值相同的键值对链接在一同,由此来解决哈希冲突问提报告 (链地址法)。

3、String

SDS长度(len的值)小于1MB,没人程序将分配和len属性同样大小的未使用空间,这时free和len属性值相同。举个例子,SDS的len将变成15字节,则程序也会分配15字节的未使用空间,SDS的buf数组的实际长度变成15+15+1=31字节(额外有哪几次字节用户保存空字符)。

push:listInsertNode ---O(1)

SDS长度(len的值)大于等于1MB,程序会分配1MB的未使用空间。比如进行修改后后,SDS的len变成60 MB,没人它的实际长度是60 MB+1MB+1byte。

Set

hashtable哈希表还要能实现O(1)复杂性度的读写操作,并且我下行强度 很高。源码如下:

你这些 特性类似JDK7后后的HashMap,当有有哪几次或以上的键被分配到哈希数组的同有哪几次索引上时,会产生哈希冲突。

quickList 是 zipList 和 linkedList 的混合体。它将 linkedList 按段切分,每一段使用 zipList 来紧凑存储,多个 zipList 之间使用双向指针串接起来。将会链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存全是单独分配,会加剧内存的碎片化,影响内存管理下行强度 。推荐阅读:史上最全 60 道 Redis 面试题。

Redis在互联网公司一般有以下应用:

比如jemalloc在64位系统中,将内存空间划分为小、大、巨大有哪几次范围;每个范围内又划分了有些小的内存块单位;当Redis存储数据时,会选者大小最大慨的内存块进行存储。

与双端链表相比,压缩列表还要能节省内存空间,并且我进行修改或增删操作时,复杂性度较高;并且我当节点数量较少时,还要能使用压缩列表;并且我节点数量多时,还是使用双端链表划算。更多请在Java技术栈微信公众号后台回复:redis。

zrem---zsldelete---平均O(logN), 最坏O(N)

Redis中的字典使用hashtable作为底层实现说说,每个字典会中有 有哪几次哈希表,有哪几次平时使用,没人 仅在rehash(重新散列)时使用。随着对哈希表的操作,键会逐渐增多或减少。推荐阅读:这将会是史上最全 Redis 高可用解决方案总结。

llen:listLength ---O(N)

ZSet

常数复杂性度获取字符串长度:将会SDS在len属性中记录了长度,全都有获取有哪几次SDS长度时间复杂性度仅为O(1)。

预空间分配:将会对有哪几次SDS进行修改,分为一下三种生活请况:

intset底层实现为有序,无重复数组保存集合元素。 intset你这些 特性里的整数数组的类型还要能是16位的,32位的,64位的。将会数组里所有的整数全是16位长度的,将会新加入有哪几次32位的整数,没人整个16的数组将升级成有哪几次32位的数组。升级还要能提升intset的灵活性,又还要能节约内存,但不可逆。

5、Hash

lpush: listAddNodeTail ---O(1)

len:sdslen---O(1)

再比如电商在大促销时,会用有些特殊的设计来保证系统稳定,扣减库存还要能考虑如下设计:

ziplist是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块(而全是像双端链表一样每个节点是指针)组成的顺序型数据特性;具体特性相对复杂性性,有兴趣读者还要能看 Redis 哈希特性内存模型剖析。在新版本中list链表使用 quicklist 代替了 ziplist和 linkedlist:

上边源码还要能复杂性成如下特性:

redis所有的数据特性类型如下(重要,上边会用):

int编码字符串对象和embstr编码字符串对象在一定条件下会转化为raw编码字符串对象。embstr:<=39字节的字符串。int:8个字节的长整型。raw:大于39个字节的字符串。

惰性释放空间:当执行sdstrim(截取字符串)后后,SDS不必立马释放多出来的空间,将会下次再进行拼接字符串操作,且拼接的没人刚才释放的空间大,则哪此未使用的空间就会排上用场。通过惰性释放空间解决了特定请况下操作字符串的内存重新分配操作。

quicklist 默认的压缩强度是 0,也要是不压缩。为了支持快速的 push/pop 操作,quicklist 的首尾有哪几次 ziplist 不压缩,此时强度要是 1。为了进一步节约空间,Redis 回会对 ziplist 进行压缩存储,使用 LZF 算法压缩。更多请在Java技术栈微信公众号后台回复:redis。

create:sdsnew---O(1)

Hash对象的底层实现还要能是ziplist(压缩列表)将会hashtable(字典将会也叫哈希表)。

redisObject对象非常重要,Redis对象的类型、结构编码、内存回收、共享对象等功能,都还要能了redisObject支持。没人 设计的好处是,还要能针对不同的使用场景,对5中常用类型设置多种不同的数据特性实现,从而优化对象在不同场景下的使用下行强度 。

Zset:排行榜

rpush: listAddNodeHead ---O(1)  

zrank--zslGetRank---平均O(logN), 最坏O(N)

redisObject:值val“world”存储在redisObject中。实际上,redis常用5中类型全是以redisObject来存储的;而redisObject中的type字段指明了Value对象的类型,ptr字段则指向对象所在的地址。

本文内容思维导图如下:

2

get:sdsrange---O(n)

Set:赞、踩、标签、好友关系

srem:intsetRemove---O(N)

简单动态字符串(SDS),你这些 特性更像C++的String将会Java的ArrayList,长度动态可变:

sds:键key“hello”是以SDS(简单动态字符串)存储,上边完整性介绍。