Redis 为什么这么快?

  • 时间:
  • 浏览:3
  • 来源:uu快3计划_uu快3官方_单双

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

4.2 ziplist(压缩列表)

当有十几个 多列表键只包含几瓶列表项,且是小整数值或长度比较短的字符串时,这么了redis就使用ziplist(压缩列表)来做列表键的底层实现。

常数复杂度获取字符串长度:或者SDS在len属性中记录了长度,好多好多 获取有十几个 多SDS长度时间复杂度仅为O(1)。

里边源码后能 复杂成如下内控 :

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

Redis也使用链地址法来解决键冲突。即每个哈希表节点与有无十几个 多next指针,多个哈希表节点用next指针构成有十几个 多单项链表,链地址法就让我将相同hash值的对象组织成有十几个 多链表装入 hash值对应的槽位。

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

Set

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

当亲戚亲戚亲戚亲戚朋友执行set hello world命令时,会有以下数据模型:

SDS长度(len的值)大于等于1MB,守护进程会分配1MB的未使用空间。比如进行修改就让 ,SDS的len变成100MB,这么了它的实际长度是100MB+1MB+1byte。

set:sdscpy—O(n)

sadd:intsetAdd---O(1)

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

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

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

len:sdslen---O(1)

3、String

2

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

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

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

本文内容思维导图如下:

简单动态字符串(SDS),好多好多 内控 更像C++的String或者Java的ArrayList,长度动态可变:

llen:listLength ---O(N)

get:sdsrange---O(n)

4、List

push:listInsertNode ---O(1)

Zset:排行榜

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

预空间分配:或者对有十几个 多SDS进行修改,分为一下有本身情形:

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

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

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

本文作者:Java技术栈

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

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

Hash对象的底层实现后能 是ziplist(压缩列表)或者hashtable(字典或者也叫哈希表)。

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

5、Hash

redisObject对象非常重要,Redis对象的类型、内控 编码、内存回收、共享对象等功能,都还要redisObject支持。另有十几个 多设计的好处是,后能 针对不同的使用场景,对5中常用类型设置多种不同的数据内控 实现,从而优化对象在不同场景下的使用传输效率。

4.1 linkedlist(双端链表)

此内控 比较像Java的LinkedList,有兴趣后能 阅读一下源码。

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

好多好多 内控 类式于于JDK7就让 的HashMap,当有有十几个 多或以上的键被分配到哈希数组的同有十几个 多索引上时,会产生哈希冲突。

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

srem:intsetRemove---O(N)

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

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

Redis的对象redisObject

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

通过里边的应用场景后能 看出Redis是非常高效和稳定的,那Redis底层是怎么后能 实现的呢?

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

1、简介和应用

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

dictEntry:Redis给每个key-value键值对分配有十几个 多dictEntry,里边有着key和val的指针,next指向下有十几个 多dictEntry形成链表,好多好多 指针后能 将多个哈希值相同的键值对链接在一同,由此来解决哈希冲突那先 的问题(链地址法)。

index : listIndex ---O(N)

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

sds:键key“hello”是以SDS(简单动态字符串)存储,里边详细介绍。

create:sdsnew---O(1)

intset底层实现为有序,无重复数组保存集合元素。 intset好多好多 内控 里的整数数组的类型后能 是16位的,32位的,64位的。或者数组里所有的整数有无16位长度的,或者新加入有十几个 多32位的整数,这么了整个16的数组将升级成有十几个 多32位的数组。升级后能 提升intset的灵活性,又后能 节约内存,但不可逆。

lpush: listAddNodeTail ---O(1)

ZSet

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

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

ZSet有序集合对象底层实现后能 是ziplist(压缩列表)或者skiplist(跳跃表)。

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

intset(整数集合)当有十几个 多集合只包含整数,或者元素不要 有无使用intset(整数集合)作为Set集合对象的底层实现。

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

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

6

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

hashtable哈希表后能 实现O(1)复杂度的读写操作,或者传输效率很高。源码如下:

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

slen:intsetlen ---O(1)

7

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

Set集合对象的底层实现后能 是intset(整数集合)或者hashtable(字典或者也叫哈希表)。

惰性释放空间:当执行sdstrim(截取字符串)就让 ,SDS不用立马释放多出来的空间,或者下次再进行拼接字符串操作,且拼接的这么了刚才释放的空间大,则那先 未使用的空间就会排上用场。通过惰性释放空间解决了特定情形下操作字符串的内存重新分配操作。

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

redis所有的数据内控 类型如下(重要,里边会用):

rpush: listAddNodeHead ---O(1)