vlambda博客
学习文章列表

Redis基础数据结构&基本应用

"

读书多了,容颜自然改变,许多时候,自己可能以为许多看过的书籍都成了过眼云烟,不复记忆,其实他们仍是潜在的。在气质里,在谈吐上,在胸襟的无涯,当然也可能显露在生活和文字里。by 三毛

"


概述

    Redis有5中基础的数据结构:string(字符串),list(列表),hash(字典),set(集合)和zset(有序集合);这些是Redis中最基础和最重要的部分


01
string(字符串)


    string是Redis中最简单的字符串,其内部表示就是一个数组,并且它是一个动态字符串,是可修改的字符串,其内部结构的实现类似于ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,即当前字符串分配的实际空间一般要高于实际字符串长度

    注意:当字符串长度小于1MB时,扩容都是加倍现有的空间.如果字符串长度超过1MB,扩容时一次只会多扩1MB的空间(字符串最大长度是512MB).

    使用:将要存入的信息使用JSON序列化成字符串,然后将序列化后的字符串塞进Redis,取信息时会经过一次反序列化的过程

键值对> set name codeOK> get name"code">exists name(integer) 1del name(integer) 1> get name(nil)批量键值对:对多个字符串进行读写,节省网络开销> set name1 codeOK> set name2 superOK>mget name1 name2 name31) "code"2) "super"3) (nil)> mset name1 boy name2 girl name3 unknow> mget name1 name2 name31) "boy"2) "girl"3) "unknow"过期和set命令扩展> set name code> get name"code"> expire name 5 #5s后过期> setex name 5 code  #5s后过期,等价于set+expire> setnx name code  #如果name不存在就执行set创建,如果已经存在则创建不成功计数:如果value是一个整数,还可以进行自增操作(范围是signed long最大值和最小值之间,超出范围Redis会报错)> set age 30OK> incr age(integer) 31> incrby age 5(integer) 36> incrby age -5(integer) 31

    字符串由多个字节组成,每个字节又由8个bit组成,如此便可以将一个字符串看成很多bit 的组合,这便是bitmap(位图)数据结构,后面会讲.


02
list(列表)


    Redis的list就相当于LinkedList(是链表,不是数组),这意味着list的插入和删除操作快,时间复杂度是O(1),同时也意味着索引定位很慢,时间复杂度是O(n).列表中每个元素都使用双向指针顺序,串起来可以同时支持向前向后遍历

    Redis列表结构常用来做异步队列使用.将需要延后处理的任务结构体序列化成字符串,塞进Redis的列表,另一个线程从这个列表中轮询数据进行处理

队列:常用于消息排队和异步逻辑处理> rpush books java golang(integer) 2> llen books(integer) 2> lpop books"java"> lpop books"golang"> lpop books(nil)栈:不常用> rpush books java golang(integer) 2> rpop books"golang"> rpop books"java"> rpop(nil)

慢操作:

    lindex相当于java链表的get(int index)方法,其实际操作是对链表进行遍历,性能随参数增大而变差

    ltrim(保留),ltrim的两个参数start_index和end_index定义了一个区间,在这个区间内的值,ltrim要保留,其它的都被砍掉,可以使用ltrim实现一个定长链表

    注意:index可以为负数,表示倒数的元素

> rpush books java python golang(integer) 3> lindex books 1"python"> lrange books 0 -11) "java"2) "python"3) "golang"> ltrim books 1 -1OK> lrange books 0 -11) "python"2) "golang"> ltrim books 1 0  #清空了整个列表OK> llen books(integer) 0以上命令皆谨慎使用

快速列表:

    实际上Redis列表的底层存储的不是一个简单的LinkedList,而是称之为"快速链表"(quicklist)的一个数据结构(不使用普通链表的原因是普通链表需要附加的指针空间太大,会浪费空间,还会加重内存的碎片化)

    首先在列表元素较少的情况下,会使用一块连续的内存存储,这个结构是压缩列表(ziplist),它将所有的元素彼此紧紧的挨着一起存储,分配的是一块连续的内存;当数据量较多时才会采用quicklist

    quicklist的组成是将链表和ziplist结合起来,也就是将多个ziplist使用双向指针串起来使用

