当前位置: 首页 > ds >正文

Redis相关命令详解及其原理

Redis相关概念

Redis 是 Remote Dictionary Service 的简称;即远程字典服务;

Redis 是内存数据库KV 数据库数据结构数据库

Redis中value的数据结构

redis是key-value数据库,redis提供5种基本数据结构存储其中的value。

String

String 是一种二进制安全的数据结构(即每个String都有一个长度字段,通过长度字段来区分每个String类型的数据,而不是C语言中使用\0来分割每个string),可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。

String是动态字符串 raw,当字符串长度小于1M 时,加倍扩容;超过 1M 每次只多扩 1M;字符串最大长度为 512M

常用命令
命令介绍
SET key value设置指定 key 的值
SETNX key value只有在 key 不存在时设置 key 的值
GET key获取指定 key 的值
MSET key1 value1 key2 value2 …设置一个或多个指定 key 的值
MGET key1 key2 ...获取一个或多个指定 key 的值
STRLEN key返回 key 所储存的字符串值的长度
INCR key将 key 中储存的数字值增一
DECR key将 key 中储存的数字值减一
EXISTS key判断指定 key 是否存在
DEL key(通用)删除指定的 key
EXPIRE key seconds(通用)给指定 key 设置过期时间
存储结构

字符串长度小于等于 20 且能转成整数,则使用 int 存储;

字符串长度小于等于 44,则使用 embstr 存储;

字符串长度大于 44,则使用 raw 存储;

应用

当一个对象极少修改时,可以用String类型来存储对象

 SET role:10001 '{["name"]:"mark",["sex"]:"male",["age"]:30}'SET role:10002 '{["name"]:"darren",["sex"]:"male",["age"]:30}'# 极少修改,对象属性字段很少改变的时候
GET role:10001
# key 如何来设置
# 1. 有意义的字段  role 有多行
# 2. role:10001  redis 客户端  role:10001:recharge  role:10001:activity:10001

因为String类型可以存储整数和浮点数类型的数据,因此可以用String来作为一个计数器累加器

 # 统计阅读数 累计加1incr reads# 累计加100incrby reads 100

基于String的SETNX命令,可以用String类型来作为一个分布式锁

# 加锁   加锁 和 解析  redis 实现是 非公平锁     ectd zk  用来实现公平锁
# 阻塞等待   阻塞连接的方式
# 介绍简单的原理: 事务
setnx lock 1   # 不存在才能设置 定义加锁行为  占用锁  
setnx lock uuid  # expire 30 过期
set lock uuid nx ex 30# 释放锁
del lockif (get(lock) == uuid)del(lock);

String底层是以二进制来存储的,因此String可以实现位运算,位运算可以用来实现签到功能。

# 猜测一下 string 是用的 int 类型 还是 string 类型
# 月签到功能 10001 用户id 202106 2021年6月份的签到 6月份的第1天
setbit sign:10001:202106 1 1# 计算 2021年6月份 的签到情况
bitcount sign:10001:202106# 获取 2021年6月份 第二天的签到情况 1 已签到 0 没有签到
getbit sign:10001:202106 2

List(列表)

Redis 的 List 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

常用命令
命令介绍
RPUSH key value1 value2 ...在指定列表的尾部(右边)添加一个或多个元素
LPUSH key value1 value2 ...在指定列表的头部(左边)添加一个或多个元素
LSET key index value将指定列表索引 index 位置的值设置为 value
LPOP key移除并获取指定列表的第一个元素(最左边)
RPOP key移除并获取指定列表的最后一个元素(最右边)
LLEN key获取列表元素数量

LRANGE key start end

LRANGE key 0 -1

获取列表 start 和 end 之间 的元素

获取列表 第0个到最后一个元素之间 的元素

LREM key count value        

因为list不具备去重功能,因此一个list可能存在多个相同的value,LREM从左开始删除count个value

BRPOP key timeout

它是 RPOP 的阻塞版本,因为这个命令会

在给定list无法弹出任何元素的时候阻塞连接

应用

list可以从左与右同时追加value和去除value,通过限制,可以基于lsit实现栈(左进)和队列

#栈 
LPUSH + LPOP# 或者
RPUSH + RPOP
#队列LPUSH + RPOP# 或者
RPUSH + LPOP

阻塞队列

LPUSH + BRPOP# 或者
RPUSH + BLPOP

基于LRANGE/RRANGE可以用来实现显示固定窗口记录

