现在的位置: 首页 > 综合 > 正文

redis各种类型的存储情况分析

2018年05月20日 ⁄ 综合 ⁄ 共 4043字 ⁄ 字号 评论关闭

1:SORT命令的时间复杂度是0(n+mlogm),其中n表示要排序的列表(集合或有序集合)中的元素个数,m表示要返回的元素个数

   所以开发中使用SORT命令时需要注意以下几点。
(1)尽可能减少待排序键中元素的数量(使n尽可能小)。
(2)使用LIMIT参数只获取需要的数据(使m尽可能小)。
(3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存

2: 任务队列

   与任务队列进行交互的实体有两类,一类是生产者(producer),一类是消费者(consumer)。生产者会将需要处理的任务放入任务队列中,

而消费者则不断地从任务队列中读入任务信息并执行。

  使用任务队列的好处:1:松耦合,2:易于扩展消费者可以有多个。

 

#无限循环读取任务队列中的内容
loop
task=RPOR queue
if task
#如果任务队列中有任务则执行它
execute( task)
else
#如果没有则等待1秒以免过于频繁地请求数据
wait 1 second

BRPOP命令和RPOP命令相似,唯一的区别是当列表中没有元素时BRPOP命令会一直阻
塞住连接,直到有新元素加入。如上段代码可改写为:
loop
#如果任务队列中没有新任务,BRPOP 命令会一直阻塞,不会执行execute()。
task=BRPOP queue, 0
#返回值是一个数组(见下介绍),数组第二个元素是我们需要的任务。
execute( task[1])

BRPOP命令接收两个参数,第一个是键名,第二个是超时时间,单位是秒

当获得一个元素后BRPOP命令返回两个值,分别是键名和元素值

3:优先级队列

  BRPOP命令可以同时接收多个键,其完整的命令格式为BLPOP key [key …]timeout,如BLPOP queue:1 queue:2 0。

意义是同时检测多个键,如果所有键都没有元素则阻塞,如果其中有一个键有元素则会从该键中弹出元素

loop
task =
BRPOP queue:confirmation.email,
queue:notification.email,
0e
xecute( task[1])

4:发布/订阅模式

  “发布/订阅”模式中包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或若干个频道(channel),

而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。

发布者发布消息的命令是PUBLISH,用法是PUBLISH channel message,PUBLISH命令的返回值表示接收到这条消息的订阅者数量。

订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel[channel …]

进入订阅状态后客户端可能收到三种类型的回复。每种类型的回复都包含3个值,第一个
值是消息的类型,根据消息类型的不同,第二、三个值的含义也不同。消息类型可能的取值有:
(1)Subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个值是
当前客户端订阅的频道数量。
(2)message。这个类型的回复是我们最关心的,它表示接收到的消息。第二个值表示产生
消息的频道名称,第三个值是消息的内容。
(3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当
前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非“发
布/订阅”模式的命令了。

redis C>PSUBSCRIBE channel.?*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel.?*"
3) (integer) 1
规则channel.?*可以匹配channel.1和channel.10,但不会匹配channel.。

注意 使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道;

同样UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则

5:存储

 Redis的每个键值都是使用一个redisObject结构体保存的,redisObject的定义如下:
typedef struct redisObject {
unsigned type:4;
unsigned notused:2; /* Not used */
unsigned encoding:4;
unsigned lru:22; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
}robj;

其中type字段表示的是键值的数据类型,取值可以是如下内容:
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4

encoding字段表示的就是Redis键值的内部编码方式,取值可以是:
#define REDIS_ENCODING_RAW 0 /* Raw representation */
#define REDIS_ENCODING_INT 1 ed as integer */
#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
#define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */

字符串类型:

  1.字符串类型
Redis使用一个sdshdr类型的变量来存储字符串,而redisObject的ptr字段指向的是该变量
的地址。sdshdr的定义如下:
struct sdshdr {
int len;
int free;
char buf[];
};
其中len字段表示的是字符串的长度,free字段表示buf中的剩余空间,而buf字段存储的才是字符串的内容。

Redis启动后会预先建立10000个分别存储从0到9999这些数字的redisObject类型变量作为共享
对象,如果要设置的字符串键值在这10000个数字内(如SET key1 123)则可以直接引用共享对
象而不用再建立一个redisObject了,也就是说存储键值占用的空间是0字节

当执行了SET key1 123和SET key2 123后,key1和key2两个键都直接引用了一个已经建立好的共享对象,节省了存储空间

提示 当通过配置文件参数maxmemory设置了Redis可用的最大空间大小时,Redis不会使用共享对象,因为对于每一个键值都需要使用一个redisObject来记录其LRU信息。

散列类型

  散列类型的内部编码方式可能是REDIS_ENCODING_HT或
REDIS_ENCODING_ZIPLIST① 。在配置文件中可以定义使用REDIS_ENCODING_ZIPLIST方式编码散列类型的时机:

  hash-max-ziplist-entries 512
  hash-max-ziplist-value 64

当散列类型键的字段个数少于hash-max-ziplist-entries参数值且每个字段名和字段值的长
度都小于hash-max-ziplist-value参数值(单位为字节)时,Redis就会使用REDIS_
ENCODING_ZIPLIST来存储该键,否则就会使用REDIS_ENCODING_HT。

REDIS_ENCODING_HT编码即散列表,可以实现O(1)时间复杂度的赋值取值等操作,其
字段和字段值都是使用redisObject存储的

REDIS_ENCODING_ZIPLIST编码类型是一种紧凑的编码格式,它牺牲了部分读取性能以
换取极高的空间利用率,适合在元素较少时使用

该编码类型同样还在列表类型和有序集合
类型中使用。REDIS_ENCODING_ZIPLIST编码结构如图4-7所示,其中zlbytes是uint32_t类型,
表示整个结构占用的空间。zltail也是uint32_t类型,表示到最后一个元素的偏移,记录zltail使得
程序可以直接定位到尾部元素而无需遍历整个结构,执行从尾部弹出(对列表类型而言)等操
作时速度更快。zllen是uint16_t类型,存储的是元素的数量。zlend是一个单字节标识,标记结构
的末尾,值永远是255

第一个部分用来存储前一个元素的大小以实现倒序查找,当前一个元素的大小小于254字
节时第一个部分占用1个字节,否则会占用5个字节。
第二、三个部分分别是元素的编码类型和元素的大小,当元素的大小小于或等于63个字
节时,元素的编码类型是ZIP_STR_06B(即0<<6),同时第三个部分用6个二进制位来记录元
素的长度,所以第二、三个部分总占用空间是1字节。当元素的大小大于63且小于或等于16383
字节时,第二、三个部分总占用空间是2字节。当元素的大小大于16383字节时,第二、三个部
分总占用空间是5字节。
第四个部分是元素的实际内容,如果元素可以转换成数字的话Redis会使用相应的数字类
型来存储以节省空间,并用第二、三个部分来表示数字的类型(int16_t、int32_t等)。
使用REDIS_ENCODING_ZIPLIST编码存储散列类型时元素的排列方式是:元素1存储字
段1,元素2存储字段值1,依次类推,

例如,当执行命令HSET hkey foo bar命令后,hkey键值的内存结构如下图所示,

抱歉!评论已关闭.