目录


  • 安装
  • redis 模块
  • Redis API 使用
  • 连接方式
  • String 操作
  • 按位操作的应用场景
  • Hash 操作
  • scan方法-用于获取大量的数据
  • List 操作
  • 阻塞的pop方法
  • Set 集合操作
  • 有序集合
  • 关于db
  • 管道
  • 发布/订阅

Redis-缓存系统

缓存系统也可以叫缓存数据库,现在主流的系统有 Redis 和 Memcached :

MongoDB,比较早的缓存系统,直接持久化到硬盘

Redis,现在正火的。半持久化数据,数据默认存在内存中,可以持久化到硬盘里持久保存。效率高,在单线程下运行,通过epoll实现的高并发

Memcached,轻量级的缓存系统,不能持久化只能存在内存中。相对应该比较简单,可以自学?

1、安装

通过yum安装就好了,在epel源里:

$ yum install redis

开放防火墙:

$ firewall-cmd --permanent --add-port=6379/tcp$ firewall-cmd --reload

开启服务:

$ redis-server

可以在命令后面加上 & ,这样启动后就是运行在后台。如果再后台运行想停止服务:

$ redis-cli shutdown

另外,redis默认是以保护模式启动的,只能本机连。你的redis可能不是运行在本机的,比如在虚拟机上,那么本机以外可能连不上,或者只能连不能改。就不要那么麻烦再去整配置文件了,这里以学习测试为主,推荐这么启动:

$ redis-server --protected-mode no

你也可以根据需要加上 & 启动后再后台运行。配置文件什么的用的时候再去研究吧,这里我们搭建学习环境。

可以先进入redis的命令行界面里简单操作一下,进入命令行界面:

$ redis-cli

简单的存一个值:

> set age 23

age是key,23是value,取出age的值:

> get age

查看已经存了哪些key:

> keys *

存值,有存活时间:

> set city ShangHai ex 2

上面存的值只能存活2秒,超过时间再去get,返回的就是(nil)

帮助命令很有用,有不清楚的,可以看下命令的语法和说明

> help [ 命令 ]


2、redis 模块

使用python操作redis,需要安装第三方模块,模块名也叫redis。

3、Redis API 使用

redis-py 的API的使用可以分类为:


  • 连接方式

  • 连接
  • 连接池

  • 操作

  • String 操作
  • Hash 操作
  • List 操作
  • Set 操作
  • Sort Set 操作

  • 管道
  • 发布订阅

参考资料:

​https://github.com/andymccurdy/redis-py/​

Redis 命令参考(中文翻译版):http://doc.redisfans.com/

4、连接方式

先来连接redis,然后把上面命令行界面里的操作在python上再做一遍:

Python操作Redis的最佳实践_数据

上面注释的部分给了另外一种通过连接池连接的方式,使用的时候,推荐使用连接池连接:

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。

5、String 操作

redis中的String在内存中是按照一个key对应一个value来存储。

​set(name, value, ex=None, px=None, nx=False, xx=False)​​ :设置值,默认如果key不存在则创建,key存在则修改

可选参数:


  • ex :过期时间(秒)
  • px :过期时间(毫秒)
  • nx :若设为True,只有name不存在时,set操作才执行
  • xx :若设为True,只有name存在时,set操作才执行

​setnx(name, value)​​ :效果同上面的 ns=True

​setex(name, value, time)​​ :效果同上面的 ex=time

​psetex(name, time_ms, value)​​ :效果同上面的 px=time_ms

​get(name)​​ :获取值

​mset(*args, **kwargs)​​ :批量设置

​mget(keys, *args)​​ :批量获取

Python操作Redis的最佳实践_数据_02

​getset(name, value)​​ 获取name的当前值,然后给name赋一个新的值

Python操作Redis的最佳实践_redis_03

​getrange(key, start, end)​​ :获取子序列,相当于列表切片(字符串也可以当列表操作)

Python操作Redis的最佳实践_redis_04

​setrange(name, offset, value)​​ :修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

Python操作Redis的最佳实践_redis_05

