暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis 核心数据结构与高性能原理

LiusCoding 2021-03-25
292

一、Redis介绍

1. Redis 是什么

Remote Dictionary Server(Redis)是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map),列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

2. Redis的优缺点

  • 1 .支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash 表)、set(集合)、

zset(排序 set)、hyperloglog(基数估算)

  • 2. 支持持久化操作,可以进行 aof 及 rdb 数据持久化到磁盘,从而进行数据备份或数

    1据恢复等操作,较好的防止数据丢失的手段。

  • 支持通过 Replication 进行数据复制,通过 master-slave 机制,可以实时进行数据的

同步复制,支持多级复制和增量复制,master-slave 机制是 Redis 进行 HA 的重要手段。
单进程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题。

二、Redis的安装

 1下载地址:http://redis.io/download
2
3安装步骤:
4
5# 安装gcc
6yum install gcc
7
8# 把下载好的redis-5.0.3.tar.gz放在/usr/local文件夹下,并解压
9# 下载
10wget http://download.redis.io/releases/redis-5.0.3.tar.gz
11# 解压
12tar xzf redis-5.0.3.tar.gz
13cd redis-5.0.3
14
15# 进入到解压好的redis-5.0.3目录下,进行编译与安装
16make
17
18# 修改配置
19daemonize yes  #后台启动
20protected-mode no  #关闭保护模式,开启的话,只有本机才可以访问redis
21# 需要注释掉bind
22#bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
23
24# 启动服务
25src/redis-server redis.conf
26
27# 验证启动是否成功 
28ps -ef | grep redis 
29
30# 进入redis客户端 
31src/redis-cli 
32
33# 退出客户端
34quit
35
36# 退出redis服务: 
37(1)pkill redis-server 
38(2)kill 进程号                       
39(3)src/redis-cli shutdown 

三、Redis五种数据结构

Redis 命令参考

https://www.redis.net.cn/order/

image.png

1. String 结构

Redis 字符串是字节序列。Redis 字符串是二进制安全的,这意味着他们有一个已知的
长度没有任何特殊字符终止,所以你可以存储任何东西,512 兆为上限

image.png
 1字符串常用操作
2    SET  key  value                     //存入字符串键值对
3    MSET  key  value [key value ...]    //批量存储字符串键值对
4    SETNX  key  value                   //存入一个不存在的字符串键值对
5    GET  key                            //获取一个字符串键值
6    MGET  key  [key ...]                //批量获取字符串键值
7    DEL  key  [key ...]                 //删除一个键
8    EXPIRE  key  seconds                //设置一个键的过期时间(秒)
9    原子加减
10    INCR  key                           //将key中储存的数字值加1
11    DECR  key                           //将key中储存的数字值减1
12    INCRBY  key  increment              //将key所储存的值加上increment
13    DECRBY  key  decrement              //将key所储存的值减去decrement

String应用场景

image.png

image.png
 11、单值缓存
2    SET  key  value     
3    GET  key
4
5
62、分布式锁
7    SETNX  product:10001  true                  //返回1代表获取锁成功
8    SETNX  product:10001  true                  //返回0代表获取锁失败
9    。。。执行业务操作
10    DEL  product:10001                          //执行完业务释放锁
11    SET product:10001 true  ex  10  nx          //防止程序意外终止导致死锁
12
133、计数器
14    INCR article:readcount:{文章id}   
15    GET article:readcount:{文章id} 
16
174、Web集群session共享
18    spring session + redis实现session共享
19
205、分布式系统全局序列号    
21    INCRBY  orderId  1000                       //redis批量生成序列号提升性能
22
236、对象缓存
24    1) SET  user:1  value(json格式数据)
25    2) MSET  user:1:name  zhz   user:1:balance  1888
26        MGET  user:1:name   user:1:balance 

2. Hash 结构

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232  键值对(40多亿)。

image.png
 1Hash常用操作
2    HSET  key  field  value                     //存储一个哈希表key的键值
3    HSETNX  key  field  value                   //存储一个不存在的哈希表key的键值
4    HMSET  key  field  value [field value ...]  //在一个哈希表key中存储多个键值对
5    HGET  key  field                            //获取哈希表key对应的field键值
6    HMGET  key  field  [field ...]              //批量获取哈希表key中多个field键值
7    HDEL  key  field  [field ...]               //删除哈希表key中的field键值
8    HLEN  key                                   //返回哈希表key中field的数量
9    HGETALL  key                                //返回哈希表key中所有的键值
10    HINCRBY  key  field  increment              //为哈希表key中field键的值加上增量increment

Hash应用场景

image.png

image.png
 1对象缓存
