redis是一款高效的分布式缓存中间件。
redis为什么快
因为他所有的数据都在内存中,像传统的关系型数据库是存储在磁盘上的,所有的运算都是内存级别的运算,而且单线程避免了多线程切换带来的性能损耗问题。正因为redis是单线程,所以要小心使用redis 命令,对于那些耗时的指令(比如keys )一定要谨慎使用或者不使用,一不小心就会导致redis卡顿。
消除锁竞争。 多线程环境下,为了保证数据的一致性,需要使用锁来保证多线程的线程安全。锁的获取和释放会带来额外的开销,并且可能导致线程阻塞。redis单线程
执行命令,不存在多个线程抢锁的情况,避免了抢锁带来的性能损耗。
高效的数据结构 。redis支持多种数据结构,string,hash,list,set,sorted set等等,每种数据结构都采用了专门的底层实现,
以确保高效的操作。
IO多路复用
redis使用io多路复用技术来处理多个客户端的连接,将连接信息放入队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
文件事件分派器理解:
想象你经营着一家热门餐厅,每天会有大量顾客前来就餐。餐厅里有很多服务员,但不同顾客的需求不一样,有的要点餐,有的要结账,有的要加菜。你作为餐厅老板,不可能让服务员自己随意去招呼顾客,那样肯定会乱套。于是你安排了一个调度员,这个调度员站在餐厅中央,时刻关注着每一位顾客的状态。当顾客有需求时,调度员会根据具体需求,把相应的任务分配给合适的服务员去处理
注意:redis的单线程是指redis的命令操作是单线程,但是连接客户端和持久化机制同样有各自的线程
string数据结构使用
将用户张三存储到redis中。如果使用string结构的话,有两种普遍的做法,set user:张三id 张三这个对象的json字符串
第二种做法是用mset命令:mset user1:username zhangsan user1:age 23 user1:gender nan
第一种做法的好处就是存的时候简单,但是再要修改value对象值的时候还要将json字符串转成对象修改属性,然后又转成json存储到redis中
第二种做法要修改用户属性就简单了,我们可以直接用 mset user1:age 25 user1:gener nv user1:love java
注意:mset在redis集群里使用可能会出错
在 Redis 集群里,所有的键会被映射到 16384 个哈希槽(hash slot)中的某一个,映射算法通常是对键进行 CRC16 计算,然后将结果对 16384 取模。集群中的每个主节点负责一部分哈希槽,不同的主节点管理不同范围的哈希槽。
Redis 集群要求在一个命令中涉及的所有键必须属于同一个哈希槽,这样才能保证命令可以在单个节点上执行。如果一个命令涉及的多个键被映射到了不同的哈希槽,就会触发 “CROSSSLOT Keys in request don't hash to the same slot” 错误。后续很多数据类型操作都有可能遇到这个问题,解决方式跟这个差不多。
我们可以在集群中这样使用mset:
mset {user1:}username zhansan {user1:}age 23 {user1:}gender nv {user1:}love java
执行keys * 看看key有没有存入进去
获取的时候,可用使用get也可以使用mget
mget {user1:}love {user1:}uername
setnx命令
设置一个不存在的key,如果之前redis中存在这个key,那么设置失败,如果不存在,则设置成功
这个命令在java圈子非常火爆,可以用这个命令来实现分布式锁 。
string在实际开发的运用场景
场景很多。举两个例子
1. 分布式系统中的 session 存储
场景描述:在分布式系统中,用户的 session 信息需要在多个服务器之间共享, 以保证用户在不同服务器上的操作具有一致性。 可以将用户的 session 信息存储在 Redis 的 String 类型中, 以用户 ID 或 session ID 作为键,session 数据作为值。 示例:一个分布式的 Web 应用程序,用户登录后将 session 信息存储在 Redis 中。 当用户在不同的服务器上进行操作时,通过 session ID 从 Redis 中获取 session 信息
2.限时业务 场景描述:在一些业务场景中,需要对某些操作设置时间限制, 例如验证码的有效期、限时抢购等。可以使用 Redis 的 String 类型结合 EXPIRE 命令来实现限时业务。 示例:一个网站在用户注册时会发送验证码,验证码的有效期为 5 分钟。 可以将验证码以用户 ID 作为键,验证码内容作为值存储在 Redis 的 String 类型中, 并设置 5 分钟的过期时间
3.计数器业务
比如某个视频或者文章的点击量,我们可以用redis的 incr命令
总之string的用法非常广泛,甚至可以说一个string结构只要你用的好,其余的结构你甚至可以不用了解,通过string结构在再结合业务代码完全
可以不需要使用别的数据结构,只是说可能会对你的编码技术要求更高一点 。
hash数据结构的应用
hash结构类似于java中的map操作。
hset key field value 存储一个hash表key的值
hsetnx key field value 存储一个不存在的哈希表key的值
hmset key field value field value ...... 在一个哈希表key中存储多个键值对
hget key field 获取hash表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
hash结构应用场景
1.对象存储
hmset user username lisi love java gender ry
hmget user username love gender
2.电商购物车(说烂了)
以用户id为key,商品id为field,商品数量为value
购物车操作:
添加商品:hset cart:1(用户id) 99(商品id) 1(数量)
增加数量:hincrby cart:1 99 1
商品总数:hlen cart:1
删除商品:hdel cart:1 99 (注意别把key删了,那用户购物车所有物品都没了。。。。)
获取购物车所有商品:hgetall cart:1
hash结构的优缺点
优点:
1.同类数据归类整合存储,方便数据管理
2.相比string操作消耗内存与CPU更小
3.相比string存储更节省空间
缺点:
1.过期功能不能使用在field上,只能用在key上
2.redis集群架构下不适合大规模使用
list常用操作
lpush key value ... 将一个或多个值(value)插入到key列表的表头(最左边)
rpush key value ... 将一个或多个值(value)插入到key列表的表尾(最右边)
lpop key 移除并返回key列表的头元素
rpop key 移除并返回key列表的尾元素
lrange key start stop 返回列表key中,区间以偏移量start和stop指定
blpop key timeout 从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
brpop key timeout 从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
利用list的结构属性,我们可以实现一些栈和队列的相关操作
栈:lpush+lpop
queue(队列)lpush+rpop
blocking mq(阻塞队列)lpush+brpop
list应用场景
微博消息和微信公众号消息
我关注了阿里巴巴和字节跳动公众号。阿里巴巴发了一个消息,消息id为1000.那么就可以用list命令来存储
lpush msg:我的id 1000
然后字节跳动发了一个消息,消息id为2000,
lpush msg:我的id 2000
查看订阅的公众号最新消息
lrange msg:我的id 0 10
set常用操作
sadd key member ... 往集合key中存入元素,元素存在则忽略,若key不存在则新建
srem key 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中删除
set运算操作
sinter key ... 多个key取交集运算
sinterstore des key ... 将交集结果存入新集合des中
sunion key key 并集运算
sunionstore des key ... 将并集结果存入新集合des中
sdiff key ... 差集运算
sdiffstore des key ... 将差集结果存入新集合des中
set应用场景
微信小程序参与抽奖
点击"参与抽奖"加入集合,对应命令
sadd key userId
查看参与抽奖所有用户
smembers key
抽取count名中奖者
srandmember key count 或者 spop key count
微信点赞应用场景
点赞:sadd zan:消息id 用户id
取消点赞 srem zan:消息id 用户id
检查用户是否点过赞 sismember zan:消息id 用户id
获取点赞的用户列表 smembers zan:消息id
获取点赞用户数 scard zan:消息id
set集合操作实现抖音关注模型
我关注的博主 我->{嘴哥,华哥,刚哥,张三}
张三关注的博主:张三->{嘴哥,赵丽颖}
嘴哥关注的博主:{华哥,刚哥}
我和张三的共同关注是 sinter 我 张三 结果就是 嘴哥
判断我关注的博主也关注他,比如我关注了嘴哥、华哥、刚哥,嘴哥也关注了华哥和刚哥,那么判断我和嘴哥是否都关注了华哥和刚哥,
sismember 我 华哥 刚哥 sismember 嘴哥 华哥 刚哥 通过两个语句来判断
我可能认识的人,比如说我关注了张三,并且跟张三都关注了嘴哥,但是张三关注了赵丽颖,我没有关注赵丽颖,那么就表示赵丽颖是我可能认识的人
那么可用这个命令来获取我可能认识的人:sdiff 张三 我
zset常用操作
zset就是set的有序操作集合
zadd key score member 往有序集合key中加入带分值元素
zrem key member 从有序集合key中删除元素
zscore key member 返回有序集合key中元素member的分值
zincrby key incrment member 为有序集合key中元素member的分值加加上incrment
zcard key 返回有序集合key中元素个数
zrange key start stop 正序获取有序集合key从start下标到stop下标的元素
zrevrange key start stop 倒序获取。。。。
zset集合操作
zunionstore destkey numkeys key .... 并集计算
zinterstore destkey numkeys key 交集计算
zset应用场景
zset集合操作实现排行榜
点击某个新闻,增加分数
zincrby hotNews:新闻id 1 守护香港
展示当日排行前十
zrevrange hotNews:新闻id 0 9 withscores
一周搜索榜单计算
zunionstore hotNews:311-317 7
展示一周排行前十
zrevrange hotNews:311-317 0 9 withscores
redis还有种数据结构,bitmap,其实就是string。
redis的数据结构用法非常灵活,太灵活导致实际应用的时候不知道该选哪个,这里我建议直接用string,value存储json格式就行,然后用业务代码来实现你的需求。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek “源神”启动!「GitHub 热点速览」
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器