​setbit(name, offset, value)​​ :修改字符串内容,这里按二进制的bit位进行操作。上面那个是按字节操作

Python操作Redis的最佳实践_redis_06

​getbit(name, offset)​​ :获取name对应的值的二进制表示中的那一位的值,不是0就是1

​bitcount(key, start=None, end=None)​​ :获取name对应的值的二进制表中 1 的个数,加上 start 和 end 参数限制统计的范围

6、按位操作的应用场景

用最省空间的方式,存储在线用户数及分别是哪些用户在线。

用户状态只有2种,0离线,1在线。每个用户的状态只占1个位,每个用户都有一个用户id,用户id就是这个用户状态存储在变量中的 offset 的位置,具体看代码示例:

Python操作Redis的最佳实践_数据_07

​bitop(operation, dest, *keys)​​ :获取keys的值,按照operation的方法做位运算,结果赋值给dest。用不到

​strlen(name)​​ :返回name对应值的字节长度(一个汉字3个字节)

​incr(name, amount=1)​​ :自增 name 对应的值,当 name 不存在时,则创建 name=amount

​decr(name, amount=1)​​ :自减 name 对应的值,当 name 不存在时,则创建 name=amount

​incrbyfloat(name, amount=1.0)​​ :和上面差不多,支持浮点型数值

Python操作Redis的最佳实践_redis_08

​append(key, value)​​ :在 key 的 value 值后面追加内容

Python操作Redis的最佳实践_redis_09

7、Hash 操作

hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据

​hset(name, key, value)​​ :在name对应的hash中设置一个键值对(不存在,则创建;否则,修改)

​hmset(name, mapping)​​ :在name对应的hash中批量设置键值对

​hget(name, key)​​ :在name对应的hash中根据key获取value

​hmget(name, keys, *args)​​ :在name对应的hash中获取多个key的值

​hgetall(name)​​ :获取name对应hash的所有键值,key 和 value都获取,但是无区分

​hlen(name)​​ :获取name对应的hash中键值对的个数

​hkeys(name)​​ :获取name对应的hash中所有的key的值

​hvals(name)​​ :获取name对应的hash中所有的value的值

​hexists(name, key)​​ :检查name对应的hash是否存在当前传入的key

Python操作Redis的最佳实践_有序集合_10

​hdel(name,*keys)​​ :将name对应的hash中指定key的键值对删除

​hincrby(name, key, amount=1)​​ :自增name对应的hash中的指定key的值,不存在则创建key=amount

​hincrbyfloat(name, key, amount=1.0)​​ :自增name对应的hash中的指定key的值,不存在则创建key=amount

8、scan方法-用于获取大量的数据

​hscan(name, cursor=0, match=None, count=None)​​ :增量式迭代获取,对于获取数据量很大的数据时非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆。参数:


  • name :redis的name
  • cursor :游标(基于游标分批取获取数据)
  • match :匹配指定key,默认None表示所有的key。可以用通配符,? * 等,具体参考其他常用操作中的 keys 命令的参数
  • count :每次分片最少获取个数,默认None表示采用Redis的默认分片个数

​hscan_iter(name, match=None, count=None)​​ :利用yield封装hscan创建生成器,实现分批去redis中获取数据

9、List 操作

redis中的List在在内存中是按照一个name对应一个List来存储。

​lpush(name,values)​​ :在name对应的list中添加元素,每个新的元素都添加到列表的最左边

​rpush(name,values)​​ :同上,添加到右边

​llen(name)​​ :name对应的list元素的个数

​lrange(name, start, end)​​ :在name对应的列表分片获取数据,要获取列表全部,就 0, -1

Python操作Redis的最佳实践_有序集合_11

​lpushx(name,value)​​ :在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边

​rpushx(name,value)​​ :同上,添加到右边

Python操作Redis的最佳实践_redis_12

​linsert(name, where, refvalue, value))​​ :在name对应的列表的某一个值前(‘before’)或后(‘after’)插入一个新值

Python操作Redis的最佳实践_redis_13

​r.lset(name, index, value)​​ :对name对应的list中的某一个索引位置重新赋值

