《快学BigData》--Redis 总结(B)(27)

2023-03-06 21:15:33 浏览数 (2)

Redis储存类型

在以上的图上可以看出Redis是使用redisObject的对象来表示所有的key和value的,数据类型包括:String,Hash,List,Set,Sort Set编码的方式有Row,int,ht,zipmap,linkedlist,ziplist,intset方式,只有打开了 Redis 的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。

在设计时要注意一下几点:

1、key不要太长,尽量不要超过1024字节,这样不仅消耗内存,也会降低查找的效率

2、Key也不要太短,太短的话,key的可读性会降低

3、在项目中key的设计尽量使用规范的命名规则,如:userId:name:sex等

1-1)、String

A)、常用命令

set:设置key-value 的值

get:获取键为key的值

incr:递加键一次的整数值

decr:递减键一次的整数值

mget:得到所有的给定键的值

B)、实例

redis 127.0.0.1:6379> set baidu www.baidu.com

OK

redis 127.0.0.1:6379> get baidu

"www.baidu.com"

redis 127.0.0.1:6379> append baidu .link

(integer) 18

redis 127.0.0.1:6379> get baidu

"www.baidu.com.link"

redis 127.0.0.1:6379> set version 0

OK

redis 127.0.0.1:6379> incr version

(integer) 1

redis 127.0.0.1:6379> incr version

(integer) 2

redis 127.0.0.1:6379> get version

"2"

redis 127.0.0.1:6379> incrby versions 100

(integer) 100

redis 127.0.0.1:6379> get versions

"100"

redis 127.0.0.1:6379> type baidu

string

redis 127.0.0.1:6379> type version

string

redis 127.0.0.1:6379> rename baidu re-baidu

OK

redis 127.0.0.1:6379> get baidu

(nil)

redis 127.0.0.1:6379> get re-baidu

"www.baidu.com.link"

redis 127.0.0.1:6379> mget baidu

1) (nil)

redis 127.0.0.1:6379>

C)、使用场景

String是最常用的诗句的一种类型,普通的key/value的储存都可以归于此类。

D)、实现方式

String在redis储存的默认的是一个字符串,被reidsobject所引用,当与incr,decr时,就会转化为数值进行计算,此时的redisObject的encoding字段为int

1-2)、Hash

A)、常用命令

hset:HSET key field value 设置对象指定字段的值

hget:HGET key field 获取对象中该field属性域的值

hmset:HMSET key field value [field value ...] 同时设置对象中一个或多个字段的值

hmget:HMGET key field[field...] 获取对象的一个或多个指定字段的值

hgetall:HGETALL key 获取对象的所有属性域和值

hvals:HVALS key 获取对象的所有属性值

hlen:HLEN key 获取对象的所有属性字段的总数

hexists:HEXISTS key field 查看对象是否存在该属性域

hdel:HDEL key field[field...] 删除对象的一个或几个属性域,不存在的属性将被忽略

B)、实例

redis 127.0.0.1:6379> HSET person name jack

(integer) 1

redis 127.0.0.1:6379> HSET peson age 10

(integer) 1

redis 127.0.0.1:6379> HSET person sex famale

(integer) 1

redis 127.0.0.1:6379> HGETALL person

1) "name"

2) "jack"

3) "sex"

4) "famale"

redis 127.0.0.1:6379> HKEYS person

1) "name"

2) "sex"

redis 127.0.0.1:6379> HVALS person

1) "jack"

2) "famale"

redis 127.0.0.1:6379> HDEL person name

(integer) 1

redis 127.0.0.1:6379> HGETALL person

1) "sex"

2) "famale"

redis 127.0.0.1:6379> HMGET person name

1) "jack"

redis 127.0.0.1:6379> HLEN person

(integer) 2

C)、使用场景

Hash一般的储存用户的对象的信息,例如用户的姓名,性别,生日等信息,使用普通的key/value来储存数据。

1-1)、以Key作为储存

方式一的是将ID作为key,其他的作为value封装成对象一序列化的方式来储存,这种方式的缺点是,增加序列化/反序列化的开销,并且在需要时修改其中的一项信息,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