2    HMSET  user  {userId}:name  ls  {userId}:balance  1888
3    HMSET  user  1:name  ls1:balance  1888
4    HMGET  user  1:name  1:balance 
5电商购物车
6    1)以用户id为key
7    2)商品id为field
8    3)商品数量为value
9购物车操作
10    添加商品->hset cart:1001 10088 1
11    增加数量->hincrby cart:1001 10088 1
12    商品总数->hlen cart:1001
13    删除商品->hdel cart:1001 10088
14    获取购物车所有商品->hgetall cart:1001

Hash 结构优缺点

优点

  • 同类数据归类整合存储,方便数据整理

  • 相比String操作消耗内存与cpu更小

  • 相比String存储更节省空间

缺点

  • 过期功能不能使用在field,只能用在key上

  • Redis集群架构下不适合大规模使用

3. List结构

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)一个列表最多可以包含 232 个元素 (4294967295, 每个列表超过40亿个元素)。

image.png
1List常用操作
2    LPUSH  key  value [value ...]       //将一个或多个值value插入到key列表的表头(最左边)
3    RPUSH  key  value [value ...]       //将一个或多个值value插入到key列表的表尾(最右边)
4    LPOP  key                           //移除并返回key列表的头元素
5    RPOP  key                           //移除并返回key列表的尾元素
6    LRANGE  key  start  stop            //返回列表key中指定区间内的元素,区间以偏移量start和stop指定
7
8    BLPOP  key  [key ...]  timeout      //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
9    BRPOP  key  [key ...]  timeout      //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待

List 应用场景

image.png

image.png

image.png
 11、常用数据结构
2    Stack(栈) = LPUSH + LPOP
3    Queue(队列)= LPUSH + RPOP
4    Blocking MQ(阻塞队列)= LPUSH + BRPOP
52、微博和微信公号消息流
63、微博消息和微信公号消息
7    /**
8    * 事例
9    **/
10    A关注了MacTalk,备胎说车等大V
11    1)MacTalk发微博,消息ID为10018
12    LPUSH  msg:{A-ID}  10018
13    2)备胎说车发微博,消息ID为10086
14    LPUSH  msg:{A-ID} 10086
15    3)查看最新微博消息
16    LRANGE  msg:{A-ID}  0  4

4. Set结构

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 2 (4294967295, 每个集合可存储40多亿个成员)。

image.png
 11、Set常用操作
2    SADD  key  member  [member ...]             //往集合key中存入元素,元素存在则忽略,若key不存在则新建
3    SREM  key  member  [member ...]             //从集合key中删除元素
4    SMEMBERS  key                               //获取集合key中所有元素
5    SCARD  key                                  //获取集合key的元素个数
6    SISMEMBER  key  member                      //判断member元素是否存在于集合key中
7    SRANDMEMBER  key  [count]                   //从集合key中选出count个元素,元素不从key中删除
8    SPOP  key  [count]                          //从集合key中选出count个元素,元素从key中删除
9
102、Set运算操作
11    SINTER  key  [key ...]                      //交集运算
12    SINTERSTORE  destination  key  [key ..]     //将交集结果存入新集合destination中
13    SUNION  key  [key ..]                       //并集运算
14    SUNIONSTORE  destination  key  [key ...]    //将并集结果存入新集合destination中
15    SDIFF  key  [key ...]                       //差集运算
16    SDIFFSTORE  destination  key  [key ...]     //将差集结果存入新集合destination中

Set应用场景

image.png

image.png

image.png

image.png

image.png
 11、微信抽奖小程序
2    1)点击参与抽奖加入集合
3    SADD key {userlD}
4    2)查看参与抽奖所有用户
5    SMEMBERS key      
6    3)抽取count名中奖者
7    SRANDMEMBER key [count] / SPOP key [count]
8
92、微信微博点赞,收藏,标签
10    1) 点赞
11    SADD  like:{消息ID}  {用户ID}
12    2) 取消点赞
13    SREM like:{消息ID}  {用户ID}
14    3) 检查用户是否点过赞
15    SISMEMBER  like:{消息ID}  {用户ID}
16    4) 获取点赞的用户列表
17    SMEMBERS like:{消息ID}
18    5) 获取点赞用户数 
19    SCARD like:{消息ID}
203、集合操作
21    SINTER set1 set2 set3 -> { c }
22    SUNION set1 set2 set3 -> { a,b,c,d,e }
23    SDIFF set1 set2 set3  -> { a }
24
254、集合操作实现微博微信关注模型
26    1) A关注的人: 
27    ASet-> {B, C}
28    2) D老师关注的人:
29     DSet--> {A, E, B, C}
30    3) B老师关注的人: 
31    BSet-> {A, D, E, C, F)
32    4) 我A和D老师共同关注: 
33    SINTER ASet DSet--> {B, C}
34    5) 我A关注的人也关注他(D老师): 
35    SISMEMBER BSet D
36    SISMEMBER CSet D
37    6) 我可能认识的人: 
38    SDIFF DSet ASet->(A, E}
39
405、集合操作实现电商商品筛选
41    SADD  brand:huawei  P40
42    SADD  brand:xiaomi  mi-10
43    SADD  brand:iPhone iphone12
44    SADD os:android  P40  mi-10
45    SADD cpu:brand:intel  P40  mi-10
46    SADD ram:8G  P40  mi-10  iphone12
47    SINTER  os:android  cpu:brand:intel  ram:8G ->  {P40,mi-10}

