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数据迁移完成