ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Redis核心数据结构应用场景与高性能原理刨析

2021-09-10 12:58:21  阅读:183  来源: 互联网

标签:命令 刨析 Redis member field key 集合 数据结构


Redis核心数据结构应用场景与高性能原理刨析


后续有两个概念比较模糊,后续需要进行处理

1、Redis的数据结构

Redis有5种数据结构,分别为String(字符串)、Hash(哈希)、List(列表),Set(集合)、ZSet(有序集合)。

1.1、String

1、单值缓存
set key value
get key

在这里插入图片描述

2、对象缓存
2.1、将对象式的value抽象成一个json格式,然后就可以跟单值缓存一样了
set user:1 value
get user:1

在这里插入图片描述

2.2、批量操作,一次存多个键值对

命令含义
mset user:1:name lele user:1:balance 1800批量操作存储
mget user:1:name user:1:balance批量操作获取

在这里插入图片描述

3、分布式锁

命令含义
setnx product:100 true获取当前key的锁,返回1代表取锁成功
setnx product:100 true获取当前key的锁,返回0代表取锁失败

执行相应的业务操作,加积分什么的

命令含义
del product:100删除当前key
set product:100 true ex 10 nx设置超时时间,默认为秒

这几行命令的意思是多个线程同时对同一商品进行操作,只有第一个才能获取锁成功,获取到锁之后,进行一系列的业务操作,减去相应的库存,并将这个锁释放掉,但为了防止意外,可以设置这个锁的超时时间,单位是秒。

在这里插入图片描述

4、计数器

命令含义
incr article:readcount:{文章id}给当前key值的积分加1
get article:readcount:{文章id}获取当前key值的积分

这行命令的意思是每执行一次 incr article:readcount:{文章id} 命令,就会加1,当执行get命令时,就会获取到加的总数,比如我们平时看的微信小文章中的阅读次数就可以用这个做。

在这里插入图片描述

5、指定增量计数器
incrby key 100
给对应的key加上100

在这里插入图片描述

1.2、Hash

1、常用操作

命令含义
HSET key field value存储一个哈希表key的键值
HSETNX key field value存储一个不存在的哈希表key的键值
HMSET key field value [field value …]在一个哈希表key中存储多个键值对
HGET key field获取哈希表key对应的field键值
HMGET key field [field …]批量获取哈希表key中多个field键值
HDEL key field [field …]删除哈希表key中的field键值
HLEN key返回哈希表key中field的数量
HGETALL key返回哈希表key中所有的键值
HINCRBY key field increment为哈希表key中field键的值加上增量increment

2、对象缓存

命令含义
hmset user {userid}:name lele {userid}:balance 100设置hash对象
hmget user {userid}:name lele {userid}:balance 100获取hash对象

hmset user 1:name lele 1:balance 100
hmget user 1:name 1:balance

在这里插入图片描述

在这里插入图片描述

hgetall key
获取全部的值

在这里插入图片描述

优缺点:

优点

1、同类数据归类整合储存,方便数据管理。
2、相比string操作消耗内存与cpu更小
3、相比string存储更节省空间

缺点:

1、过期功能不能使用在field上,只能使用在key上
2、redis集群架构下不适合大规模使用

1.3、List

1、常用操作

命令含义
LPUSH key value [value …]将一个或多个值value插入到key列表的表头(最左边)
RPUSH key value [value …]将一个或多个值value插入到key列表的表尾(最右边)
LPOP key移除并返回key列表的头元素
RPOP key移除并返回key列表的尾元素
LRANGE key start stop返回列表key中指定区间内的元素,区间以偏移量start和stop指定
BLPOP key [key …] timeout从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
BRPOP key [key …] timeout从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待

2、常用数据结构也可以用redis的list轻松实现
Stack(栈) = LPUSH + LPOP
Queue(队列)= LPUSH + RPOP Blocking
MQ(阻塞队列)= LPUSH + BRPOP
这个阻塞队列相当于,我要去里面拿东西,但是现在里面没有了,所以我就执行 BRPOP 让队列阻塞,知道队列中有了,我再执行,可以设置超时时间。

3、案例
平时我们刷的微博或者朋友圈等 ,每次的消息都是发的时间最晚的在最上面,这种用redis也可以实现
比如小明现在关注了 A 和 B ,当前,A 先发了一条消息,随后,B 也发了一条消息,B 发消息的时间比 A 的晚,那么在小明这里的排序应该是 B的消息在上面,A 的消息在下面,这里其实是当有消息时,我们可以用 LPUSH 命令将消息放到队列中,然后使用 LRANGE 命令将需要展示的消息展示出来。但是这里我们就会发现一个问题,每一个人都会有自己的队列,然后通过 LRANGE 命令去操作它,这里之前解决办法有两种方案,一种是push,一种是pull。
push是每发一条消息,会把自己的消息id全部告诉粉丝,然后粉丝存到自己的队列中,这种在一个人有上亿粉丝时就不太适用了,但是有些业务场景可以做成先发给在线粉丝,非在线的后续可以慢慢发。
pull是每发一条消息,然后把这个消息放到一个公共的地方,粉丝们自己去访问然后放到自己的队列中。

1.4、Set

1、Set常用操作

命令含义
SADD key member [member …]往集合key中存入元素,元素存在则忽略,若key不存在则新建
SREM key member [member …]从集合key中删除元素
SMEMBERS key获取集合key中所有元素
SCARD key获取集合key的元素个数
SISMEMBER key member判断member元素是否存在于集合key中
SRANDMEMBER key [count]从集合key中选出count个元素,元素不从key中删除
SPOP key [count]从集合key中选出count个元素,元素从key中删除