5. Zset 数据结构

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为 2 (4294967295, 每个集合可存储40多亿个成员)。

image.png
 1ZSet常用操作
2    ZADD key score member [[score member]…]     //往有序集合key中加入带分值元素
3    ZREM key member [member …]                  //从有序集合key中删除元素
4    ZSCORE key member                           //返回有序集合key中元素member的分值
5    ZINCRBY key increment member                //为有序集合key中元素member的分值加上increment 
6    ZCARD key                                   //返回有序集合key中元素个数
7    ZRANGE key start stop [WITHSCORES]          //正序获取有序集合key从start下标到stop下标的元素
8    ZREVRANGE key start stop [WITHSCORES]       //倒序获取有序集合key从start下标到stop下标的元素
9
10Zset集合操作
11    ZUNIONSTORE destkey numkeys key [key ...]   //并集计算
12    ZINTERSTORE destkey numkeys key [key …]     //交集计算

Zset 应用场景

image.png
 1Zset集合操作实现排行榜
2    1)点击新闻
3    ZINCRBY  hotNews:20190819  1  守护香港
4    2)展示当日排行前十
5    ZREVRANGE  hotNews:20190819  0  9  WITHSCORES 
6    3)七日搜索榜单计算
7    ZUNIONSTORE  hotNews:20190813-20190819  7 
8    hotNews:20190813  hotNews:20190814... hotNews:20190819
9    4)展示七日排行前十
10    ZREVRANGE hotNews:20190813-20190819  0  9  WITHSCORES

6. redis更多应用场景

image.png

四、Redis 更多高级命令

 11、keys:
2    全量遍历键, 用来列出所有满足特定正则字符串规则的key,当redis数据量比较大时,性能比较差,要避免使用
3
42、SCAN cursor [MATCH pattern] [COUNT count]
5    scan 参数提供了三个参数,第一个是 cursor 整数值(hash桶的索引值),第二个是 key 的正则模式,
6    第三个是一次遍历的key的数量(参考值,底层遍历的数量不一定),并不是符合条件的结果数量。第
7    一次遍历时,cursor 值为 0,然后将返回结果中第一个整数值作为下一次遍历的 cursor。一直遍历
8    到返回的 cursor 值为 0 时结束。
9    注意:但是scan并非完美无瑕, 如果在scan的过程中如果有键的变化(增加、 删除、 修改) ,那
10    么遍历效果可能会碰到如下问题: 新增的键可能没有遍历到, 遍历出了重复的键等情况, 也就是说
11    scan并不能保证完整的遍历出来所有的键,开发市需要考虑
12
133、Info:
14    查看redis服务运行信息,分为 9 大块,每个块都有非常多的参数,这 9 个块分别是:
15
16  Server 
17    服务器运行的环境参数
18
19  Clients 
20    客户端相关信息
21
22  Memory 
23    服务器运行内存统计数据
24
25  Persistence 
26    持久化信息
27
28  Stats 
29    通用统计数据
30
31  Replication 
32    主从复制相关信息
33
34  CPU CPU 
35    使用情况
36
37  Cluster 
38    集群信息
39
40  KeySpace 
41    键值对统计数量信息

五、Redis 单线程与高性能

1. Redis单线程为什么还能这么快?

  1. 因为它所有的数据都在 **内存 **中,所有运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如 keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。

  2. Redis 完全基于内存,绝大部分请求是纯粹的内存操作,非常迅速,数据存在内存中。

  3. 数据结构简单,对数据操作也简单。

  4. 采用单线程,避免了不必要的上下文切换和竞争条件,不存在多线程导致的cpu切换,不用考虑各种加锁和释放锁操作,没有死锁问题导致的性能消耗。

  5. 使用多路复用IO模型,非阻塞IO。

2. Redis 单线程如何处理那么多的并发客户端连接?

Redis的IO多路复用:
redis 利用 epoll 来实现 IO 多路复用, 将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。

nginx 也是采用 IO 多路复用原理解决 C10K 问题

1 # 查看redis支持的最大连接数,在redis.conf文件中可修改,# maxclients 10000 
2  127.0.0.1:6379> CONFIG GET maxclients 
3   ##1) "maxclients" 
4   ##2) "10000"


文章转载自LiusCoding,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论