redis 数据结构

Key操作

命令

keys *
keys n*e
keys n?

scan 0
scan 0 match xxx* count 1000

del key1 key2
unlink key1 key2
exists key1
rename a b
expire a 10
ttl a
type a
dbsize
randomkey
debug object key1

flushdb async
flushall async

scan要点

  • count参数代表扫描的槽位数

  • 返回为0表示全部扫描完成,否则根据返回游标继续扫描直到返回为0

  • 结果里的key可能重复,需要去重

  • 高位进位加法

普通加法:右侧加1,依次进位
高位进位加法:左侧添1

解决:避免扫描时扩容或缩容及rehash导致的对遍历过的槽位进行重复遍历。

大key扫描

#每100个scan指令就休息0.1
src/redis-cli --bigkeys -i 0.1

String

使用

set key value [EX seconds] [PX milliseconds] [NX(不存在才成功)|XX(已存在才成功)]
eg: set name imooc EX 10 NX
set name imooc
mset name imooc age 10
get name
mget name1 name2
getset name imooc
del name
incr a
decr a
incrby a 100
decrby a 100
append name zhangsan
setnx name imooc (如果存在key,则失败,返回0)
msetnx name libo age 10 (有一个失败,整个都失败)
setex name 10 libo (设置失效时间)
getrange name 0 5 (截取字符,从索引0到索引5)

原理

  • SDS(Simple Dynamic String)
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; //1byte,目前长度
    uint64_t alloc; //1byte,分配长度
    unsigned char flags; //1byte,使用不同结构体的标志位
    char buf[]; //内容
};
  • 所有Redis对象的header,共16bytes。
struct RedisObject { 
    int4 type; // 4bits  类型
    int4 encoding; // 4bits 存储格式
    int24 lru; // 24bits 记录LRU信息
    int32 refcount; // 32bits 引用计数
    void *ptr; // 8bytes,64-bit,指向对象内容的指针
} robj;
  • 字符串存储形式
    embstr:长度小于44(64 - 16 - 3),一次性分配空间,header和sds内存地址连续
    raw:长度大于44(64 - 16 - 3),两次分配空间,header和sds内存地址不连续
  • 扩容
    1M以前,每次X2
    1M以后,每次+1M
  • 优势
    1、长度获取,O(1)
    2、空间预分配,空间惰性释放
    3、二进制安全:可存储任意二进制

Hash

使用

hset myhash username "hello world"
hmset myhash a 1 b 2
hget myhash username
hmget myhash a b
hgetall myhash
hdel myhash a
hdel myhash a b
hincrby myhash a 100
hexists myhash a
hlen myhash
hkeys myhash
hvals myhash

hash里最后一个key移除后自动销毁数据结构

原理

类似Java HashMap,数组+链表
渐进式rehash

List

使用

lpush mylist a b c (insert by left side)
c index:0/-3
b index:1/-2
a index:2/-1

rpush mylist a b c (insert by right side)
a index:0/-3
b index:1/-2
c index:2/-1

lindex mylist 0
lrange mylist 0 -1 (show item from first to the end)
lrange mylist 0 -2 (show item from first to the reciprocal second)
lpop mylist (eject the the left item)
rpop mylist
llen mylist
lpushx mylist x (insert x into the left side when mylist has items)
rpushx mylist x
lrem mylist 0 a (remove all item is a in mylist)
lrem mylist 2 a (remove two a from the beginning)
lrem mylist -2 a (remove two a from the end)
lset mylist 3 x (insert x which the index is 3)
linsert mylist before a x (insert x before the first a)
linsert mylist after a x (insert x after the first a)
rpoplpush mylist mylist2 (eject the right item in mylist and insert it into the left side in mylist2)
blpop key1 key2 timeout(阻塞获取数据)

没有元素自动销毁数据结构

原理

链表

数据少时ziplist:连续内存存储
数据多时quicklist:多个ziplist+双向指针,快速增删

Set

使用

sadd myset a b c
sadd myset a (can not success)
srem myset a b
smembers myset 
sismember myset a
sdiff myset1 myset2 (myset1 - myset2)
sinter myset1 myset2 (交集)
sunion myset1 myset2 (并集)
scard myset
srandmember myset 
sdiffstore newset1 oldset1 oldset2
sinterstore newset1 oldset1 oldset2
sunionstore newset1 oldset1 oldset2

没有元素自动销毁数据结构

原理

类似Java HashSet,无序,唯一
value为null的字典

IntSet

  • set里都是整数且数量少
typedef struct intset {
    uint32_t encoding; //决定整数位宽,16位、32位、64位
    uint32_t length; //元素个数
    int8_t contents[]; //整数数组,可以是16位、32位、64位
} intset;
  • 存入非整数
    debug结果为hashtable

SortedSet

使用

