redis之哈希类型-列表类型-集合类型-有序集合-慢查询-pipeline-发布订阅-Bitmap位图-HyperLogLog-GEO地理位置

发布时间 2023-04-23 21:52:10作者: lsumin

redis之哈希类型-列表类型-集合类型-有序集合-慢查询-pipeline-发布订阅-Bitmap位图-HyperLogLog-GEO地理位置

昨日内容回顾

# 1 redis介绍
	特性:
    # 速度快:10w ops(每秒10w读写) 数据存在内存中 c语言实现 单线程模型
    # 持久化:rdb和aof
    # 多种数据结构:
    	5大数据结构
        BitMaps位图:布隆过滤器 本质是 字符串
        HyperLogLog:超小内存唯一值计数 12kb HyperLogLog 本质是 字符串
        GEO:地理信息定位 本质是有序集合
    # 支持多种编程语言:基于tcp通信协议 各大编程语言都支持
    # 功能丰富:发布订阅(消息) Lua脚本 事务(pipeline)
    # 简单:源代码几万行 不依赖外部库
    # 主从复制:主服务器和从服务器  主服务器可以同步到从服务器中
    # 高可用和分布式:
    	2.8版本以后使用redis-sentinel支持高可用
        3.0版本以后支持分布式
        
# 2 redis在linux上安装
	wget 源代码下载
    make
    make install
    src:可执行文件
    
# 3 三种启动方式
	redis-server
    动态参数 --xx xx
    配置文件启动(常用)
    
# 4 客户端连接 关闭服务端 查看服务项 查看redis进程
	redis-cli -h 127.0.0.1 -p 6379
    ps -ef|grep redis---> kill 端口号
    ps -ef|grep redis  #查看进程
    netstat -antpl|grep redis #查看端口
	redis-cli -h ip -p port ping #命令查看
    
# 5 应用场景
	缓存系统 计数器 消息队列 排行榜 社交网络 实时系统 地理位置信息
    
# 6 通用命令
	keys  # 打印
    	keys * 打印所有  keys he[h-l] 打印he开头第三个字母h到l
    dbsize  # 计算key的总数
    exists key  # 查看key是否存在,存在返回1 不存在返回0
    del key  # 删除,成功返回1 不成功返回0
    expire key 数字  # 几秒过期
    ttl key  # 查看key过期时间
    persist key  # 去掉key的过期时间
    type key  # 查看key类型
    
    info命令  # 内存 cpu 主从相关
    client list  # 正在连接的会话
    

今日内容详细

1 哈希类型

### 1 ---hget,hset,hdel
hget key field  # 获取hash key对应的field的value 时间复杂度为 o(1)
hset key field value  # 设置hash key对应的field的value值 时间复杂度为 o(1)
hdel key field  # 删除hash key对应的field的值 时间复杂度为 o(1)
# 举例
hset user:1:data age 22
hget user:1:data age
hset user:1:info name lqz
hgetall user:1:data
hdel user:1:data

### 2 ---hexists,hlen
hexists key field  # 判断hash key 是否存在field 时间复杂度为 o(1)
hlen key  # 获取hash key field的数量  时间复杂度为 o(1)
heixts user:1:data name  # 存在返回1 不存在返回0
hlen user:1:data  # 返回数量

### 3 ---hmget,hmset
hmget key field1 field2...  # 批量获取hash key 的一批field对应的值  时间复杂度是o(n)
hmset key field1 value1 field2 value2  #批量设置hash key的一批field value 时间复杂度是o(n)

### 4 ---hgetall,hvals,hkeys
hgetall key  #返回hash key 对应的所有field和value  时间复杂度是o(n)
hvals key   #返回hash key 对应的所有field的value  时间复杂度是o(n)
hkeys key   #返回hash key对应的所有field  时间复杂度是o(n)
### 小心使用hgetall
# 举例
## 计算网站每个用户主页的访问量
hincrby user:1:info pageview count
## 缓存mysql的信息 直接设置hash格式

### 其他操作 hsetnx,hincrby,hincrbyfloat
hsetnx key field value  # 设置hash key对应field的value(如果field已存在 则失败) 时间复杂度o(1)
hincrby key field intCounter #hash key 对英的field的value自增intCounter 时间复杂度o(1)
hincrbyfloat key field floatCounter #hincrby 浮点数 时间复杂度o(1)

2 列表类型

# 插入操作

# rpush 从右侧插入
rpush key value1 value2 value3...  # 时间复杂度为o(1~n)
# lpush 从左侧插入