Python操作Redis的最佳实践_redis_14

​r.lrem(name, value, num)​​ :在name对应的list中删除指定的值。num为0删除所有;num为正数,从前往后删除num个;num为负数,从后向前删除num个。

Python操作Redis的最佳实践_redis_15

​lpop(name)​​ :在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素

​rpop(name)​​ :同上,从右侧获取并移除

​lindex(name, index)​​ :使用下标获取值

​ltrim(name, start, end)​​ :移除 start 和 end索引位置以外的值

Python操作Redis的最佳实践_redis_16

​rpoplpush(src, dst)​​ :从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边

Python操作Redis的最佳实践_redis_17


10、阻塞的pop方法

下面的2个pop方法和前面不带b开头的方法基本上是一样的,但是多了一个timeout参数。在timeout的时间内如果列表中没有值,则阻塞,一旦有值进来,就会取出来。非常像队列的操作。timeout如果是0,则一直阻塞,直到取到值。如果timeout时间到还没取到值,会返回None。

​blpop(keys, timeout)​​ :将多个列表排列,按照从左到右去pop对应列表的元素。这里keys可以是多个name

​brpop(keys, timeout)​​ :同上,每个列表中取元素的时候是从右开始

​brpoplpush(src, dst, timeout=0)​​ :

blpop 和 brpop 和前面略有不同,可以从多个列表中取值,具体效果如下:

Python操作Redis的最佳实践_数据_18


11、Set 集合操作

Set集合就是不允许重复的列表,并且集合是无序的。后面有有序集合

​sadd(name,values)​​ :name对应的集合中添加元素

​scard(name)​​ :获取name对应的集合中元素个数

​smembers(name)​​ :获取name对应的集合的所有成员

Python操作Redis的最佳实践_redis_19

​sdiff(keys, *args)​​ :差集,返回一个集合

​sdiffstore(dest, keys, *args)​​ :同上,返回值是新集合的元素个数,新集合存储到dest中

​sinter(keys, *args)​​ :交集,返回一个集合

​sinterstore(dest, keys, *args)​​ :同上,返回值是新集合的元素个数,新集合存储到dest中

​sunion(keys, *args)​​ :并集,返回一个集合

​sunionstore(dest,keys, *args)​​ :同上,返回值是新集合的元素个数,新集合存储到dest中

Python操作Redis的最佳实践_redis_20

​sismember(name, value)​​ :values 是否是 name 集合的成员

​smove(src, dst, value)​​ :将某个成员从一个集合中移动到另外一个集合

​spop(name)​​ :从集合的右侧(尾部)移除一个成员,并将其返回

​srandmember(name, numbers)​​ :从name对应的集合中随机获取 numbers 个元素,默认就取1个,可以取多个。

​srem(name, values)​​ :在name对应的集合中删除某些值

Python操作Redis的最佳实践_数据_21

同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法

​sscan(name, cursor=0, match=None, count=None)​

​sscan_iter(name, match=None, count=None)​


12、有序集合

有序集合,在集合的基础上,为每个元素排序,元素的排序需要根据另外一个值来进行比较。所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

​zadd(name, *args, **kwargs)​​ :在name对应的有序集合中添加元素,每个成员都要有一个分数,2种可是可选,看例子

​zcard(name)​​ :获取name对应的有序集合元素的数量

​zcount(name, min, max)​​ :也是统计集合的元素数量,但是是满足分数在 min 和 max 之间的元素的数量

Python操作Redis的最佳实践_有序集合_22

​zincrby(name, value, amount)​​ :自增name对应的有序集合的 value 对应的分数,默认自增1

​r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)​​ :按照索引范围获取有序集合的元素

参数:


  • name :
  • start :有序集合索引起始位置(非分数)
  • end :有序集合索引结束位置(非分数)
  • desc :排序规则,默认按照分数从小到大排序
  • withscores :是否获取元素的分数,默认只获取元素的值
  • score_cast_func :对分数进行数据转换的函数

​r.zrevrange( name, start, end, withscores=False, score_cast_func=float)​​ :另一种从大到小排列的方法

