目录
Redis
Redis:全称Remote Dictionary Service,远程字典服务。
1. Redis基础数据结构
Redis的所有数据结构都是以一个唯一的字符串作为key,然后通过去这个key去获取不同的数据结构。
基础数据结构分成5种:
- string:字符串
- list:列表
- hash:哈希
- set:集合
- Zset:有序集合
1.1 string(字符串)
1.1.1 概念
Redis的字符串有len(长度)和cap(容量)的概念,len是字符串实际长度,cap是字符串的容量。当cap大小小于1m时,每次增加都会翻倍,超过1m时则会每次增加1m,cap的最大值为512m。
Redis字符串采用预分配冗余空间的方式(cap > len),避免了内存的频繁分配。
1.1.2 操作
字符串类型的操作
对单个字符串K-V进行修改,get
、set
命令
# key-value的增删改查
>set key value #新增和修改
OK
>get key #查询value
"value"
>exiist key #查询key
(integer) 1
>del key #删除key
(integer) 1
>get key #删除后查询不到
(nil)
批量键值对设置获取
命令mget
,mset
>mset name1 11111 name2 22222 name3 33333
OK
>mget name1 name2 name3
"11111"
"22222"
"33333"
expire
,key过期时间设置以及setex
、setnx
set命令的扩展
#key过期时间设置
>set name "test"
OK
>get name
"test"
>expire name 5 # 单位为秒
#wait for 5s
>get name
(nil)
#set扩展
>setex name 5 "test" # 在设置的同时设置过期时间
>setnx name "test" # 设置key,存在则设置失败,不存在则设置成功
自增命令incr
、incrby
,使用于value是整数。自增的范围是signed long的最大值和最小值
>set name 5
OK
>get name
5
>incr name
>get name
6
>incrby name 5
>get name
11
>incrby name -5
>get name
6
bitmap:一个字符串由字节组成,1个字节有8个bit组成,所以一个字符串有多个bit组成,这就是bitmap数据结构。
1.2 list(列表)
1.2.1 概念
Redis的列表相当于Java的LinkedList,他是一个链表而不是数组,链表特性就是增加和删除很快O(1)。但是寻找具体位置很慢O(n)。
当列表弹出最后一个元素的时候,该数据结构自动被删除,内存被回收。
List数据结构常用于做异步队列,将需要延后处理的结构体序列化成字符串塞进redis的列表,另一个线程从列表中轮询数据进行处理。
1.2.2 操作
rpush
和rpop
以及lpop
Redis中都是以rpush
来构建。根据rpop
和lpop
取不同方向的数据。rpop
取先存进list的数,类似队列,先进先出的特点,lpop
先去后面存入list的数据,类似栈,先进后出。
> rpush books Math English Golang
(integer) 3
> llen books
(integer) 3
> rpop books
"Golang"
> lpop books
"Math"
lindex
,相当于Java中连表里的get(int index)操作,需要对链表进行遍历,然后取第几个的值。
ltrim
,保留区间内的,去除区间外的,获取到一个新的链表。
lrange
,打印区间内的值
> rpush days Monday Tuesday Wednesday Thursday Friday Saturday Sunday #生成一个新的rpush
(integer) 7
> llen days
(integer) 7
> lindex days 2 #获取下标为2的值
"Wednesday"
> lindex days 0 #下标是由0开始的
"Monday"
> llen days
(integer) 7
> lrange days 0 -1 #-1是倒数第一个数,-2是倒数第二个数
1) "Monday"
2) "Tuesday"
3) "Wednesday"
4) "Thursday"
5) "Friday"
6) "Saturday"
7) "Sunday"
> llen days
(integer) 7
> ltrim days 1 -1 # 获取从第一个元素到最后一个元素的列表
OK
> llen days # 已经将原先第0位的Monday去除
(integer) 6
> lrange days 0 -1 #新生成列表2
1) "Tuesday"
2) "Wednesday"
3) "Thursday"
4) "Friday"
5) "Saturday"
6) "Sunday"
> ltrim days 1 -2 # 获取新生成列表2从第一个元素到最后二个元素的列表就是从Wednesday到Saturday
OK
> llen days
(integer) 4
> lrange days 0 -1 # 遍历列表,发现已经将原来的
1) "Wednesday"
2) "Thursday"
3) "Friday"
4) "Saturday"
list底层初解
当列表元素较少的时候使用的是ziplist
,通过将元素压缩存储在一个连续的内存上进行存储,当元素较多的时候使用的是quicklist
,通过链表和ziplist
结合起来,通过将多个ziplist
进行双向串联,避免了普通链表的空间浪费和内存碎片化的问题。
1.3 hash(字典)
1.3.1 概念
Redis中的字典相当于Java中的HashMap,
相同点:数组结合链表,无序。
不同点:Redis中hash的值只能存储字符串。Java的rehash操作是allin,一次性全部进行rehash,redis是渐进式rehash,在渐进式rehash中会在rehash中保留新旧两个hash,然后查询时查询两个,在后续才会将旧hash的内容慢慢同步到新hash中,当移除最后一个旧hash后,原数据结构会被删除。
hash的优点,在存储的时候可以对一个对象的不同字段进行分开存储,而字符串存储的时候需要将整个对象进行存储,在复杂对象存取上 消耗小于字符串
而对于单个字符串的情况,hash结构的存储消耗会高于单个字符串的消耗。
1.3.2 操作
hget
、hset
、hgetall
、hmset
,
hget
:获取单个key对应的value。
hset
:设置一个k-v键值对。
hgetall
:获取该key下的所有value。
hmset
:设置多个k-v键值对。
> hset books java "first book"
1
> hset books golang "second book"
1
> hset books php "third book"
1
> hgetall books
1) "java"
2) "first book"
3) "golang"
4) "second book"
5) "php"
6) "third book"
> hlen book
0
> hget books java
"first book"
> hset books golang "second book" # 更新前后没有改变
0
> hget books golang
"second book"
> hmset books java "update first book" golang "update second book" php "update third book" # 根据key批量修改value
OK
> hgetall books # 根据key批量获取value
1) "java"
2) "update first book"
3) "golang"
4) "update second book"
5) "php"
6) "update third book"
1.4 Set(集合)
1.4.1 概念
Redus的集合相当于Java里的HashSet,内部的键值对是无序的唯一的,也就是随机去重存入,所有的value都是null
1.4.2 操作
sadd
、spop
、smembers
、sismember
、scard
sadd
:添加value进入key集合。
spop
: 从key集合中取出value。
smembers
:展示集合中的所有元素。
sismember
:查询该集合中是否存在元素。
scard
:统计集合中一共拥有的元素个数。
> sadd member golang
(integer) 1
> sadd member golang
(integer) 0
> sadd member java php python
(integer) 3
> smembers member
1) "java"
2) "python"
3) "golang"
4) "php"
> sismember member java
(integer) 1
> sismember member javas
(integer) 0
> scard member
4
> spop member
"php"
> spop member
"golang"
> spop member
"java"
> spop member
"python"
> spop member
(nil)
1.5 ZSet(有序列表)
1.5.1 概念
ZSet 有两个特点,一是内部的value唯一,二是每个value都有自己的score,通过这个score可以进行排序。同样的当value 都被移除之后,数据结构会被删除,内存自动回收。
1.5.2 操作
zadd
:添加元素
zrange
:按排序参数进行输出
zrevrange
:按排序参数逆序输出
zcard
:计数k-v个数
zscore
:获取指定k-v的score
zrank
:获取该k-v的排名
zrankbyscore
:遍历输出score区间内的value,携带参数withscores
可以输出value和score。
zrem
:移除元素
> zadd items 9.99 "math" # zadd添加元素
(integer) 1
> zadd items 21.11 "chinese"
(integer) 1
> zadd items 101.11 "MaxMoney"
(integer) 1
> zadd items 3033.11 "RMB"
(integer) 1
> zrange items 0 -1 # 遍历范围内的value,按score顺序输出
1) "math"
2) "chinese"
3) "MaxMoney"
4) "RMB"
> zrevrange items 0 -1 # 遍历范围内的value,按score逆序输出
1) "RMB"
2) "MaxMoney"
3) "chinese"
4) "math"
> zcard items # 计算k-v的数量
4
> zscore items "RMB" # 输出k-v对应的score
3033.11
> zrank items "RMB" # 输出k-v对应的排序,从零开始,顺序
3
> zrank items "math"
0
> zrangebyscore items 0 100 # 遍历score在区间内的value,输出value
1) "math"
2) "chinese"
> zrangebyscore items 0 100 withscores # 遍历score在区间内的value,输出value和score
1) "math"
2) 9.99
3) "chinese"
4) 21.11
> zrem items math # 移除元素
1
> zrangebyscore items 0 100 withscores # 移除元素后的结果展示,用于对比,展示zrem的作用
1) "chinese"
2) 21.11
1.6 跳跃链表
跳跃连表是ZSet列表的内部数据结构,他基础数据结构是一个普通的链表,将所有的元素串起来。
然后在这些基础链表结点中选择出更高一级的节点,然后将这些更高一级的节点用一个链表穿起来,这
样就会出现一些链表节点可能会身兼数职,即使低级链表的节点也是高级列表的节点。新增的时候新节
点成为身兼数职的节点的概率是随机的。二分递减,最底层也就是所有元素穿起来的一层概率为1,每往上一级概率*0.5。
1.7 容器型数据结构的通用规则
容器型数据结构:
- list
- set
- zset
- hash
规则1:create if not exists
如果容器不存在,则创建一个新的数据结构。
规则2:drop if no elements
如果容器内元素没有了,那么立即删除元素,释放内存。
1.8 过期时间
Redis中所有的数据结构都可设过期时间,时间一到则会自动删除改k-v对象,而不是只删除一个value。
学习自《Redis深度历险:核心原理和应用实践》