01_redis_基础数据结构

安装

  1. Docker
docker pull redis
docker run --name myredis -d -p6379:6379 redis
docker exec -it myredis redis-cli
  1. 直接安装
 brew install redis 
# ubuntu 
 apt-get install redis 
# redhat
 yum install redis 
# 运行客户端
 redis-cli
  1. 源码启动
    windows版:
    https://github.com/MSOpenTech/redis/releases
    解压:Redis-x64-3.2.100.zip
    在解压目录下
启动服务
redis-server.exe 
启动客户端,连接服务器
redis-cli.exe 
安装为windows服务
redis-server.exe --service-install redis.windows.conf 
卸载服务:
redis-server --service-uninstall
开启服务:
redis-server --service-start
停止服务:
redis-server --service-stop
重命名服务:
redis-server --service-name name

应用场景

  1. 记录帖子点赞数,评论数,点击数
  2. 缓存用户行为历史
  3. 有关id

数据结构

五种数据结构

  1. string
  2. list
  3. set
  4. hash
  5. zset

1. 字符串string

string 是redis最简单的数据结构,所有数据结构的key都是以唯一的string作为名称,然后通过key去找到value。不同类型的数据结构的差异都是value的结构不一样。
字符串的一个常见的用处就是缓存用户信息,将用户信息结构体使用json序列化成字符串,然后将序列化的字符串存到redis中。同样取出用户信息,也要进行反序列化。
redis的字符串是动态字符串,可以修改的字符串,内部结构类似与ArrayList,采用预分配空间来减少内存的频分分配,内部当前的字符串空间要大于实际字符串长度。当字符串小于1m的时候,扩容都是加倍现有的空间,如果超过1m,每次扩用只会扩1m。字符串的最大长度是512m

设置

#设置键值对
set key1 value1
#根据键获取值
get key1
#判断是否存在
exists key1
#删除
del key1

批量操作

#设置
 mset key1 value1 key2 value2
#获取
mget key1 key2

对key设置过期时间

#key1 5秒过期
expire key1 5 
#expire 等价 setex 
setex key2 5 value2
#如果 name 不存在就执行 set 创建
setnx key1 value1

计数

 set age 30 
#自增
incr age
#减少6
incrby  age -6
#自增是有范围的 在signed long之间

字符串有多个字节组成,每个字节由8个bit组成,可将字符串看成多个bit组成,这边是bitmap数据结构[位图]

list

list相当于linkedList,它是链表结构,插入和删除快,索引定位慢
当弹出最后一个元素,该数据结构被删除,内存自动回收。
list常用来做异步队列使用

  1. 队列   左进右出
rpush key value1 value2
llen key
lpop key  #value1
lpop key # value2
  1. 栈  右进右出
rpush key value1 value2 
rpop key #value2
rpop key #value1
  1. 慢操作
    相当于get(index),需要对链表进行遍历,随着index的增大性能变慢。ltrim跟着两个参数(start_index,end_index)定义了一个区间,区间内的保留,区间外的全部砍掉。可以通过ltrim实现一个定长的链表。index可以为负数,-1是倒数第一个元素,-2是倒数第二个元素
 rpush books python java golang 
 lindex books 1 # O(n) 慎用
 lrange books 0 -1 # 获取所有元素,O(n) 慎用
 ltrim books 1 -1 # O(n) 慎用
lrange books 0 -1 
 ltrim books 1 0 # 这其实是清空了整个列表,因为区间范围长度为负
  1. 快速列表
    redis底层存储不是简单的LinkedList ,而是一个快速列表quicklist的一个结构
    首先,在列表元素较少的情况下,会使用一块连续的内存存储,称之为ziplist,即压缩列表。将所有的元素紧挨着存储,分配的是一块连续的内存。当数据量大的时候会使用quicklist。因为普通的链表需要附件的指针空间太大,比较浪费空间,加重内存的碎片化。
    比如一个列表中只存int类型的数据,但是需要prev和next两个额外的指针,所以将列表和ziplist结合起来组成了quiklist。就是将多个ziplist使用双向指针穿起来使用。满足了插入和删除快,又不会出现太大的空间 冗余

字典hash

相当于HashMap。是无序字典。内部结构和HashMap一致。是数组+链表的二维结构。第一维数组的hash碰撞的时候,就会将碰撞的hash用链表存储起来。
但是redis的字典只能是string 。另外和HashMap的rehash不一样,reahs是一个很耗时的操作,HashMap在的字典很大的时候,需要一次全部rehash。而redis为可高性能,不能堵塞服务,采用了渐进式rehash
渐进式rehash,会在rehash的同时,保留新旧两个hash,查询时会查询两个hash结构,然后在后续的定时任务以及hash的子指令中,将旧hash的内容迁移到新hash中。当旧hash移除最后一个元素,该数据结构被删除,内存被回收。
hash结构也可以存用户信息,不同于字符串一次性需要全部 序列化整个对象,hash可以对用户结构的每个字段进行单独存储,当需要获取用户信息可以进行部分获取,而以字符串的形式进行存储用户信息只能一次性全部读取完,比较浪费网络流量。
hash也有缺点,hash结构的存储消耗要高于单个字符串,使用hash还是字符串根据实际情况来定。