1-2)、储存key-value匹配的方式

第二种是把用户信息对象有多少成员就存成多少个 key-value 对的形式,用用户 ID 对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化反序列化的开销和并发问题,但是用户 ID 为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

1-3)、Redis 储存Hash的方式

Key依然是ID,value是一个map,这个map的key是成员的属性,value是属性值,这样对数据的修改和储存都可以直接通过其内部Map的key(redis内部的key成为field),也就是通过key(id) field(属性的标签)就可以查询出对应的数据了,既不需要重复储存,也不需要序列化与反序列化带来的性能问题,很好的解决了这个问题。

这里需要注意的是,redis提供了接口hgetall会把全部的属性查询出来,这样数据多了会去遍历整个Map,由于redis是单线程的,遍历Map会比较慢,则会影响其他的线程的操作,索引查询时需要注意。

D)、实现方式

Redis Hash 对应的value的内部就是一个HashMap,HashMap的数据量的大小可以分为不用的方式,分为数据量少时会采用类似一维数组的方式来紧凑储存,而不会采用hashMap目的是节省redis的内存的空间,对应的value redisobject的encoding为zipmap,当数据量多时则会自动转化为hashmap此时的encoding为ht。

1-3)、List

A)、常用命令

lst:LSET key index value 在列表中的索引设置一个元素的值

lrange:LRANGE key start stop 从一个列表获取各种元素

rpush:RPUSH key value1 [value2] 添加一个或多个值到列表

rpushx:RPUSHX key value 添加一个值列表,仅当列表中存在

lindex:LINDEX key index 从一个列表其索引获取对应的元素

linsert:LINSERT key BEFORE|AFTER pivot value 在列表中的其他元素之后或之前插入一个元素

llen:LLEN key 获取列表的长度

lpop:LPOP key 获取并取出列表中的第一个元素

lrem:LREM key count value 从列表中删除元素

ltrim:LTRIM key start stop 修剪列表到指定的范围内

B)、实例

redis 127.0.0.1:6379> LPUSH list redis

(integer) 1

redis 127.0.0.1:6379> LPUSH list redis1

(integer) 2

redis 127.0.0.1:6379> LPUSH list hello

(integer) 3

redis 127.0.0.1:6379> LPUSH list word

(integer) 4

redis 127.0.0.1:6379> LLEN list

(integer) 4

redis 127.0.0.1:6379> LRANGE list 0 3

1) "word"

2) "hello"

3) "redis"

4) "redis"

redis 127.0.0.1:6379> LRANGE list 0 5

1) "word"

2) "hello"

3) "redis"

4) "redis"

redis 127.0.0.1:6379> LPOP list

"word"

redis 127.0.0.1:6379> RPOP list

"redis"

redis 127.0.0.1:6379> LTRIM list 0 3

OK

redis 127.0.0.1:6379> LINDEX list 1

"redis"

redis 127.0.0.1:6379>

C)、使用场景

Redis list使用的比较多,由于他是一个消息队列,可以确保先后顺序,不必用mysql那样order by 来排序,利用LRANGE可以很方便的实现分页的功能,也可以实现关注的列表,粉丝列表等都可以用redis的list结构来实现,

D)、实现方式

Redis list 是以双向链表的方式来实现的,既可以支持反向查找和遍历,更方便操作,不过是给内存增加开销,redis内部的很多现实,包括发送缓冲队列等也是用的这个数据结构。

1-4)、Set

A)、常用命令

sunion:SUNION key [key ...] 添加多个set元素

srem:SREM key member [member ...] 从集合里删除一个或多个元素,不存在的元素会被忽略

spop:SPOP key [count] 获取并删除一个集合里面的元素

smove:SMOVE source destination member 移动集合里面的一个key到另一个集合

sinter:SINTER key [key ...] 获得两个集合的交集

sdiff:SDIFF key [key ...] 获得队列不存在的元素

sacrd:SCARD key 获取集合里面的元素数量

sadd:SADD key member [member ...] 添加一个或者多个元素到集合(set)里

sscan:SSCAN key cursor [MATCH pattern] [COUNT count] 迭代set里面的元素

