Redis 为什么这么快?

  • 时间:
  • 浏览:3
  • 来源:大发5分快3_极速5分PK10

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

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

intset底层实现为有序,无重复数组保存集合元素。 intset这种 形态学 里的整数数组的类型能不能 是16位的,32位的,64位的。愿因数组里所有的整数算不算 16位长度的,愿因新加入六个 32位的整数,没法 整个16的数组将升级成六个 32位的数组。升级能不能 提升intset的灵活性,又能不能 节约内存,但不可逆。

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

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

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

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

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

Zset:排行榜

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

通过顶端的应用场景能不能 看出Redis是非常高效和稳定的,那Redis底层是怎样实现的呢?

redis所有的数据形态学 类型如下(重要,顶端会用):

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

2

sds:键key“hello”是以SDS(简单动态字符串)存储,顶端全版介绍。

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

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

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

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

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

index : listIndex ---O(N)

预空间分配:愿因对六个 SDS进行修改,分为一下并算不算 具体情况:

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

rpush: listAddNodeHead ---O(1)  

Redis的对象redisObject

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

常数繁杂度获取字符串长度:愿因SDS在len属性中记录了长度,就让获取六个 SDS长度时间繁杂度仅为O(1)。

本文内容思维导图如下:

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

len:sdslen---O(1)

4.2 ziplist(压缩列表)

当六个 列表键只涵盖血块列表项,且是小整数值或长度比较短的字符串时,没法 redis就使用ziplist(压缩列表)来做列表键的底层实现。

1、简介和应用

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

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

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

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

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

create:sdsnew---O(1)

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

SDS长度(len的值)大于等于1MB,多多线程 会分配1MB的未使用空间。比如进行修改就让,SDS的len变成300MB,没法 它的实际长度是300MB+1MB+1byte。

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

上图中,直接在Redis中扣减库存,记录日志后通过Worker同步到数据库,在设计同步Worker时能不能 考虑并发补救和重复补救的大问题。

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

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

lpush: listAddNodeTail ---O(1)

4、List

push:listInsertNode ---O(1)

Set

7

顶端源码能不能 繁杂成如下形态学 :

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

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

srem:intsetRemove---O(N)

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

本文作者:Java技术栈

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

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

从图中能不能 看出Redis的linkedlist双端链表有以下形态学 :节点涵盖prev、next指针、head指针和tail指针,获取前置节点、后置节点、表头节点和表尾节点的繁杂度算不算 O(1)。len属性获取节点数量也为O(1)。

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

惰性释放空间:当执行sdstrim(截取字符串)就让,SDS我太久 立马释放多出来的空间,愿因下次再进行拼接字符串操作,且拼接的没法 刚才释放的空间大,则这种 未使用的空间就会排上用场。通过惰性释放空间补救了特定具体情况下操作字符串的内存重新分配操作。

ZSet

6

Redis中的字典使用hashtable作为底层实现得话,每个字典会涵盖六个 哈希表,六个 平时使用,就让仅在rehash(重新散列)时使用。随着对哈希表的操作,键会逐渐增多或减少。推荐阅读:这愿因是史上最全 Redis 高可用补救方案总结。

5、Hash

Redis也使用链地址法来补救键冲突。即每个哈希表节点算不算 六个 next指针,多个哈希表节点用next指针构成六个 单项链表,链地址法就让将相同hash值的对象组织成六个 链表中放hash值对应的槽位。

slen:intsetlen ---O(1)

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

get:sdsrange---O(n)

4.1 linkedlist(双端链表)

此形态学 比较像Java的LinkedList,有兴趣能不能 阅读一下源码。

3、String

set:sdscpy—O(n)

简单动态字符串(SDS),这种 形态学 更像C++的String愿因Java的ArrayList,长度动态可变:

intset(整数集合)当六个 集合只涵盖整数,就让元素太久算不算 使用intset(整数集合)作为Set集合对象的底层实现。

dictEntry:Redis给每个key-value键值对分配六个 dictEntry,顶端有着key和val的指针,next指向下六个 dictEntry形成链表,这种 指针能不能 将多个哈希值相同的键值对链接在同时,由此来补救哈希冲突大问题(链地址法)。

这种 形态学 类事JDK7就让的HashMap,当有六个 或以上的键被分配到哈希数组的同六个 索引上时,会产生哈希冲突。

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

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

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

sadd:intsetAdd---O(1)

hashtable哈希表能不能 实现O(1)繁杂度的读写操作,就让强度很高。源码如下:

llen:listLength ---O(N)