redis 操作指南、应用场景
5大应用场景:1.缓存技术; 2.列队; 3. 去重技术; 4. 积分板; 5.订阅与发布
Redis应用场景
- 使用Redis做缓存
- Redis的字符串、哈希表两种结构适合做key与value信息
- 使用Redis做队列
- 使用列表可以实现普通级和优先级队列功能
- 使用有序集合数据结构,可以实现优先级列队
- 使用哈希表可以实现 延时队列
- 使用Redis去重
- 利用集合,实现小批量数据去重
- 利用字符串数据结构的位操作,实现布隆过滤,大规模去重
- 利用自带的HyperLogLog数据结构,可以实现超大规模去重和计数
- 使用Redis实现积分板块
- 有序集合可以实现积分版功能,自动排序排名等
- 使用Redis实现发布订阅功能
- 自带的订阅发布模式可以实现多对多发布订阅
连接Redis
简单连接
通常本机没有设置密码 可以简写为
import redis
"""decode_responses 写存的数据是字符串形式"""
r = redis.Redis(host='ip地址', port=6379, db=0, password='设置的密码', decode_responses=True) # 默认db=0
"""本地redis无密码可以简写"""
r = redis.Redis()
连接池
当并发量比较高的时候, 频繁的连接创建和释放对性能会有较高的影响;连接池的原理是, 通过预先创建多个连接, 当进行redis操作时, 直接获取已经创建的连接进行操作。
import redis
"""decode_responses 写存的数据是字符串形式"""
pool = redis.ConnectionPool(host='ip地址', port=6379, db=0, password='设置的密码', decode_responses=True) # 默认db=0
r = redis.Redis(connection_pool=pool)
1. 字符串
插入字符串
简单插入
r.set('key', 'value')
nx=True控制相同key不覆盖
r.set('key', 'value', nx=True) # 不覆盖
获取
通过get获取到的是bytes类型,所以需要
decode转换
ret = r.get('key2').decode()
追加
- 文本追加
append(key,appebd)
往文本后面增加文本 - 数字增量
incr(key)
数字增加、参数2默认1= 增加1 - 数字减量
decr(key)
数字减小、参数2默认1= 减1
使用场景
常用于记录简单的映射关系。 例如 一万个员工信息与工号的关系 ,key=工号、value=员工名
弊端
- 数据量超过百万级,字符串储存会造成大量内存浪费, 此时推荐用redis的hash数据储存,**
内存占用率只有字符串类型1/4,速度不比字符串形式差
** - 当数据量上百万级时候,运行
keys *
会很卡,所以在不知道数据体量时,切勿运行keys *
命令
2. 列表
列表分左右两个方向,所以可以从两侧对列表进行操作
还有很多操作例如:
Lrem
删除指定元素lindex
获取指定下标的值ltrim
修剪列表Linsert
指定位置添加元素lpushx
如果存在添加,不存在不添加rpushx
同上blpop
有值就取出,否则阻塞等待brpop
同上brpoplpush
同上
插入数据
插入 | 描述 | 语法 |
---|---|---|
从左插入 | 原生语法 | lpush list str |
从左插入 | redis模块 | r.lpush(list, str) |
从右插入 | 原生语法 | rpush list str |
从右插入 | redis模块 | r.rpush(list, str) |
查看数据
查数据长度
查看 | 描述 | 语法 |
---|---|---|
查看长度 | 原生语法 | llen key |
查看长度 | redis模块 | r.llen(key) |
根据索引查找
索引从左边开始,可以为-1 例如 查看右边5条。
lrange key -5 -1
查找 | 描述 | 语法 |
---|---|---|
根据索引查找 | 原生语法 | lrange key 0 2 查找索引 0-2的 |
根据索引查找 | redis模块 | r.lrange(list, 0,2) |
查看列表所有 | 原生语法 | lrange key 0 -1 |
查看列表所有 | redis模块 | r.lrange(list, 0,-1) |
查看列表所有数据
在不知道数据量的时候,切勿查找所有,应当先查看其长度
查找 | 描述 | 语法 |
---|---|---|
查看列表所有 | 原生语法 | lrange key 0 -1 |
查看列表所有 | redis模块 | r.lrange(list, 0,-1) |
弹出数据
除了读取,还能弹出pop数据,弹出也分左右,注意数据弹出后会被删除
弹出 | 描述 | 语法 |
---|---|---|
从左弹出 | 原生语法 | lpush key |
从左弹出 | redis模块 | r.lpop(key) |
从右弹出 | 原生语法 | rpush key |
从右弹出 | redis模块 | r.rpop(key) |
删除数据
self.r.lrem(name, count, data)
# name = key
# count 删除个数
# data 删除的数据
修改数据
支持,根据索引查修改数据值
修改 | 描述 | 语法 |
---|---|---|
修改数据 | 原生语法 | lset key index new_str |
修改数据 | redis模块 | r.lset(key, index, value) |
3.1 无序集合
集合与列表不同之处: 集合数据不能重复,且集合没有方向!
集合的应用
- 根据集合内数据不重复的特性实现去重并记录信息
- 多个集合可以做交集、差集等计算
比如: 学生课程监控,学生报名每一门课为一个集合, 这样就可以计算出,既报了学科A 又报名了学科B的学生。 或者只报名了A没报名B的学生
插入数据
sadd key value1 value2
- key 可以是数字、字母、下划线、中文 但是不建议使用中文
- value 可以是一个或者多个,如果多个则必须用空格隔开
- 插入顺序无关
- 插入后返回插入数据量(去重之后的)
查找数据
spop取出的数据会被删除掉, 但是 smembers取全部数据不会删除
功能 | 描述 | 语法 |
---|---|---|
取元素数量 | 原生语法 | scard key |
取元素数量 | redis模块 | r.scard(key) |
取数据 | 原生语法 | spop key sount count为取多少数据 默认1条 |
取数据 | redis模块 | r.spop(key) |
取全部数据 | 原生语法 | smembers key |
取全部数据 | redis模块 | r.smembers(key) |
判断是否存在 | 原生语法 | sismember key 存在返回1 |
判断是否存在 | redis模块 | r.sismember(key,'value') |
删除数据
srem key value1 value2
集合的交集
概念:集合A 与 集合B ,A与B都有的数据集合称为交集
sinter key key2
集合的并集
概念:集合A 与 集合B ,两个集合合并在一起并去重
sunion key key2
集合的差集
概念:集合A 与 集合B ,只属于自己的集合,与上面两个相反
sdiff key key2
3.2 有序集合 (积分)
redis 利用有序集合可以实现积分排行功能,做到实时排名快速归类等特点
添加数据
方法1(可以用变量):
r.zadd('集合名',值1,分数1,值2,分数2)
方法2:
r.zadd('集合名',值1=分数1,值2=分数2)
修改评分
r.zincrby('有序集合名', 值, 新分数)
注意! 新版redis该命令修改为如下
r.zincrby('有序集合名', 分数加减, 值)
排序
按评分排序
规则 | 语法 |
---|---|
zrangebyscore |
分数从小到大排序 |
zrevrangebyscore |
分数从大到小排序 |
r.zrangebyscore('有序集合名', 查找分上线,查找分下限,结果切片起始,结果数量,withscores=False)
r.zrevrangebyscore('有序集合名', 查找分上线,查找分下限,结果切片起始,结果数量,withscores=False)
"""取积分在10~100内倒序取前三个"""
r.zrevrangebyscore('rank', 100, 10,0,3)
按位置排序
基于位置顺序进行排序, 支持-1这样的语法
规则 | 语法 |
---|---|
zrange |
分数从小到大排序 |
zrevrange |
分数从大到小排序 |
上述根据0开始的索引找到需要排序的元素范围,然后对这个范围内的数据进行排序
例如
r.zrange('有序集合名', 开始位置, 结束位置,desc=False, withscores=False)
r.zrevrange('有序集合名', 开始位置, 结束位置, withscores=False)
- desc=True zrange的属性,底层会调用reverange方法,作用是取最大值的x个元素,而不是取最小的x个元素再倒序
- withscores为False,返回结果会排序,否则返回元祖
取出分数最高的5个
r.zrange('rank',0,4,withscores=True)
查排名,查评分
可以查询一个值在列表中的排名
规则 | 语法 |
---|---|
zrank |
值存在返回排名(从0开始)0为最小分的下标,不存在返回None |
zrevrank |
值存在返回排名(从0开始)0为最大分的下标,不存在返回None |
zscore |
查询指定值的评分 |
zcard |
查询值总数 |
zcount |
查询评分范围内多少值 |
特别注意:
python与redis新版本数据库交互:
- zadd:
db.zadd(REDIS_KEY, {member:score})
- zincrby:
db.zincrby(REDIS_KEY, increment, menber)
4. 哈希表
HashTable : key-value的映射,根据key就能快速找到value,并且无论多少键值对,查询时间始终不变,Python字典就是基于哈希表实现的
哈希表可以保存大量数据,一个哈希表可以存储43亿个键值对
- 官方说,哈希表储存内容相同的情况下,内存占比比字符串小很多推荐使用
常用语法
意 | 语法 | 描述 |
---|---|---|
增 | r.hset('表名key', 字段, 值) |
添加hash值 |
增 | r.hmset('表名key', {字段1:值1,字段2:值2}) |
添加多个hash值 |
删 | r.hdel('表名key', 字段 |
删除hash |
查 | r.hvals('表名key') |
返回一个包含哈希表中所有值的表 |
查 | r.hkeys('表名key') |
所有字段的字段名 |
查 | r.hget('表名key', 字段名) |
取一个字段值 |
查 | r.hmget('表名key', [字段1, 字段2]) |
一次性取多个值 |
查 | r.hgetall('表名key') |
全表中所有字段于值 |
查 | r.hlen('表名key') |
查询表内字段总数,没有表返回0 |
查 | r.hexists('表名key', 字段) |
查询key是否存在 |
插入、删除、查重
案例1
import redis
pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)
# 插入
r.hset('online_status', 'user1', 1)
# 删除
r.hdel('online_status', 'user1')
# 查重
ret = r.hexists('online_status', 'user1')
print(ret)
案例2
单个参数 + 批量插入 Demo
import redis
import json
pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)
"""单个插入信息"""
r.hset('user_info', '小张', json.dumps({'age': 18, 'address': '重庆'}))
"""批量插入信息"""
other_people = {
'老王': json.dumps({'age': 18, 'address': '重庆'}),
'小李': json.dumps({'age': 18, 'address': '上海'}),
}
r.hmset('user_info', other_people)
5. 发布消息/订阅频道
该模式是一种消息通讯模式,实现了一堆多的消息实时发布功能,
优势:
- 不浪费系统监听资源
- 不会轮询带来的消息延迟
- 自动解决字符串通讯问题。
- 代码更简洁
在python中实现 redis的 发布订阅功能是非常的简单
服务端
import redis
r = redis.Redis(decode_responses=True)
r.publish('频道1', '是这条消息')
向一个指定频道发送一个消息
客户端订阅频道
import redis
r = redis.Redis(decode_responses=True)
listener = r.pubsub()
listener.subscribe('频道1')
for message in listener.listen():
print(message)
运行结果
注意链接上会自动打印一条链接频道的提示信息!
导出导入数据
源服务器
登录redis服务器,然后通过redis的客户端进行连接redis,命令如下:
[root@ ~]# redis-cli
127.0.0.1:6379>
注释:如果没有将redis-cli安装成服务,可以进入redis的src目录下进行客户端的连接
连接成功后,我们可以通过下面的命令找到redis的文件存放目录
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/var/lib/redis"
127.0.0.1:6379>
注释:在/var/lib/redis下
下面我们查看一下redis数据备份的触发条件,查看redis配置文件/ect/redis.conf ,可以看到redis数据备份的触发条件为:
save 900 1 #900秒内至少有1个key被更改,进行备份
save 300 10 #300秒内至少有300个key被更改,进行备份
save 60 10000 #60秒内至少有10000个key被更改,进行备份
我们可以通过 save的方式直接对此时的数据进行备份,命令如下:
[root@ ~]# redis-cli
127.0.0.1:6379> save #数据备份
127.0.0.1:6379> #退出
这个时候我们可以在redis的文件存放目录/var/lib/redis目录下看到刚刚备份的dump.rdb文件
目标服务器
登录目标redis服务器,我们先停止redis服务:
service redis stop #停止redis服务
然后进入redis的文件存放目录/var/lib/redis,把刚刚备份的dump.rdb文件替换该目录下的dump.rdb文件
(建议先备份当前目录下的dump.rdb文件),重启redis服务
service redis start #启动redis服务
到此,redis数据迁移完成
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!