redis之哈希类型-列表类型-集合类型-有序集合-慢查询-pipeline-发布订阅-Bitmap位图-HyperLogLog-GEO地理位置
目录
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
# 使用的是五大数据类型中的:有序集合