2、Set运算操作

命令含义
SINTER key [key …]交集运算
SINTERSTORE destination key [key …]将交集结果存入新集合destination中
SUNION key [key …]并集运算
SUNIONSTORE destination key [key …]将并集结果存入新集合destination中
SDIFF key [key …]差集运算
SDIFFSTORE destination key [key …]将差集结果存入新集合destination中

3、案例
抽奖,比如抽奖是下面这张图

在这里插入图片描述

当有一个人点击抽奖时,我们执行 sadd key {userId} 命令去给set集合里面添加一个用户id。
当点击查看所有参与用户的时候,我们可以使用命令 smembers key 去显示出所有的用户。
抽取中奖用户的时候我们可以使用命令 SRANDMEMBER key [count] 或者 SPOP key [count],
SRANDMEMBER key [count] 命令只适用于抽一次奖的那种,因为筛选完之后,筛选出的用户还在set集合中;
SPOP key [count] 命令适合于多次抽奖,比如一、二、三等奖,因为筛选完之后,筛选到的用户会被移除set集合。

关注模型

me关注的人:{A1,A2,A4,A6,A8}
A1关注的人:{A2,A3,A4}
A2关注的人:{A1,A4,A5,A6}
A3关注的人:{A6,A7,A8}
A4关注的人:{A2,A5}

me和A2的共同关注:{A1,A4,A6}
A1关注的人也关注着A2:{A4} --也就是看A1关注的每一个人的关注列表中有没有A2
命令如下图:

在这里插入图片描述

1.5、ZSet

1、Set常用操作

命令含义
ZADD key score member [[score member]…]往有序集合key中加入带分值元素
ZREM key member [member …]从有序集合key中删除元素
ZSCORE key member返回有序集合key中元素member的分值
ZINCRBY key increment member为有序集合key中元素member的分值加上increment
ZCARD key返回有序集合key中元素个数
ZRANGE key start stop [WITHSCORES]正序获取有序集合key从start下标到stop下标的元素
ZREVRANGE key start stop [WITHSCORES]倒序获取有序集合key从start下标到stop下标的元素

2、Zset集合操作

命令含义
ZUNIONSTORE destkey numkeys key [key …]并集计算
ZINTERSTORE destkey numkeys key [key …]交集计算

3、案例

在这里插入图片描述

这个微博热搜相信我们也是经常见到的,他们上面的排行以及阅读量都可以用redis来实现。
1、可以通过ZINCRBY key increment member命令给文章加上分值,也就是打开了多少次,默认是1。

在这里插入图片描述

2、获取当天的排行可以用倒叙排序展示的命令
ZREVRANGE key start stop [WITHSCORES]
[WITHSCORES] 这个的意思是加上分值
我这里是乱码,能说明意思就好

在这里插入图片描述

3、如果要展示七天的总和,我们可以求并集再排序
zunionstore hotNews:20180813-20180819 7 hotNews:20180813 hotNews:20180814 hotNews:20180815 hotNews:20180816 hotNews:20180817 hotNews:20180818 hotNews:20180819
这行命令的意思是对7个key求并集并存储到 hotNews:20180813-20180819 key中

在这里插入图片描述

2、Redis高性能原理

2.1、Redis是单线程的吗?

其实严格意义上来说,Redis不是单线程的,比如Redis的持久化、异步删除、集群数据这些都是由额外的线程来完成的。
我们平时说的Redis单线程其实是是指从其它端发送给Redis的IO操作都是由一个线程来完成的,外部访问Redis时,Redis会将这些命令排好序,然后一个一个执行。

2.2、Redis单线程为什么还能这么快?

因为Redis的操作是在内存上的,所有的操作都是内存级别的,而且单线程也避免了多线程之间的线程切换损耗,但是在操作时一定要注意,尤其是bigKey,一旦操作失误就会造成Redis卡顿。

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

Redis的IO多路复用:redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
这块这个概念还是有点模糊,后续进行深层次的学习可能会有其它博客解释

在这里插入图片描述

3、Redis高级命令

3.1、keys *

遍历全库,效率比较低,可支持通配符,如下图所示:

在这里插入图片描述

3.2、scan渐进式遍历键

SCAN cursor [MATCH pattern] [COUNT count] scan 参数提供了三个参数,第一个是 cursor 整数值(hash桶的索引值),第二个是 key 的正则模式, 第三个是一次遍历的key的数量(参考值,底层遍历的数量不一定),并不是符合条件的结果数量。第 一次遍历时,cursor 值为0,然后将返回结果中第一个整数值作为下一次遍历的 cursor。一直遍历 到返回的 cursor 值为 0 时结束。
注意:但是scan并非完美无瑕, 如果在scan的过程中如果有键的变化(增加、 删除、 修改) ,那 么遍历效果可能会碰到如下问题:
新增的键可能没有遍历到, 遍历出了重复的键等情况(有可能在遍历期间又插入新数据,产生了rehash()), 也就是说 scan并不能保证完整的遍历出来所有的键, 这些是我们在开发时需要考虑的。
这块这个概念还是有点模糊,后续进行深层次的学习可能会有其它博客解释
代码示例如下:

在这里插入图片描述

从图中就可以看出,每一次的结果不一定都是固定的,每一次返回的数字都是下一次扫描的起点游标,直到返回0结束。

标签:命令,刨析,Redis,member,field,key,集合,数据结构
来源: https://blog.csdn.net/qq_41931364/article/details/120195707

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有