# linsert
linsert key before|after value newvalue  # 从元素value的前或后插入 newValue 时间复杂度o(n) ,需要遍历列表
## 举例
linsert listkey before b java
linsert listkey after b php

# 删除操作
lpop key  # 从列表左侧弹出一个item 时间复杂度o(1)
rpop key #从列表右侧弹出一个item 时间复杂度o(1)
lrem key count value
# 根据count值 从列表中删除所有value相同的项 时间复杂度o(n)
count>0 从左到右 删除最多count个value相等的项
count<0 从右向左,删除最多 Math.abs(count)个value相等的项
count=0 删除所有value相等的项
lrem listkey 0 a  # 删除列表中所有值a
lrem listkey -1 c  # 从右侧删除1个c

ltrim key start end  # 按照索引范围修剪列表 o(n)
ltrim listkey 1 4  # 只保留下表1--4的元素

# 查询操作
lrange key start end  # 包含end获取列表指定索引范围所有item o(n)
lrange listkey 0 2
lrange listkey 1 -1 #获取第一个位置到倒数第一个位置的元素

lindex key idnex  # 获取列表指定索引的item o(n)
lindex listkey 0
lindex listkey -1

llen key  # 获取列表长度

# 修改操作
lset key index newvalue  # 设置列表指定索引值为newvalue o(n)
lset listkey 2 ppp  # 把第二个位置设为ppp

# 实现timeLine功能 时间轴 微博关注的人 按时间轴排列 在列表中放入关注人的微博即可

# 其他操作
blpop key timeout  # lpop的阻塞版 timeout是阻塞超时时间 timeout=0为拥有不阻塞 o(1)
brpop key timeout  # rpop的阻塞版,timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1)

# 要实现栈的功能
lpush+lpop
# 实现队列功能
lpush+rpop
# 固定大小的列表
lpush+ltrim
# 消息队列
lpush+brpop 

3 集合类型

sadd key element  # 向集合key添加element(如果element存在,添加失败) o(1)
srem key element  # 从集合中的element移除掉 o(1)
scard key  # 计算集合大小
sismember key element  # 判断element是否在集合中
srandmember key count  # 从集合中随机取出count个元素,不会破坏集合中的元素
spop key  # 从集合中随机弹出一个元素
smembers key  # 获取集合中所有元素 无序 小心使用 会阻塞住

sdiff user:1:follow user:2:follow  # 计算user:1:follow和user:2:follow的差集
sinter user:1:follow user:2:follow  # 计算user:1:follow和user:2:follow的交集  
sunion user:1:follow user:2:follow  # 计算user:1:follow和user:2:follow的并集

sdiff|sinter|sunion + store destkey...  # 将差集,交集,并集结果保存在destkey集合中

# 应用场景
去重场景
抽奖系统:通过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

# API使用
zadd key score element  # score可以重复 可以多个同时添加 element不能重复 o(logN)
zrem key element  # 删除元素 可以多个同时删除 o(1)
zscore key element  # 获取元素的分数 o(1)
zincrby key increScore element  # 增加或减少元素的分数 o(1)
zcard key  # 返回元素总个数
zrank key element  # 返回element元素的排名(从小到大排)

zrange key 0 -1  # 返回排名 不带分数 o(log(n)+m) n是元素个数,m是要获取的值
zrange player:rank 0 -1 withscores  # 返回排名 带分数
zrangebyscore user:1:ranking 90 210 withscores  # 获取90分到210分的元素

zcount key minScore maxScore  # 返回有序集合内在指定分数范围内的个数 o(log(n)+m)

zremrangebyrank key start end #删除指定排名内的升序元素 o(log(n)+m)
zremrangebyrank user:1:rangking 1 2 #删除升序排名中1到2的元素

zremrangebyscore key minScore maxScore #删除指定分数内的升序元素 
zremrangebyscore user:1:ranking 90 210 #删除分数90到210之间的元素

# 举例
排行榜:音乐排行榜 销售榜 关注榜 游戏排行榜

# 其他操作
zrevrank  # 返回某个元素从高到低排序的顺序
#zrevrank girls dlrb  返回迪丽热巴 按分数降序排的排名
zrevrange  # 从高到低排序取一定范围
zrevrangebyscore  # 返回指定分数范围内的降序元素

zinterstore  # 对两个有序集合交集
zunionstore  # 对两个有序集合求并集

5 慢查询

# 单线程架构 命令一个个执行 会有长慢命令 造成整个redis的阻塞

# redis提供一种方式 可以记录长慢命令【放到慢查询队列中】 用于后续的排查修改工作

