redis----day02(哈希类型操作、列表类型操作、集合类型操作、有序集合操作、获取长慢命令、pipeline与事务、发布订阅(观察者模式)、Bitmap位图、HyperLogLog)
.
.
.
.
.
.
今日内容
1 哈希类型操作
------------------------------------------
###1---hget,hset,hdel 给字典添加键值对,获取键对应的值,删除键值对
hget name key # 获取 name对应的字典中key对应的值 时间复杂度为 o(1)
hset name key value # 设置name对应的字典中,k v 键值对 时间复杂度为 o(1)
hdel name key # 删除hash key对应的field的值 时间复杂度为 o(1)
#测试
hget userinfo age
hset userinfo kkk vvv
hdel userinfo kkk
------------------------------------------
###2---hexists,hlen
判断字典的长度以及字典里键存不存在 时间复杂度为 o(1)
hexists userinfo name # 判断userinfo字典里面的 键name 存不存在 存在返回1 不存在返回0
hlen userinfo # 返回字典里键值对的数量 时间复杂度为 o(1)
------------------------------------------
###3---hmget,hmset 批量获取字典值与批量设置字典
hmget userinfo name age # 批量获取字典 多个键 对应的值 时间复杂度是o(n)
hmset userinfo name1 lihua age1 26 # 批量设置字典多个键值对 时间复杂度是o(n)
------------------------------------------
###4--hgetall,hvals,hkeys 获取字典全部键值对、全部的值、全部的键
hgetall userinfo # 获取字典全部键值对 时间复杂度是o(n)
hvals key # 获取字典全部的值 时间复杂度是o(n)
hkeys key # 获取字典全部的键 时间复杂度是o(n)
# 小心使用hgetall 会造成阻塞
##1 计算网站每个用户主页的访问量
hincrby userinfo pageview count
hincrby userinfo pageview 1 # userinfo字典里 pageview键对应值加1
hget userinfo pageview
------------------------------------------
##其他操作 hsetnx,hincrby,hincrbyfloat
hsetnx userinfo key value # 设置字典对应key的value(如果field已存在,则失败),时间复杂度o(1)
hincrbyfloat userinfo key 1.2 # 设置userinfo字典对应key的值自增1.2 时间复杂度o(1)
------------------------------------------
.
.
.
.
.
.
.
.
.
.
2 列表类型操作
--------------------------------------------------------
# 插入操作
# rpush 从list11列表右侧插入
rpush list11 value1 value2 # 时间复杂度为o(1~n)
# lpush 从列表左侧插入
# linsert 从list11列表某一个元素插入
linsert list11 before|after oldValue newValue
#从元素value的前或后插入newValue 时间复杂度o(n) ,需要遍历列表
linsert list11 before aaa aaa111
linsert list11 after aaa aaa222
--------------------------------------------------------
# 删除操作
lpop list11 # 从列表list11左侧弹出一个item 时间复杂度o(1)
rpop list11 # 从列表list11右侧弹出一个item 时间复杂度o(1)
lrem list11 n value
# 根据n值,从list11列表中删除所有值是value的数据 时间复杂度o(n)
1 n>0 列表从左到右,删除最多n个 值是value的数据
2 n<0 列表从右向左,删除最多n个 值是value的数据
3 n=0 列表删除所有 值是value的数据
lrem list11 0 a # 删除列表中所有值是a的数据
lrem list11 -1 c # 从右侧删除1个值是c的数据
ltrim list11 start end # 按照索引范围修剪列表 o(n)
ltrim list11 1 4 # 只保留下表1到4之间的元素
-----------------------------------------------------------
-----------------------------------------------------------
# 查询操作 获取列表指定开始与结束索引范围的值
lrange list11 start end # 获取列表指定索引范围所有item o(n)
lrange list11 0 2
lrange list11 0 -1 # 获取列表第一个位置到倒数第一个位置的值
lindex list11 index # 获取列表指定索引的item o(n)
lindex list11 0
lindex list11 -1
llen list11 # 获取list11列表长度
-----------------------------------------------------------
-----------------------------------------------------------
# 修改操作 按索引位置改值
lset list11 index newValue # 设置list11列表,指定索引位置的值为newValue o(n)
lset list11 2 ppp # 把第二个位置设为ppp
# 列表实战
实现timeLine功能,时间轴,微博关注的人,按时间轴排列
所有人发了一个微博,在数据库里就有一条记录,假设现在总用户是100个人,但是该用户只有10个好友
现在就想这10个人发的微博,按时间去排序,在该用户的朋友圈展示出来,怎么办
redis建立一个用户的朋友圈列表,只要该用户的好友发了微博,就把该微博的id 放到该用户的朋友圈列表里面,
这样当用户看朋友圈的时候,从列表里面,通过微博的id 拿到微博数据,按时间排列一下,
展示出来就是朋友圈看到的效果了
----------------------------------------------------------
----------------------------------------------------------
# 其他操作
blpop list11 timeout
# 移出并获取列表的第一个元素,
# 如果列表没有元素,会阻塞列表直到等待超时 或发现可弹出元素为止。
# timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1)
brpop list11 timeout #同上
lpush+lpop # 实现栈的功能 先进后出
lpush+rpop # 实现队列功能 先进先出
lpush+ltrim # 固定大小的列表 有新的数据添加到列表里 通过修剪踢掉对应数量的老数据
# 重要
lpush+brpop
# 可以实现简单的消息队列 左侧添加数据 从右侧取的时候如果没有,就阻塞在这了
# 但不够专业,如果一个进程放了一个重要的数据,另一个进程取出来后,数据在用的过程中
# 突然进程报错了,但数据还没用完,这个时候列表里该数据已经没了,想再拿也没有了
# 所以真正好的消息队列,应该有一个确认机制,进程先用,用完告诉队列没有问题了,
# 消息队列再删除该数据,比如rabbitmq或kafka
---------------------------------------------------------------
.
.
.
.
.
.
.
.
.
3 集合类型操作
# 首先集合里的数据是无序的、无重复的 !!!
sadd set88 v1 v2 v3
# 向集合set11添加元素(如果元素存在,添加失败,其他不存在的还能正常添加进去) o(1)
srem set88 value1 # 从集合中移除指定元素 o(1)
scard set88 # 计算set88集合的大小
sismember set88 v1 # 判断v1是否在集合中
srandmember set88 n # 从集合中随机取出n个元素,不会破坏原集合
spop set88 n # 从集合中随机弹出一个元素 会破坏原集合
smembers set88 # 获取集合中所有元素 ,无序,小心使用,会阻塞住
sdiff set1 set2 # 计算set1和set2的差集 set1集合的独有部分
sinter set1 set2 # 计算set1和set2的交集 共有部分
sunion set1 set2 # 计算并集 两集合所有的部分
sunionstore set3 set1 set2 set8 # 将set1 set2 set8集合的并集保存到set3集合中
sinterstore set4 set1 set2 # 将set1 set2集合的交集保存到set4集合中
sdiffstore set5 set1 set2 # 将set1 set2集合的差集保存到set5集合中
-----------------------------------------------
# 应用场景
推荐场景
两个集合如果交集大于多少,说明两集合比较相似,可以把对应集合的差集数据推给,另一个集合
去重场景
抽奖系统 :通过spop来弹出用户的id,活动取消,直接删除
点赞,点踩,喜欢等,用户如果点了赞,就把用户id放到该条记录的集合中
标签:给用户/文章等添加标签,sadd user:1:tags 标签1 标签2 标签3
给标签添加用户,关注该标签的人有哪些
共同好友:集合间的操作
-----------------------------------------------
.
.
.
.
.
.
.
.
4 有序集合(zset)操作
# 有顺序的,不重复的 集合
# 特点:不能重复 并有一个分值字段,来保证顺序
key score value
user:ranking 1 lqz
user:ranking 99 lqz2
user:ranking 88 lqz3
# 集合与有序集合区别
集合:无重复元素,无序,element
有序集合:无重复元素,有序,element+score
# 列表和有序集合区别
列表:可以重复,有序,element
有序集合:无重复元素,有序,element+score
----------------------------------------------
# 使用命令
zadd zset88 score1 v1 score2 v2
# score可以重复,可以多个同时添加,元素不能重复 o(logN)
zrem zset88 v1 # 删除元素,可以多个同时删除 o(1)
zscore zset88 v1 # 获取元素的分数 o(1)
zincrby zset88 2 v1 # 增加或减少元素v1对应的分数2 o(1)
zcard zset88 # 返回元素总个数 o(1)
zrank zset88 v1 # 返回v1元素的排名(从小到大排)
zrange zset88 0 -1 # 返回有序集合所有元素不带分数
zrange zset88 0 -1 withscores # 返回所有元素,带分数
zrange zset88 -2 -1 # 拿有序集合里分数排最大的两个
zrangebyscore zset88 minScore maxScore # 返回指定分数范围内的元素
zrangebyscore zset88 90 210 withscores # 获取90分到210分的元素,带分数
zcount zset88 minScore maxScore # 返回指定分数范围内元素的个数
zremrangebyrank zset88 start end # 删除指定排名范围内的元素 前开后闭
zremrangebyrank zset88 2 4 # 删除有序集合中 排名是3与4 的元素
zremrangebyscore zset88 minScore maxScore # 删除指定分数内的元素
zremrangebyscore zset88 2 100 # 删除分数2到100之间的元素
------------------------------------------------
# 其他操作
zrevrank zset88 v1 # 返回v1元素 按分数降序排序的排名
zrevrange zset88 0 -1 # 从高到低排序取一定范围的有序集合元素
zinterstore # 对两个有序集合交集
zunionstore # 对两个有序集合求并集
------------------------------------------------
# 实战
# 所有的排行榜都可以用有序集合:
音乐排行榜,销售榜,关注榜,游戏排行榜
------------------------------------------------
.
.
.
.
.
.
.
.
.
.
.
5 慢查询
# 单线程架构,命令一个个执行,
# 如果有长慢命令,会造成整个redis的阻塞
# redis提供一种方式,可以记录长慢命令【放到慢查询队列中】,用于后续的排查修改工作
# 配置一个时间,如果查询时间超过了我们设置的时间,我们就认为这是一个慢查询.
--------------------------------------------------------
# 配置慢查询------两个主要配置
slowlog-max-len :慢查询队列的长度 也就是说队列里最多放多少个慢查询命令
slowly-log-slower-than :超过多少微妙,就算慢命令,就会记录到慢查询队列中
# 实战----在redis客户端敲命令----给配置文件设置上
config set slowlog-log-slower-than 1000 # 默认是10000微秒 一般设1000微秒就是1毫秒
config set slowlog-max-len 2000 # 通常设1000左右
config rewrite # 写了永久生效,如果不写,只是暂时生效
# 查看慢查询队列
slowlog len # 查看当前慢查询队列里 有多少慢查询命令
slowlog reset # 清空慢查询队列
slowlog get # 获取慢查询队列的所有慢命令
--------------------------------------------------------
客户端超时不一定慢查询,但慢查询是客户端超时的一个可能因素
4个阶段都有可能导致客户端超时
.
.
.
.
.
.
.
.
.
6 pipeline与事务
# redis通过管道可以支持事务
# Redis的pipeline(管道)功能在命令行中没有,但redis是支持pipeline的,
而且在各个编程语言版的client中都有相应的实现(Redis模块)
将一批命令,批量打包,在redis服务端批量计算(执行),然后把结果批量返回
1次pipeline(n条命令)执行时间 = 1次网络时间 + n次命令执行时间
------------------------------------------------
# python实现pipline
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
#创建pipeline
pipe = r.pipeline(transaction=True)
#开启事务
pipe.multi()
pipe.set('name', 'lqz')
# 其他代码,可能出异常
pipe.set('role', 'nb')
pipe.execute() # 一次性把管道里所有命令,按顺序全部执行完,有一个命令执行失败,回滚到开始
---------------------------------------------------
# redis原生也能实现事务 直接在命令行里敲命令也能实现事务mutil
multi # 1 开启管道
set name lqz
set age 18 # 命令都放管道里了
exec # 放到管道中一次性执行
---------------------------------------------------
---------------------------------------------------
# 模拟实现乐观锁 watch+multi实现乐观锁
# 在开启事务之前,先watch
watch age # 监听 age 的值
multi
decr age
exec # 后执行 会失败 被watch的数据 乐观的认为不会不会被别人改,一旦自己要改该数据的时候
# 发现该数据被别人改过了,那么该改数据的命令就会执行失败,最终导致事务回滚到开始状态
------------------
# 另一台机器
multi # 和上面机器同时开启管道,两个机器开启的管道没有联系
decr age
exec # 先执行,上面的执行就会失败(乐观锁,被wathc的事务不会执行成功)
.
.
.
.
.
.
.
.
.
7 发布订阅
------------------------------------------------------------
发布订阅是观察者模式,只要订阅了某个东西,这个东西发生变化,我们就能收到
# 观察者(Observer) 模式定义:
对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
发布者发布了消息,所有的订阅者都可以收到通知
redis就能实现这样的功能 !!!
# 应用场景:比如关注了某个明星,该明星发了微博,所有关注他的人都能收到通知
------------------------------------------------------------
------------------------------------------------------------
# redis客户端 创建一个发布频道lqz 并发了条信息 hello
publish lqz hello # 只要有订阅者,客户端发送消息,所有订阅者都能收到
subscribe lqz # 另外的客户端,订阅lqz频道,等待接收消息
pubsub numsub lqz # 查看某个频道有几个订阅者
pubsub channels # 列出活跃的频道
# 发布订阅和消息队列的区别
发布订阅数全收到,消息队列有个抢的过程,只有一个抢到
发布订阅是观察者模式的实现,每个订阅者监听一个自己的队列,发布者发布消息后,放到每一个订阅者的队列里
这样所有的订阅者就都能收到了!!!
.
.
.
.
.
.
.
8 Bitmap位图
位图不是实际的数据类型,而是在字符串类型上定义的一组面向位的操作。
Bitmap位图:
# 是字符串类型,但是以二进制形式存储的,获取,设置某个二进制位的
--------------------------------------------------
set hello big
getbit hello xx # 返回从左起0开始,第xx个比特位,对应的数字0或1
setbit hello 7 1 # 把第7个比特位对应数字设置为1
get hello # big就变成了cit
---------------------------
.
.
bitcount name start end # start end 不写默认就是字符串全部索引对应的字符
# 统计字符串,索引范围内对应字符的对应二进制数字里有几个1
bitcount hello
bitcount hello 0 1
# 由于上面把一个0改成1了,所以结果是13个1
# 独立用户统计
假设:1亿用户,5千万活跃用户
要统计每一天的活跃用户是多少,怎么办?
数据类型 | 每个userid占用空间 | 需要存储用户量 | 全部内存量 |
---|---|---|---|
set集合 | 32位(假设userid是整形,占32位) | 5千万 | 32位*5千万=200MB |
bitmap | 1位 | 1亿 | 1位*1亿=12.5MB |
int32类型 4个字节表示一个数字---》 可以表示 正负 2的31次方-1的10进账数字范围
存一个数字1 都要占4个字节
存一个数字1001 都要占4个字节
-方式一:登录,把id放到集合中---》统计集合大小,就算出今天的用户活跃量了
-方式二:登录,操作位图,把id对应的数字设为1 ,以后统计1的个数
# 方式二具体实现:前提是用户量大的情况下
首先每天按日期在redis里面创一个对应的字符串
比如 set data1 c # 随便设置个简单的字符串 c
每天0点计数器归零,每来一个用户登录 setbit data1 n 1
# 给位图对象按计数器数字,给对应位置设置为1
# 这样一天下来,只要用 bitcount data1 统计一下该字符串里面有多少个1
# 就是今天所有的登录用户数了
-----------------------------------------
# 位图的其他操作方法 (好像没啥用)
bitpos hello 1 start end
# start end 指定从字符串的哪个索引位置开始查找 默认是从0到最后
# bitpos用于在位图指定比特位上查找第一个被设置为1或0的位置
bitpos hello 1 # 位图对象中第一个1的位置,结果是 1
bitpos hello 0 # 结果是 0
bitpos hello 1 1 2
# 返回从第一个字节到第二个字节之间 第一个1的位置,为 9
.
.
.
.
.
.
.
.
.
.
.
9 HyperLogLog
HyperLogLog是一种算法
redis中支持这种算法,
基于HyperLogLog算法: 极小的空间完成独立数量统计!!!
类似于布隆过滤器,但算法不一样
------------------------------------------
# HyperLogLog本质是字符串类型的数据,
# 但是可以往里面放值,而且只能往里放值,但是取不出来
# 只用来做个数统计与去重
pfadd key element # 向hyperloglog添加元素,可以同时添加多个
pfcount key # 计算hyperloglog的独立总数
pfadd uuids "uuid1" "uuid2" "uuid3" "uuid4" # 向uuids中添加4个uuid
pfcount uuids # 返回4
# 也可以做独立用户统计
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY