4、集合
(1)概略
集合(set)与列表相似,都是用来保存多个字符串,但集合与列表有两点不同:集合中的元素是无序的,因此不能经过索引来操作元素;集合中的元素不能有重复。
一个集合中最多可以存储2^32-1个元素;除了支持常规的增删改查,Redis还支持多个集合取交集、并集、差集。
(2)外部编码
集合的外部编码可以是整数集合(intset)或哈希表(hashtable)。
哈希表前面曾经讲过,这里略过不提;需求留意的是,集合在运用哈希表时,值全部被置为null。
整数集合的结构定义如下:
typedef struct intset{
uint32_t encoding;
uint32_t length;
int8_t contents[];
} intset;
其中,encoding代表contents中存储内容的类型,虽然contents(存储集合中的元素)是int8_t类型,但实践上其存储的值是int16_t、int32_t或int64_t,详细的类型便是由encoding决议的;length表示元素个数。
整数集适宜用于集合一切元素都是整数且集合元素数量较小的时分,与哈希表相比,整数集合的优势在于集中存储,节省空间;同时,虽然关于元素的操作复杂度也由O(n)变为了O(1),但由于集合数量较少,因此操作的时间并没有清楚优势。
(3)编码转换
只要同时满足下面两个条件时,集合才会运用整数集合:
集合中元素数量小于512个;
集合中一切元素都是整数值。
假设有一个条件不满足,则运用哈希表;且编码只能够由整数集合转化为哈希表,反方向则不能够。
下图展现了集合编码转换的特点:
5、有序集合
(1)概略
有序集合与集合一样,元素都不能重复;但与集合不同的是,有序集合中的元素是有顺序的。与列表运用索引下标作为排序依据不同,有序集合为每个元素设置一个分数(score)作为排序依据。
(2)外部编码
有序集合的外部编码可以是紧缩列表(ziplist)或腾跃表(skiplist)。ziplist在列表和哈希中都有运用,前面曾经讲过,这里略过不提。
腾跃表是一种有序数据结构,经过在每个节点中维持多个指向其他节点的指针,从而到达快速拜访节点的目的。除了腾跃表,完成有序数据结构的另一种典型完成是平衡树;大少数状况下,腾跃表的效率可以战争衡树媲美,且腾跃表完成比平衡树复杂很多,因此redis中选用腾跃表替代平衡树。
腾跃表支持平均O(logN)、最坏O(N)的复杂点停止节点查找,并支持顺序操作。Redis的腾跃表完成由zskiplist和zskiplistNode两个结构组成:前者用于保存腾跃表信息(如头结点、尾节点、长度等),后者用于表示腾跃表节点。详细结构相比照较复杂,略。
(3)编码转换
只要同时满足下面两个条件时,才会运用紧缩列表:
有序集合中元素数量小于128个;
有序集合中一切成员长度都不足64字节。
假设有一个条件不满足,则运用腾跃表;且编码只能够由紧缩列表转化为腾跃表,反方向则不能够。
下图展现了有序集合编码转换的特点:
五、运用举例
了解Redis的内存模型之后,下面经过几个例子阐明其运用。
1、预算Redis内存运用量
要预算redis中的数据占据的内存大小,需求对redis的内存模型有比较片面的了解,包括前面引见的hashtable、sds、redisobject、各种对象类型的编码方式等。
下面以最复杂的字符串类型来停止阐明。
假定有90000个键值对,每个key的长度是7个字节,每个value的长度也是7个字节(且key和value都不是整数);下面来预算这90000个键值对所占用的空间。在预算占据空间之前,首先可以判定字符串类型运用的编码方式:embstr。
90000个键值对占据的内存空间主要可以分为两部分:一部分是90000个dictEntry占据的空间;一部分是键值对所需求的bucket空间。
每个dictEntry占据的空间包括:
1) 一个dictEntry,24字节,jemalloc会分配32字节的内存块
2) 一个key,7字节,所以SDS(key)需求7+9=16个字节,jemalloc会分配16字节的内存块
3) 一个redisObject,16字节,jemalloc会分配16字节的内存块
4) 一个value,7字节,所以SDS(value)需求7+9=16个字节,jemalloc会分配16字节的内存块
5) 综上,一个dictEntry需求32+16+16+16=80个字节。
bucket空间:bucket数组的大小为大于90000的最小的2^n,是131072;每个bucket元素为8字节(由于64位系统中指针大小为8字节)。
因此,可以预算出这90000个键值对占据的内存大小为:90000*80 + 131072*8 = 8248576。
下面写个顺序在redis中验证一下:
public class RedisTest {
public static Jedis jedis = new Jedis("localhost", 6379);
public static void main(String[] args) throws Exception{
Long m1 = Long.valueOf(getMemory());
insertData();
Long m2 = Long.valueOf(getMemory());
System.out.println(m2 - m1);
}
public static void insertData(){
for(int i = 10000; i < 100000; i++){
(责任编辑:admin)