smembers:SMEMBERS key 获取集合里面的所有key

sismember:SISMEMBER key member 确定一个给定的值是一个集合的成员

sdiffstore:SDIFFSTORE destination key [key ...] 获得队列不存在的元素,并存储在一个关键的结果集

B)、实例

redis 127.0.0.1:6379> SADD myset "hello"

(integer) 1

redis 127.0.0.1:6379> SADD myset "word"

(integer) 1

redis 127.0.0.1:6379> SMEMBERS myset

1) "word"

2) "hello"

redis 127.0.0.1:6379> SADD myset "one"

(integer) 1

redis 127.0.0.1:6379> SISMEMBER myset "one"

(integer) 1

redis 127.0.0.1:6379> SISMEMBER myset "two"

(integer) 0

redis 127.0.0.1:6379> sadd friends:leto ghanima paul chani jessica

(integer) 4

redis 127.0.0.1:6379> sadd friends:duncan paul jessica alia

(integer) 3

redis 127.0.0.1:6379> sismember friends:leto jessica

(integer) 1

redis 127.0.0.1:6379> sismember friends:leto vladimir

(integer) 0

redis 127.0.0.1:6379> sinter friends:leto friends:duncan

1) "jessica"

2) "paul"

redis 127.0.0.1:6379> sinterstore friends:leto_duncan friends:leto friends:duncan

(integer) 2

redis 127.0.0.1:6379>

C)、使用场景

Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。基本的操作包括添加,删除,交并集等等操作。也可以实现文章的标签,群聊中的成员等。

D)、实现方式

set 的内部实现是一个 value 永远为 null 的 HashMap,实际就是通过计算 hash 的方式来快速排重的,这也是 set 能提供判断一个成员是否在集合内的原因。

1-5)、Sorted Set

A)、常用命令

zadd:ZADD key score1 member1 [score2 member2] 添加一个或多个成员到有序集合,或者如果它已经存在更新其分数

zcard:ZCARD key 得到的有序集合成员的数量

zincrby:ZINCRBY key increment member 在有序集合增加成员的分数

zrange:ZRANGE key start stop [WITHSCORES] 由索引返回一个成员范围的有序集合(从低到高)

zrangebylex:ZRANGEBYLEX key min max [LIMIT offset count]返回一个成员范围的有序集合(由字典范围)

zrangebyscore:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 返回有序集key中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员,有序集成员按 score 值递增(从小到大)次序排列

zrank:ZRANK key member 确定成员的索引中有序集合

zrem:ZREM key member [member ...] 从有序集合中删除一个或多个成员,不存在的成员将被忽略

zscore:ZSCORE key member 获取给定成员相关联的分数在一个有序集合

zscan:ZSCAN key cursor [MATCH pattern] [COUNT count] 增量迭代排序元素集和相关的分数

B)、实例

redis 127.0.0.1:6379> ZADD dbs 100 redis

(integer) 1

redis 127.0.0.1:6379> ZADD dbs 98 mencache

(integer) 1

redis 127.0.0.1:6379> ZADD dbs 99 mongndb

(integer) 1

redis 127.0.0.1:6379> ZADD dbs 99 java

(integer) 1

redis 127.0.0.1:6379> ZCARD dbs

(integer) 4

redis 127.0.0.1:6379> ZCOUNT dbs 10 99

(integer) 3

redis 127.0.0.1:6379> ZRANK dbs java

(integer) 1

redis 127.0.0.1:6379> ZRANK dbs other

(nil)

redis 127.0.0.1:6379> ZRANGEBYSCORE dbs 98 100

1) "mencache"

2) "java"

3) "mongndb"

4) "redis"

C)、使用场景

Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择 sorted set 数据结构,比如 twitter 的 public timeline 可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。

D)、使用场景

Redis sorted set 的内部使用 HashMap 和跳跃表(SkipList)来保证数据的存储和有序,HashMap 里放的是成员到 score 的映射,而跳跃表里存放的是所有的成员,排序依据是 HashMap 里存的 score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

Skiplist 详解:http://blog.csdn.net/acceptedxukai/article/details/17333673

0 人点赞