> hset books java "think in java" # 命令行的字符串如果包含空格,要用引号括起来
(integer) 1
> hset books golang "concurrency in go"
(integer) 1
> hset books python "python cookbook"
(integer) 1
> hgetall books # entries(),key 和 value 间隔出现
1) "java"
2) "think in java"
3) "golang"
4) "concurrency in go"
5) "python"
6) "python cookbook"
> hlen books
(integer) 3
> hget books java
"think in java"
> hset books golang "learning go programming" # 因为是更新操作,所以返回 0
(integer) 0
> hget books golang "learning go programming"
> hmset books java "effective java" python "learning python" golang "modern golang
programming" # 批量 set
OK 

同字符串一样,hash 结构中的单个子 key 也可以进行计数,它对应的指令是 hincrby,
和 incr 使用基本一样。

> hincrby user-laoqian age 1
(integer) 30 

Set集合

相当于HashSet,内部的键值对是无序唯一的。内部实现相当于一个特殊的字典。字典中所有的value都有一个值NULL
当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。 set 结构可以用来存储活动中奖的用户 ID,因为有去重功能,可以保证同一个用户不会中奖两次。

> sadd books python
(integer) 1
> sadd bookspython # 重复
(integer) 0
> sadd books java golang
(integer) 2
> smembers books # 注意顺序,和插入的并不一致,因为 set 是无序的
1) "java"
2) "python"
3) "golang"
> sismember books java # 查询某个 value 是否存在,相当于 contains(o)
(integer) 1
> sismember books rust
(integer) 0
> scard books # 获取长度相当于 count()
(integer) 3
> spop books # 弹出一个
"java" 

zset (有序列表)

类似与HashMap和SortSet的结合。它是一个set,保证了内部value的唯一性,又给每个value赋予了score,代表了value的排序权重。内部实现是[跳跃列表]的数据结构。
zset 中最后一个 value 被移除后,数据结构自动删除,内存被回收。 zset 可以用来存粉丝列表,value 值是粉丝的用户 ID,score 是关注时间。我们可以对粉丝列表按关注时间进行排序。
zset 还可以用来存储学生的成绩,value 值是学生的 ID,score 是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。

> zadd books 9.0 "think in java" 
(integer) 1 
> zadd books 8.9 "java concurrency" 
(integer) 1 
> zadd books 8.6 "java cookbook" 
(integer) 1 
> zrange books 0 -1 # 按 score 排序列出,参数区间为排名范围
1) "java cookbook" 
2) "java concurrency" 
3) "think in java" 
> zrevrange books 0 -1 # 按 score 逆序列出,参数区间为排名范围
1) "think in java" 
2) "java concurrency" 
3) "java cookbook" 
> zcard books # 相当于 count()
(integer) 3 
> zscore books "java concurrency" # 获取指定 value 的 score
"8.9000000000000004" # 内部 score 使用 double 类型进行存储,所以存在小数点精度问题
> zrank books "java concurrency" # 排名
(integer) 1 
> zrangebyscore books 0 8.91 # 根据分值区间遍历 zset
1) "java cookbook" 
2) "java concurrency" 
> zrangebyscore books -inf 8.91 withscores # 根据分值区间 (-∞, 8.91] 遍历 zset,同时返
回分值。inf 代表 infinite,无穷大的意思。
1) "java cookbook" 
2) "8.5999999999999996" 
3) "java concurrency" 
4) "8.9000000000000004" 
> zrem books "java concurrency" # 删除 value
(integer) 1 
> zrange books 0 -1 
1) "java cookbook" 
2) "think in java"

跳跃列表

因为zset支持随机插入和删除,所以不好使用数组表示,采用跳跃列表。



跳跃列表中的元素可以身兼数职,如上图中间的元素,同时处于L0,L1,L2中,可以快速在不同层级进行跳跃。
定位插入点时,先在顶层进行定位,然后下潜到下一级定位,一直下潜到最底层找到合适的位置,将新元素插进去。你也许会问,那新插入的元素如何才有机会「身兼数职」呢?
跳跃列表采取一个随机策略来决定新元素可以兼职到第几层。
首先 L0 层肯定是 100% 了,L1 层只有 50% 的概率,L2 层只有 25% 的概率,L3 层只有 12.5% 的概率,一直随机到最顶层 L31 层。绝大多数元素都过不了几层,只有极少数元素可以深入到顶层。列表中的元素越多,能够深入的层次就越深,能进入到顶层的概率就会越大。

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