Redis基础数据结构&基本应用


03
hash(字典)


    Redis的hash就相当于HashMap,是一个"数组"+"链表"的二维结构,当hash数组碰撞时就会将碰撞的元素使用链表串接起来;与HashMap不同的是,Redis字典的值只能是字符串

    HashMap在字典很大时候,rehash是个耗时操作,需要一次性全部rehash;Redis为了追求高性能,不能堵塞服务,所以采用渐进式rehash策略

    渐进式rehash会在rehash的同时,保留新旧两个hash结构,查询时会同时查询两个hash结构,然后在后续定时任务以及hash操作指令中,循序渐进的将旧hash中的内容一点点迁到新的hash结构中,当搬迁完成,新的hash结构就会取而代之

    hash结构在存储信息时,与字符串一次性全部序列化整个对象不同,hash可以对结构中每个字段单独存储;这样获取信息时就可以进行部分获取;但是存储消耗也要高于字符串

> hset books java "think in java" #如果有空格要用引号包起来(integer) 1> hset books golang "think in go"(integer) 1> hgetall books1) "java"2) "think in java"3) "golang"4) "think in golang"> hlen books(integer) 2> hget books java"think in java"> hset books golang "learning golang" #更新操作,所以返回0(integer) 0> hmset books pyhton "learning python" c "c premiere" #批量setOK

    同字符串一样,hash结构中单个子key也可以进行计数,对应的指令hincrby,其用法和字符串的incr用法一致


04
set(集合)


    Redis的set集合相当于HashSet,它内部的键值对是无序的,唯一的;它的结构就相当于一个特殊的字典,字典中所有的value都是Null

sadd books java(integer) 1> sadd books java #不允许重复(integer) 0> sadd books c golang(integer) 2> smembers books  #实际行和插入的顺序并不一致,set是无序的1"c"2) "golang"3) "java"> sismember books java #查询是否存在(integer) 1> sismember books r(integer) 0> scard books #获取长度(integer) 3> spop books #弹出一个"c"


05
zset(有序列表)


    类似于SortedSet和HashMap结合体,一方面具有set的value唯一性,另一方面可以给每个value赋予一个score,代表这个value的排序权重,其内部实现实际上是"跳跃列表"

> zadd books 9.0 java(integer) 1> zadd books 8.9 c(integer) 1> zadd books 8.0 golang(integer) 1> zrange books 0 -1  #按score排序列出,参数区间为排名范围1) java2) c3) golang> zrevrange books 0 -1 #逆序列出> zcard books  #相当于count()> zscore books c #获取指定value的score"8.9000000000000004" #内部score使用double存储,所以存在小数点精度问题> zrank java #获取排名> zrangebyscore books 0 8.91 #根据分值区间遍历zset1) golang2) c> zrangebyscore books -inf 8.91 withscores  #根据分值区间(-inf, 8.91]遍历zset,同时返回分值(inf代表infinite,无穷大d的意思)> zrem books java #删除value

跳跃列表:

    跳跃列表类似于一种层级制,最下面一层所有元素都会串起来,然后每个几个元素挑出一个代表,然后再将这几个代表使用另外一级指针串起来,然后在这些代表里面挑出二级代表,再串起来,以此类推


容器型数据结构的通用规则

  1. create if not exists:如果容器不存在,那就创建一个,再进行操作

  2. drop if not elements:如果容器中元素没有了,那么立即删除容器,释放内存


过期时间

    Redis所有数据结构都可以设置过期时间,时间到了,Redis会立即删除相应的对象.

需要注意的是,过期是以对象为单位的,比如一个zset结构的过期就是zset对象的过期,而不是其中的某个元素过期

    如果一个字符串设置了过期时间,在经过set修改之后并且没有重新设置过期时间,它的过期时间会消失


This browser does not support music or audio playback. Please play it in Weixin or another browser.