# 在某些业务场景下,需要获取固定数量的记录;比如获取最近50条战绩;这些记录需要按照插入的先
后顺序返回;
lpush says '{["name"]:"零声教育【Mark老师】", ["text"]:"祝大家儿童节快乐!", 
["picture"]:["url://image-20210601172741434.jpg", "url://image
20210601172741435.jpg"], timestamp = 1231231230}'lpush says '{["name"]:"零声教育【King老师】", ["text"]:"祝大家儿童节快乐!", 
["picture"]:["url://image-20210601172742434.jpg", "url://image
20210601172741436.jpg"], timestamp = 1231231231}'lpush says '{["name"]:"零声教育【Darren老师】", ["text"]:"祝大家儿童节快乐!", 
["picture"]:["url://image-20210601172743434.jpg", "url://image
20210601172741437.jpg"], timestamp = 1231231232}'lpush says '{["name"]:"零声教育【Mark老师】", ["text"]:"一切只为渴望更优秀的你", 
["picture"]:["url://image-20210601172744434.jpg", "url://image
20210601172741438.jpg"], timestamp = 1231231233}'lpush says '{["name"]:"零声教育【Darren老师】", ["text"]:"hello 0Voice! hello 
to better self", ["picture"]:["url://image-20210601172745439.jpg", 
"url://image-20210601172741435.jpg"], timestamp = 1231231234}'lpush says '{["name"]:"零声教育【King老师】", ["text"]:"2021届学员真牛逼!", 
["picture"]:["url://image-20210601172745434.jpg", "url://image
20210601172741440.jpg"], timestamp = 1231231235}'# 裁剪最近5条记录   战绩  近50条
ltrim says 0 4lrange says 0 -1

list适合描述插入有序的列表,如朋友圈列表就是插入有序的,先发布的在后面,后发布的在前面,再比如抖音的发布作品、朋友圈点赞列表、评论区id列表,也适合用lsit描述。

Hash

Redis 中的 Hash 是一个 String 类型的 field-value(键值对) 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接修改这个对象中的某些字段的值。

Hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组 + 链表)。不过,Redis 的 Hash 做了更多优化。

常用命令
命令介绍
HSET key field value设置指定哈希表中指定字段的值
HSETNX key field value只有指定字段不存在时设置指定字段的值
HMSET key field1 value1 field2 value2 ...同时将一个或多个 field-value (域-值)对设置到指定哈希表中
HGET key field获取指定哈希表中指定字段的值
HMGET key field1 field2 ...获取指定哈希表中一个或者多个指定字段的值
HGETALL key获取指定哈希表中所有的键值对
HEXISTS key field查看指定哈希表中指定的字段是否存在
HDEL key field1 field2 ...删除一个或多个哈希表字段
HLEN key获取指定哈希表中字段的数量
存储结构

节点数量大于 512(hash-max-ziplist-entries) 或所有字符串长度大于 64(hash-max-ziplist value),则使用 dict 实现;

节点数量小于等于 512 且有一个字符串长度小于 64,则使用 ziplist 实现;

应用

hash因为是k-v组织的映射表,所以适合用于描述东西的属性字段,如朋友圈的各种属性如点赞数、评论数,商品的各种属性如好评数、价格、购买数。因此可以用来存储易发生变化的对象。

hmset hash:10001 name mark age 18 sex male# 与 string 比较
set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:18}'# 假设现在修改 mark的年龄为19岁
# hash:hset hash:10001 age 19# string: get hash:10001# 将得到的字符串调用json解密,取出字段,修改 age 值# 再调用json加密set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:19}'

同时hash也适合缓存热点数据,减小关系数据库的压力。

Set

Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。

你可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。

常用命令
命令介绍
SADD key member1 member2 ...向指定集合添加一个或多个元素
SMEMBERS key获取指定集合中的所有元素
SCARD key获取指定集合的元素数量
SISMEMBER key member判断指定元素是否在指定集合中
SINTER key1 key2 ...获取给定所有集合的交集
SINTERSTORE destination key1 key2 ...将给定所有集合的交集存储在 destination 中
SUNION key1 key2 ...获取给定所有集合的并集
SUNIONSTORE destination key1 key2 ...将给定所有集合的并集存储在 destination 中
SDIFF key1 key2 ...获取给定所有集合的差集
SDIFFSTORE destination key1 key2 ...将给定所有集合的差集存储在 destination 中
SPOP key count随机移除并获取指定集合中一个或多个元素
SRANDMEMBER key count随机获取指定集合中指定数量的元素
存储结构

元素都为整数且节点数量小于等于 512(set-max-intset-entries),则使用整数数组存储;

元素当中有一个不是整数或者节点数量大于 512,则使用字典存储;

应用

set是无序且唯一的集合,支持交集、并集、差集操作。

基于set元素的唯一性,可以用来实现抽奖

# 添加抽奖用户sadd Award:1 10001 10002 10003 10004 10005 10006sadd Award:1 10009# 查看所有抽奖用户smembers Award:1# 抽取多名幸运用户srandmember Award:1 10# 如果抽取一等奖1名,二等奖2名,三等奖3名,该如何操作?

基于交集操作,可以用来实共同关注

sadd follow:A mark king darren mole vicosadd follow:C mark king darrensinter follow:A follow:C

基于差集操作,可以用来实现推荐好友

 sadd follow:A mark king darren mole vicosadd follow:C mark king darren# C可能认识的人:sdiff follow:A follow:C

zset

zset 类似于 Set,但和 Set 相比,zset 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。

常用命令
命令介绍
ZADD key score1 member1 score2 member2 ...向指定有序集合添加一个或多个元素
ZCARD KEY获取指定有序集合的元素数量
ZSCORE key member获取指定有序集合中指定元素的 score 值
ZINTERSTORE destination numkeys key1 key2 ...将给定所有有序集合的交集存储在 destination 中,对相同元素对应的 score 值进行 SUM 聚合操作,numkeys 为集合数量
ZUNIONSTORE destination numkeys key1 key2 ...求并集,其它和 ZINTERSTORE 类似
ZDIFF destination numkeys key1 key2 ...求差集,其它和 ZINTERSTORE 类似
ZRANGE key start end获取指定有序集合 start 和 end 之间的元素(score 从低到高)
ZREVRANGE key start end获取指定有序集合 start 和 end 之间的元素(score 从高到底)
ZREVRANK key member获取指定有序集合中指定元素的排名(score 从大到小排序)
存储结构

节点数量大于 128 或者有一个字符串长度大于 64,则使用跳表(skiplist);

节点数量小于等于 128(zset-max-ziplist-entries)且所有字符串长度小于等于 64(zset-max ziplist-value),则使用 ziplist 存储;

应用

基于元素的score实现排行榜

# 点击新闻:zincrby hot:20230612 1 10001zincrby hot:20230612 1 10002zincrby hot:20230612 1 10003zincrby hot:20230612 1 10004zincrby hot:20230612 1 10005zincrby hot:20230612 1 10006zincrby hot:20230612 1 10007zincrby hot:20230612 1 10008zincrby hot:20230612 1 10009zincrby hot:20230612 1 10010# 获取排行榜:zrevrange hot:20230612 0 9 withscores

延时队列,将消息序列化成一个字符串作为 zset 的 member;这个消息的到期处理时间作为 score,然后用 多个线程轮询 zset 获取到期的任务进行处理。

 def delay(msg):msg.id = str(uuid.uuid4()) #保证 member 唯一value = json.dumps(msg)retry_ts = time.time() + 5 # 5s后重试redis.zadd("delay-queue", retry_ts, value)# 使用连接池
def loop():while True:values = redis.zrangebyscore("delay-queue", 0, time.time(), start=0, num=1)if not values:time.sleep(1)continuevalue = values[0]success = redis.zrem("delay-queue", value)if success:msg = json.loads(value)handle_msg(msg)# 缺点:loop 是多线程竞争,两个线程都从zrangebyscore获取到数据,但是zrem一个成功一个失
败,
# 优化:为了避免多余的操作,可以使用lua脚本原子执行这两个命令
# 解决:漏斗限流

分布式定时器:生产者将定时任务 hash 到不同的 redis 实体中,为每一个 redis 实体分配一个 dispatcher 进程, 用来定时获取 redis 中超时事件并发布到不同的消费者中;

0voice · GitHub

http://www.xdnf.cn/news/18972.html

相关文章:

  • MT** 时间指标全景图:从可靠性到可维护性的度量体系
  • LangGraph-2-Demo
  • CI/CD 全链路实践:从 Git 基础到 Jenkins + GitLab 企业级部署
  • Python 操作 PPT 文件:从新手到高手的实战指南
  • 线性代数中矩阵等价与离散数学中关系的闭包之间的关联
  • VScode,设置自动保存
  • Vue中的props方式
  • 多模态RAG架构:下一代跨模态智能检索系统的设计与实践
  • 视频合成素材视频-多合一功能-青柠剪吧
  • OpenTenBase核心技术解密:突破OLTP与OLAP边界的分布式数据库革新
  • 【PS实战】制作hello标志设计:从选区到色彩填充的完整流程(大学PS作业)
  • 百度IOS客户端岗位--面试真题分析
  • 【Docker基础】Docker-compose进阶配置:资源限制与高可用部署
  • 中国移动云电脑一体机-创维LB2004_瑞芯微RK3566_2G+32G_开ADB安装软件教程
  • Web调用本地程序:Custom URL Scheme
  • Zookeeper(分布式RPC调用和分布式文件储存)
  • 2025年渗透测试面试题总结-35(题目+回答)
  • Radan钣金CAM解决方案在电气柜制造行业的应用案例
  • 物流配送路径规划项目方案
  • 【Doris】服务器配置
  • 深入浅出 ArrayList:从基础用法到底层原理的全面解析(下)
  • IDEA2022开启新版UI
  • 【嵌入式电机控制#进阶4】无感控制(二):观测器导论锁相环(全网最通俗易懂)
  • 【C++11】auto关键字:自动类型推导
  • MCP之weather server demo
  • 李沐-第十章-训练Seq2SeqAttentionDecoder报错
  • Leetcode top100之链表排序
  • 【ElasticSearch】json查询语法
  • 美团一面“保持好奇”
  • Spring Boot 项目打包成可执行程序