# 配置慢查询
	slowlog-max-len:慢查询队列的长度
    slowly-log-slower-than:超过多少微秒 就算慢命令 就会记录到慢查询队列中
    
# 举例
config set slowlog-log-slower-than 0
config set slowlog-max-len 100
config rewrite  # 写了永久生效,如果不写,只是暂时生效

# 查看慢查询队列
slowlog len  # 获取慢查询队列长度
slowlog reset  # 清空慢查询队列
slowlog get  # 获取慢查询队列的所有命令

6 pipeline与事务

Redis的pipeline(管道)功能在命令行中没有 但redis是支持pipeline的 而且在各个语言版的client中都有相应的实现(Redis模块)

将一批命令 批量打包 在redis服务端批量计算(执行) 然后把结果批量返回
1次pipeline(n条命令)=1次网络时间+n次命令时间

# python实现pipeline
import redis

pool = redis.ConnectionPool(host='101.43.19.239', port=6379, password='123456')
r = redis.Redis(connection_pool=pool)
# 创建pipeline
pipe = r.pipeline(transaction=True)
# 开启事务
pipe.multi()
pipe.set('name', 'lqz')
# 其中代码出现异常 整个事务失败
pipe.set('data', 'nb')
pipe.execute()


# redis原生实现事务 实现事务mutil
# 1 mutil 开启事务 放到管道中一次性执行
multi  # 开启事务
set name lqz
set age 19
exec

# 2 模拟实现乐观锁 watch+multi实现乐观锁
# 在开启事务之前 先watch
watch age
multi
decr age
exec

# 另一台机器
multi
decr age
exec  # 先执行 上面的执行就会失败(乐观锁 被watch的事务不会执行成功)

7 发布订阅

# 发布订阅是 观察者模式:只要订阅了某个东西 这个东西发生变化 我们就能收到
发布者发布了消息 所有的订阅者都可以收到 就是生产者消费者模型(后订阅了 无法获取历史消息)

# 一个客户端发送消息
publish lqz hello  # 只要有订阅者 客户端发送消息 所有订阅者都能收到

# 另外两个客户端 订阅频道 等待接收消息
subscribe lqz

# 查看某个频道有几个订阅者
pubsub numsub lqz

# 列出活跃的频道
pubsub channels

# 发布订阅和消息队列
发布订阅数全收到 消息队列有个抢的过程 只有一个抢到

8 Bitmap位图

Bitmap位图:是字符串类型 但是以二进制形式存储的 获取 设置某个二进制位的

# set hello big
# getbit hello 0/1/2  # 返回比特位是0或1

# setbit hello 7 1  # 把第7 也就是第8个比特位设置为1
big就变成了cit
# bitcount hello 0 1  # 0到1的字节上的比特位上有几个1 返回几

# 独立用户统计
	假设:1亿用户 5千万活跃用户 统计今天活跃用户是多选 用户iduserid是整形 32位整型
    	int32类型 4个字节表示一个数字---> 正负2的31次方-1 的范围
        	1    4个字节
            1001 4个字节
        方式一:登录 把id放到集合中---> 统计集合大小
        方式二:登录 操作位图 把id对应的数字设为1 以后统计1的个数
'''
假设有10w独立用户 使用位图还是占用12.5mb 使用set需要32位*1万=4mb
'''

9 HyperLogLog

reids中支持这种算法 基于HyperLogLog算法:极小的空间完成独立数量统计 很类似于布隆过滤器

pfadd key element  # 向hyperloglog添加元素 可以同时添加多个
pfcount key  # 计算hyperloglog的独立总数

pfadd uuids "uuid1" "uuid2" "uuid3" "uuid4"  # 向uuids中添加4个uuid
pfadd uuids  # 返回4

# 也可以做独立用户统计

10 GEO地理位置

# GEO(地理信息定位):存储经纬度 计算两地距离 范围等
	根据经纬度---> 确定具体地址的---> 高德开放api---> 返回具体地址
    
# redis 可以存储经纬度 存储后可以做运算
	比如:两个经纬度之间距离(直线距离)
    比如:统计某个经纬度范围内有哪些好友 餐馆
    
# 经纬度如何获取
	跟后端没关系:只需要存
    app 有定位功能
    网页 集成了高德地图 定位功能
    
# redis存储
geoadd key 经度 维度 名字
# 添加
geoadd cities:locations 116.28 39.55 beijing
# 查看位置信息
geopos cities:locations beijing #获取北京地理信息
# 计算两个点距离
geodist cities:locations beijing tianjin km
# 计算附近的xx
georadiusbymember cities:locations beijing 150 km

# 使用的是五大数据类型中的:有序集合