zadd mysort 70 a 80 b 90 c
zadd mysort 100 a (replace the a's score)
zscore mysort a (show a's score)
zcard mysort (show count)
zrem mysort a b
zrange mysort 0 -1 (show all items by score asc)
zrange mysort 0 -1 withscores (从小到大)
zrevrange mysort 0 -1 withscores (从大到小)
zrangebyscore mysort 0 100 withscores limit 0 2
zrank mysort b (show rank of b,从小到大)
zrevrank mysort b (show rank of b,从大到小)
zremrangebyrank mysort 0 4 (remove by index)
zremrangebyscore mysort 80 100 (remove by score)
zincrby mysort 10 a (add 10 to item a)
zcount mysort 80 90

可以实现需轮询的延迟任务

最后一个value被删除销毁数据结构

原理

跳跃表
指针包含属性跨度span

ziplist(压缩列表)

zset和hash元素较少时采用ziplist存储
连续内存空间
debug结果ziplist
cascade update(字段记录前一个节点的长度且字段占用可变的空间)

<zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend>

// ziplist存储2和5
 [0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]
       |             |          |       |       |     |
    zlbytes        zltail    entries   "2"     "5"   end

//Hello world的entries部分
[02] [0b] [48 65 6c 6c 6f 20 57 6f 72 6c 64]

quicklist(快速列表)

debug结果是quicklist

image
  • list-max-ziplist-size -2

配置正数,ziplist里的数据项

配置负数 ziplist大小
-1 4kb
-2 8kb
-3 16kb
-4 32kb
-5 64kb
  • list-compress-depth 0

LZF无损压缩中间节点

配置 解释
0 没节点压缩
1 两端各1个节点不压缩,中间压缩
2 两端各2个节点不压缩,中间压缩
... ...(以此类推)

listpack

类似ziplist
本entry的长度字段放末尾
消除cascade update

Bitmap

使用

set AB ab
index 0-15
0110,0001; 0110,0000

getbit AB 6
setbit AB 6 1
get AB

bitcount AB (统计值为1的数量)
bitcount AB 0 0 (第一个字符的统计1数量)
bitcount AB 1 1  (第二个字符的统计1数量)
bitop对多个key做位元操作,AND,OR,XOR,NOT

原理

  • buffer[]逆序存储,方便在更高位修改且不移动原有位
    例如字符ab
    手写顺序
    buffer[0] -> b -> 0110,0010
    buffer[1] -> a -> 0110,0001
    逆序存储顺序
    buffer[0] -> a -> 0110,0001
    buffer[1] -> b -> 0110,0010

  • bitcount使用查表算法和variable-precision SWAR算法

HyperLogLog

使用

  • count
    基数(去重)统计(PV - Page View、UV - Unique View、IP等)。有误差。

  • 命令

pfadd key element [element...]
pfcount key
pfmerge destkey sourcekey [sourcekey...]

原理

(较复杂...)

BloomFilter

使用

  • contains。

判断结果为included时,可能误判。结果为not-include时,没有误判。
过滤结果为没见过时,可能误判。过滤结果为见过时,没有误判。

Image
  • 使用场景
    1、爬虫过滤相同url
    2、推送过滤相同信息(文章、视频)
    3、反垃圾信息(邮件、短信)
    4、解决缓存击穿

  • 命令

bf.reserve key 0.001 50000

bf.add key value
bf.exists key value

bf.madd key value1 value2
bf.mexists key value1 value2 value3

原理

数据经过多次hash落入位图。

空间占用在线计算:http://krisives.github.io/bloom-calculator/

(较复杂)
详解:https://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html

Geo

使用

  • 命令
geoadd
    geoadd key longitude latitude member [longitude latitude member ... ]
zrem
    zrem key member [member ... ]
geopos
    geopos key member [member ... ]
geodist
    geodist key member1 member2 [m(米)|km(千米)|ft(英尺)|mi(英里)]
geohash
    geohash member [member ... ]
georadius
    georadius key longitude latitude distance m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [Count count] [ASC(由近到远)|DESC(从远到近)]
georadiusbymember
    类似上面命令
    georadius key member distance m|km|ft|mi ......
  • 注意点
  1. 存入后轻微损失精度。
  2. (按省、市、区)拆分数据防止key对应数据量过大。

原理

  • GeoHash原理
  1. 经度按[-90, 90]对半分,左0右1,不断递归。
  2. 维度同理,按[-180, 180]对半分,左0右1,不断递归。
  3. 得到两串编码xxx, yyy,偶数位放经度,奇数位放纬度,得到zzz。
  4. zzz进行base32编码(转十进制进行字符映射)
  • GeoHash空间填充曲线
image
image
  • GeoHash注意点

GeoHash解决的是点数据问题,不适合线和面数据。
解决边界问题:同时计算本区域周围8块区域的所有点。
解决空间曲线突变问题:筛选出个别相似编码编码进行计算。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容