Python操作Redis的最佳实践_有序集合_23

​zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)​​ :按照分数筛选

​zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)​​ :同上,从大到小

Python操作Redis的最佳实践_数据_24

​r.zrangebylex(name, min, max, start=None,num=None)​​ :跳过,没讲,不好理解还用不上

​r.zrevrangebylex(name, max, min, start=None,num=None)​​ :同上,从打到小排列

​r.zremrangebylex(name, min, max)​​ :跳过

​zrank(name, value)​​ :获取某个值在 name 对应的有序集合中的排行(从 0 开始)。可以做班级成绩的排名

​zrem(name, values)​​ :删除name对应的有序集合中值是values的成员,删除单个或多个成员

​zremrangebyrank(name, min, max)​​ :根据排行范围删除

​zremrangebyscore(name, min, max)​​ :根据分数范围删除

​zscore(name, value)​​ :获取name对应有序集合中 value 对应的分数

Python操作Redis的最佳实践_数据_25

​zinterstore(dest, keys, aggregate=None)​​ :获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作

​zunionstore(dest, keys, aggregate=None)​​ :获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作

aggregate的值为: SUM MIN MAX

Python操作Redis的最佳实践_有序集合_26

同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法

​zscan(name, cursor=0, match=None, count=None, score_cast_func=float)​

​zscan_iter(name, match=None, count=None,score_cast_func=float)​

其他常用操作

​delete(*names)​​ :根据删除redis中的任意数据类型

​flushdb()​​ :删除当前db的所有数据

​flushall()​​ :删除所有db的所有数据

​exists(name)​​ :检测redis的name是否存在

​keys(pattern='*')​​ :根据模型获取redis的name,pattem参数可以使用通配符匹配,参考如下:


  • ​KEYS *​​ 匹配数据库中所有 key
  • ​KEYS h?llo​​ 匹配 hello , hallo 和 hxllo 等
  • ​KEYS h*llo​​ 匹配 hllo 和 heeeeello 等
  • ​KEYS h[ae]llo​​ 匹配 hello 和 hallo ,但不匹配 hillo

​expire(name ,time)​​ :为name设置超时时间。这个方法可以不必在赋值的时候就设置时间了,而且还能用于更新时间

​rename(src, dst)​​ :为name重命名

​move(name, db))​​ :将name移动到另外一个db中

13、关于db

db就是数据库,当 redis 服务器初始化时,会预先分配 16 (0-15)个数据库(该数量可以通过配置文件配置)。

之前的操作都是在默认的db=0下操作的。

cli命令行界面下,使用select命令切换库。python中可以在建立连接的时候声明连接哪个库。

删除数据和db的操作:

Python操作Redis的最佳实践_有序集合_27

移动、重命名:

Python操作Redis的最佳实践_有序集合_28

​randomkey()​​ :随机获取一个redis的name(不删除)

​type(name)​​ :获取name对应值的类型

同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法:

​scan(cursor=0, match=None, count=None)​

​scan_iter(match=None, count=None)​

14、管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次 pipline 是原子性操作。

Python操作Redis的最佳实践_有序集合_29


15、发布/订阅

这里分消息的发布方和订阅方。

发布消息,建立连接,然后发布消息。每条消息都有消息的频道和内容。

订阅消息,建立连接,订阅频道。开始接收消息。

发布方:

Python操作Redis的最佳实践_数据_30

订阅方:

Python操作Redis的最佳实践_数据_31

感觉这里以及上面的部分功能(List 操作中阻塞的pop方法)和消息队列有交集,需要的时候选择是个更加合适的系统使用。

这里讲的比较简单,基本上就是简单过了一遍。还有更多细致的功能,只能去查阅文档资料了。

在Python开发中经常会使用到Redis做缓存、消息队列等业务场景,此文全方面说明了Redis用法,建议收藏,以备后用!


文章转发“DevOps大咖”公众号,里面更多运维、开发领域文章,欢迎关注

长按二维码识别关注

Python操作Redis的最佳实践_有序集合_32