解锁Redis不一样的知识

1. Redis基本操作

① 安装Redis

② 启动Redis

③ 配置Redis

# 找到自己redis配置文件,然后修改这个配置文件
[root@master redis]# vim redis.conf
protected-mode yes    # 打开保护模式
port 6380                          # 生产环境中端口不要使用默认的6379,使用其它端口,如6380等。
requirepass xxx        	  # 找到requirepass,设置redis的启动密码,xxx是自定义的密码
bind 0.0.0.0                      # 如果想让外部计算机也连接redis,可以设置绑定的ip。

设置好配置文件后要指定这个配置文件启动redis:

[root@master redis]# redis-server redis.conf 
27615:C 10 Oct 2019 08:39:39.974 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
27615:C 10 Oct 2019 08:39:39.974 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=27615, just started
27615:C 10 Oct 2019 08:39:39.974 # Configuration loaded

[root@master redis]# ps -ef |grep redis
root     27616     1  0 08:39 ?        00:00:00 redis-server 0.0.0.0:6380
root     27659 26530  0 08:40 pts/0    00:00:00 grep --color=auto redis

# 注意如果redis可以在多个端口开启多个进程 ,只需按不同的配置文件(配置不同的端口)启动即可
[root@master redis]# ps -ef |grep redis
root     27616     1  0 08:39 ?        00:00:00 redis-server 0.0.0.0:6380
root     28016     1  0 08:46 ?        00:00:00 redis-server 0.0.0.0:6390
root     28029 26530  0 08:46 pts/0    00:00:00 grep --color=auto redis

如果你的redis在本地,使用客户端命令连接redis的时候,只需要指定端口。如果你的redis在服务器中,打开客户端的时候记得要指定端口指定主机地址:

thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136
106.12.115.136:6380> 

如果你开始操作数据库,这个时候redis会要求让你输入启动密码:

thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136
106.12.115.136:6380> set username thanlon  
(error) NOAUTH Authentication required.
106.12.115.136:6380> auth redis   		# 密码错误
(error) ERR invalid password
106.12.115.136:6380> auth redis       # 密码正确
OK

# 也可以在连接redis服务端的时候指定redis启动密码,使用-a参数。但是,不建议,因为直接暴露了密码,redis也会提示你这样可能是不安全的。
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 -a redis
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
106.12.115.136:6380> 

关闭redisk可以直接杀死进程,但这样可能会造成数据丢失。建议使用客户端发起关闭redis服务的,着属于正常关闭redis,可以数据的安全:

# 设置了启动密码,所以被拒绝关闭
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 shutdown
(error) NOAUTH Authentication required.
# 我们带上密码来关闭,这样就成功关闭了
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 -a redis shutdown
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
thanlon@plus-book:~$ 
# 再到服务器确定关闭与否(redis已经被成功关闭)
[root@master ~]# ps -ef |grep redis
root     28786 28722  0 08:57 pts/1    00:00:00 grep --color=auto redis
2. Redis主从复制
  • redis集群中数据库的复制是通过主从同步来实现的
  • 主节点(Master)把数据分发给从节点(Slave)
  • 主从同步的好处在于高可用,redis节点有冗余设计

在这里插入图片描述

准备两台机器,我这里使用的是VMware虚拟化两台cetnos机器,ip分别是10.0.0.2和10.0.0.3,跟别作为主、从数据库。就使用这两台机器来做redis的主从同步。另外,为了方便使用,我使用XShell软件来连接我的这两台linux机器。

① 为两天机器安装redis,上文有介绍,在这里不赘述:https://blog.csdn.net/Thanlon/article/details/100941385#41_redis_548

② 配置主(Master)数据库的配置文件

# 查看配置文件有用的信息行
[root@slave redis]# grep -v '#|^$' /usr/local/redis/redis.conf
# 编辑配置文件
[root@master redis]# vim redis.conf
# 修改下面几行为
bind 10.0.0.2      # 绑定本机的ip地址。外网情况下,不要绑定端口,直接bind 0.0.0.0
daemonize yes      # 设置后台进程方式运行
requirepass redis  # 为主redis设置密码
# 查看redis是否设置密码
10.0.0.2:6379> config get requirepass
1) "requirepass" # 关键字 
2) "redis"    	 # 密码
# 可以更改密码
10.0.0.2:6379> config set requirepass "redis"
OK
# 指定此配置文件启动redis
[root@master redis]# redis-server redis.conf

③ 配置从(Slave)数据库的配置文件

# 查看配置文件有用的信息行
[root@slave redis]# grep -v '#|^$' /usr/local/redis/redis.conf
# 编辑从数据库配置文件
[root@master redis]# vim redis.conf
# 修改下面几行为
bind 10.0.0.3             # 绑定本机的ip地址。外网情况下,不要绑定端口,直接bind 0.0.0.0
replicaof 10.0.0.2 6379   # Master的ip和端口
masterauth redis          # Master的密码
# 指定此配置文件启动redis
[root@slave redis]# redis-server redis.conf

④ 主从同步的验证

  • 主服务器的操作
# 登录主redis
[root@master redis]# redis-cli -h 10.0.0.2
# 输入主redis密码
10.0.0.2:6379> auth redis
OK
# 向主redis中添加数据
10.0.0.2:6379> set username thanlon
OK
# 查看主redis中的已经添加的数据
10.0.0.2:6379> keys *
1) "username"
  • 从服务器的操作
# 登录从redis
[root@slave redis]# redis-cli -h 10.0.0.3
# 查看从redis的数据(从redis中一开始没有数据)
10.0.0.3:6379> keys *
1) "username"
# 如果操作(例如删除)从主redis中同步的数据,就会提示数据是只读的
10.0.0.3:6379> del username
(error) READONLY You can't write against a read only replica.

注意:如果两个redis链接不成功,要排查redis是不是同一个版本、是不是都是源码安装或yum安装的。

3. Redis多实例配置

redis支持多实例的用法,也就是一个服务器可以运行多个redis服务端。我们这里把只用Master一台服务器就可以了。

# 查看redis下的文件(redis.conf是从源码包中拷贝过来的)
[root@master redis]# ls
bin  dump.rdb  redis.conf
# 修改该配置文件
[root@master redis]# mv redis.conf redis-6379.conf
# 将该配置文件备份(备份与否都可以,此步可忽略)
[root@master redis]# cp redis-6379.conf redis-6379.conf.bak
# 再复制一个redis-6379.conf并命名为redis-6380.conf作为另一个实例
[root@master redis]# cp redis-6379.conf redis-6380.conf 
# 修改redis-6379.conf配置文件中的参数
bind 10.0.0.2
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
# 修改redis-6380.conf配置文件中的参数
bind 10.0.0.2
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
# 查看redis的运行状态
[root@master redis]# ps -ef |grep redis
root       6436      1  0 Oct09 ?        00:00:17 redis-server 10.0.0.2:6379
root       6485      1  0 00:55 ?        00:00:00 redis-server 10.0.0.2:6380
root       6498   6402  0 00:56 pts/1    00:00:00 grep --color=auto redis

PS:上面的操作表示两个redis实例的配置已经完成,下面我们将这两个实例做主从同步

# 修改“从数据库”的配置文件redis_6379.conf
[root@master redis]# vim redis-6379.conf 
# 找到replicaof参数修改如下,表示从10.0.0.26379端口同步
replicaof 10.0.0.2 6379
# 开始两个实例服务
[root@master redis]# redis-server redis-6379.conf
[root@master redis]# redis-server redis-6380.conf
# 客户端连接这两个端口的redis服务
[root@master redis]# redis-cli -p 6379 -h 10.0.0.2
[root@master redis]# redis-cli -p 6380 -h 10.0.0.2
# 6379端口所在的redis客户端进行添加数据操作
10.0.0.2:6379> set username thanlon
OK
# 查看6380端口所在的redis客户端的数据,至此配置成功
10.0.0.2:6380> keys *
1) "username"
4. Python连接Redis

第一种方式使用的是普通的连接:

# -*- coding: utf-8 -*-
import redis

conn = redis.Redis(host='106.12.115.133', port=6379,password='xxx')
conn.set('name', 'kiku')
print(conn.get('name'))

第二种方式使用的是连接池连接(与线程池是一样的,可以防止重复的连接节省开销,建议使用这种方式):

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.133', port=6379, max_connections=1000,password='xxx')  # max_connections最大连接数
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
5. Python操作Redis

① String操作
redis中的String在内存中按照一个name对应一个value来存储

  • set(name, value, ex=None, px=None, nx=False, xx=False):在redis中设置值,默认不存在则创建存在则修改
ex:过期时间()
px:过期时间(毫秒)
nx:如果设置为True,只有name不存在时,当前set操作才执行(添加)
xx:如果设置为True,只有name存在时,当前set才执行操作(修改)
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.get('name'))  # b'thanlon'
  • setnx(name,value):设置值,只有name不存在时,执行设置操作
  • setex(name,value,time):设置值,time是过期时间(数字秒或timedelta对象)
  • psetex(name,time_ms,value):设置值,time_ms是过期时间(数字秒或timedelta对象)
  • mset(*args,**keargs):批量设置值,如:
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.mset({'name':'thanlon','age':23})
  • get(name):获取值
  • mget(keys,*args):批量获取值,如:
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.mget('name', 'age'))  # [b'thanlon', b'23']
print(conn.mget(['name', 'age']))  # 与上一行等价
  • getset(name,value):设置新值并获取原来的值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.getset('name', 'kiku'))  # b'thanlon'
  • getrange(key,start,end):获取子序列(根据字节获取,非字符),start表示起始位置(字节);end表示结束位置(字节)。Python2中代表的是字符。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.getrange('name', 0, 2))  # 三个字符:b'kik'
conn.set('name', '奈何先生')
print(conn.getrange('name', 0, 2))  # 以中文字节形式获取中文呢:b'\xe5\xa5\x88'
  • setrange(name,offset,value):修改字符串内容,从指定字符串索引开始后替换(新值太长时,则向后添加)。offset表示字符串索引,字节(一个汉字三个字节);value是要设置的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.get('name'))
conn.setrange('name', 7, 'kiku')  #
print(conn.get('name'))  # b'thanlonkiku'
  • setbit(name,offset,value):对name对应的值的二进制表示的位进行操作,修改二进制位。name是redis中的name,offseet是位的索引(将值变换成二进制后再进行索引),value的值只能是1或0。
  • getbit(name,offset):获取name对应的值的二进制表示中的某位的值,可用来判断获取的是0还是1
  • bitcount(key,start=None,end=None):获取二进制数中有多少个1
  • bitop(operation,dest,*keys):获取多个值,并将值作做位运算,将最后的结果保存至新的name对应的值
参数:
operation--------AND(),OR(),NOT(),XOR(异或)
dest---------------新的redisd的name
*keys------------- 要查找的redis的name
例如:获取n1,n2,n3对应的值,然后将所有的值做位运算(求并集),然后将结果保存在new_name对应的值中
bitop('AND','new_name','n1','n2','n3')
  • strlen(name):返回name对应值的字节长度(一个汉字3个字节)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.strlen('name'))
conn.set('name', '奈何先生')  # 一个汉字三个字节
print(conn.strlen('name'))
  • incr(self,name,amount=1):自增,name对应的值,当name不存在时,则创建name=amount,否则则自增。同incrby(self,name,amount=1)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('age'))  # b'24'
conn.incr('age')
print(conn.get('age'))  # b'25'
  • decr(self,name,amount=1):自减,name对应的值,当name不存在时,则创建name=amount,否则则自减。同decrby(self,name,amount=1)。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('age'))  # b'25'
conn.decr('age')
print(conn.get('age'))  # b'24'
  • incrbyfloat(self,name,amount=1.0):自增,只不过可以自增浮点数,如果amount的值是负的,则表示自减,注意没有decrbyfloat(self,name,amount=1.0)
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('no'))  # None
conn.incrbyfloat('no')
print(conn.get('no'))  # b'1'
conn.incrbyfloat('no', 0.1)
print(conn.get('no'))  # b'1.1'
  • append(key,value):在name对应的值后面追加内容
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.get('name'))  # b'thanlon'
conn.append('name', ' love kiku')
print(conn.get('name'))  # b'thanlon love kiku'

② hash操作
redis中的hash类型可以看成具有String key和String Value的map容器。所以,该类型非常适合于存储值对象的信息,如:username,password,age,sex等。我们可以使用redis的hash来存储session。

  • hset(name,key,value):name对应的hash中设置一个键值对,参数name是redis的name,key是name对应的hash中的key,value是name对应的hash中的value。hsetnx(name,key,value)表示当name对应的hash中不存在当前key时则创建(相当于添加)
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hset('admin','name','thanlon')
conn.hset('admin','age',23)
  • hmset(name,mapping):在name对应的hash中批量设置键值对
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.hmset('admin', {'name': 'thanlon', 'age': 23, 'sex': '男'})
  • hget(name,key):在name对应的hash中获取key的值value
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.hset('admin','name','thanlon')
conn.hset('admin','age',23)
print(conn.hget('admin','name'))
print(conn.hget('admin','age'))
  • hmget(name,keys,*args):在name对应hash中获取多个key的值value
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hmset('admin', {'name': 'thanlon', 'age': 23, 'sex': '男'})
print(conn.hmget('admin', 'name', 'age', 'sex'))  # [b'thanlon', b'23', b'\xe7\x94\xb7']
  • hgetall(name):获取name对应的hash的所有键值,以字典类型返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hgetall('admin'))  # {b'name': b'thanlon', b'age': b'23', b'sex': b'\xe7\x94\xb7'}
  • hlen(name):获取name对应的hash中键值对的个数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hlen('admin'))  # 3
  • hkeys(name):获取name对应的hash中所有key的值,列表形式返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hkeys('admin'))  # [b'name', b'age', b'sex']
  • hvals(name):获取name对应的hash中所有value值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hvals('admin'))#[b'thanlon', b'23', b'\xe7\x94\xb7']
  • hexits(name,key):检查name对应的hash是否存在当前输入的key
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hexists('admin', 'age'))  # True
  • hdel(name,*keys):将name对应的hash中的指定key的键值对删除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hdel('admin', 'sex', 'age'))  # 2
  • hincrby(name,key,amount=1):自增name对应的hash值中的指定key值,不存在则创建key=mount
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hincrby('admin',1,amount=2)
print(conn.hget('admin', 1))  # b'2'
  • hincrbyfloat(name,key,amount=1.0):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hincrbyfloat('admin', 2, amount=0.1)
print(conn.hget('admin', 2))  # b'1.1'
  • hscan(name,cursor=0,match=None,count=None):增量式迭代获取,对于数据大的数据非常有用。hscan可以实现分片地获取数据,并非一次性将数据全部获取完放置内存被撑爆。name是redis中的name,cursor是游标(基于游标分批获取数据),match是匹配指定的key,默认None,表示所有key,count是每次分片最少获取的个数,默认是None表示采用redis的默认分片个数。如:
# 第一次:
cursor1,data1 = conn.hscan('xxx',cursor=0,match=None,count=None)
# 第二次:
cursor2,data2 = conn.hscan('xxx',cursor=cursor1,match=None,count=None)
……
直到返回值cursor的值为0时,表示数据已经通过分片获取完毕。
  • hscan_iter(name,match=None,count=None):利用yield封装hscan创建生成器,实现分批去redis中获取数据
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
for item in conn.hscan_iter('admin'):
    print(item)
# (b'name', b'thanlon')
# (b'sex', b'man')
# (b'age', b'23')

③ List操作

  • lpush(name,values):在name对应的list中添加元素,每个新的元素添加到列表的最左边
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('names', 'thanlon')
conn.lpush('names', 'kiku')
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
  • lpushx(name,value):在name对应的list中添加元素,只有name存在时,值添加到列表的最左边
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpushx('names', '奈何先生')
  • llen(name):name对应的list元素的个数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
print(conn.llen('names'))  # 2
  • linsert(name,where,refvalue,value):在name对应的列表的某一个值前或后插入一个新值。where只能写两个值一个是BEFORE,一个是AFTER。refvalue是标杆值,即:在它的前后插入数据,value是要插入的数据。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
conn.linsert('names', 'after', 'thanlon', 'john')
conn.linsert('names', 'before', 'thanlon', 'Tom')
print(conn.lrange('names', 0, -1))  # [b'kiku',b'Tom', b'thanlon', b'john']
  • lset(name,index,value):对name对应的list中某一个索引位置重新赋值,index是list的索引位置,value是要设置的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
conn.lset('names', 0, 'Tom')
print(conn.lrange('names', 0, -1))  # [b'Tom', b'john']
  • lrem(name,count,value):在name对应的list中删除指定的值,count=0表示删除列表中所有指定的值,count=2表示从前到后删除2个,count=-2表示从后向前删除2个。
# -*- coding: utf-8 -*-
# 删除所有指定的“Tom”
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Tom', b'Tom', b'Thanlon', b'kiku', b'john']
conn.lrem('names', 0, 'Tom')  # 删除所有的Tom
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john']
# 从前到后删除2个“Tom”
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Tom', b'Tom', b'Thanlon', b'kiku', b'john', b'Tom']
conn.lrem('names', 2, 'Tom')
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john', b'Tom']
  • lpop(name):在name对应的列表的最左侧获取第一个元素并删除,返回值则是第一个元素。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lpop('names'))  # b'kiku'
  • lindex(name,index):在name对应的列表中根据索引获取列表中的元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lindex('names', 0))  # b'kiku'
print(conn.lindex('names', 1))  # b'thanlon'
  • lrange(name,start,end):在name对应的列表分片获取数据。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
  • ltrim(name,start,end):在name对应的列表中移除没有在start~end索引之间的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john', b'Tom']
conn.ltrim('names', 0, 1)  # 0~1
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku']
  • rpoplpush(src,dst):从一个列表取出最右边的元素,同时将其添加至另外一个列表的最左边,src是要取数据的列表的name,dst是要添加数据列表name。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('developers', 'Thanlon')
conn.lpush('developers', 'Kiku')
conn.lpush('masters', 'John')
conn.lpush('masters', 'Maria')
print(conn.lrange('developers', 0, -1))  # [b'Kiku', b'Thanlon']
print(conn.lrange('masters', 0, -1))  # [ b'Maria', b'John']
conn.rpoplpush('developers', 'masters')  # 将developers列表中的最右边元素添加到masters列表中元素的最左边
print(conn.lrange('developers', 0, -1))  # [b'Kiku']
print(conn.lrange('masters', 0, -1))  # [b'Thanlon', b'Maria', b'John']
  • blpop(keys,timeout):将多个值进行排列,按照从左到右去pop对应列表的元素。timeout是超时时间,当元素所有列表的数据获取完后,阻塞等待列表内有数据的时间(秒),0表示永远阻塞。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('names', 'Thanlon')
conn.lpush('names', 'Kiku')
conn.lpush('names', 'John')
conn.lpush('names', 'Maria')
print(conn.lrange('names', 0, -1))  # [b'Maria', b'John', b'Kiku', b'Thanlon']
print(conn.blpop('names'))  # (b'names', b'Maria')
print(conn.lrange('names', 0, -1))  # [b'John', b'Kiku', b'Thanlon']
print(conn.blpop('names'))  # (b'names', b'John')
print(conn.lrange('names', 0, -1))  # [b'Kiku', b'Thanlon']
  • brpoplpush(src,dst,timeout=0):从一个列表取出最右边的元素,同时将其添加至另外一个列表的最左边。前面有介绍rpoplpush方法,这里只是可以添加超时时间。
  • 自定义增量迭代:**由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,就需要获取name对应的列表,然后循环列表。但是如果列表非常大,就有可能在获取name对应的列表时撑爆内存,所以,有必要自定义增量迭代功能。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)

def list_iter(name):
    list_count = conn.llen(name)
    for index in range(0, list_count):
        yield conn.lindex(name, index)

for item in list_iter('names'):
    print(item)
# b'Kiku'
# b'Thanlon'

④ Set操作:Set集合不允许重复的列表

  • sadd(name,values):对name对应的集合添加元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.sadd('employees', 'thanlon')
conn.sadd('employees', 'kiku')
  • scard(name):获取name对应集合中的元素个数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.scard('employees'))
  • sadiff(keys,*args):在第一个name对应的集合中且不在其它name对应的集合中的元素集合
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# employees:kiku,thanlon
# bosses:Tom,John
print(conn.sdiff('employees', 'bosses'))  # {b'kiku', b'thanlon'}
  • sdiffstore(dest,keys,*args):获取在第一个name对应的集合中且不在其它name对应的集合中的元素集合,再将其新加入到dest对应的集合中。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# employees:kiku,thanlon
# bosses:Tom,John
print(conn.sdiffstore('dest', 'employees', 'bosses'))  # dest:{b'kiku', b'thanlon'}
  • sinter(keys,*args):获取多个name对应集合的交集。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
print(conn.sinter('employees', 'bosses'))  # {b'Tom'}
  • sinterstore(dest,keys,*args):获取多一个name对应集合的交集,再将其加入到dest对应的集合中
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
conn.sinterstore('dest', 'employees', 'bosses')
print(conn.smembers('dest'))  # {b'Tom'}
  • sismember(name,value):检查value是否是name对应的集合成员。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'thanlon', b'kiku'}
print(conn.sismember('employees', 'thanlon'))  # True
  • smembers(name):获取name对应集合的所有成员。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'kiku', b'thanlon'}
  • smove(src,dst,value):把某一个成员从一个集合(src)中移到另外一个集合(dst)中。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Thanlon', b'Kiku'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
conn.smove('employees', 'bosses', 'Thanlon')
print(conn.smembers('employees'))  # {b'Thanlon', b'Kiku'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
  • spop(name):从集合的右侧(尾部)移除一个成员,并将其返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
print(conn.spop('bosses'))  # b'Thanlon'
print(conn.smembers('bosses'))  # {b'Tom', b'John'}
  • srandmember(name,number):从name对应的集合中随机获取numbers个元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# 如果nmber没有指定则默认是1
print(conn.srandmember('employees'))  # b'Kiku'
print(conn.srandmember('employees', number=2))  # [b'Kiku', b'Tom']
  • srem(name,values):在name 对应的集合中删除某些值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
conn.srem('employees', 'Kiku')
print(conn.smembers('employees'))  # {b'Tom'}
  • sunion(keys,*args):获取多个name对应集合的并集
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
print(conn.sunion('employees', 'bosses'))  # {b'Kiku', b'John', b'Tom'}
  • sunionstore(dest,keys,*args):获取多个name对应集合的并集,并将结果保存到dest对应的集合中
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
print(conn.sunionstore('dest', 'employees', 'bosses'))
print(conn.smembers('dest'))  # {b'Kiku', b'John', b'Tom'}
  • sscan(name,cursor=0,match=None,count=None):同字符串操作,用于迭代分批获取数据,避免内存消耗太大。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# 第一次:
cursor1, data1 = conn.sscan('employees', cursor=0, match=None, count=1)
print(data1)  # [b'Thanlon']
# 第二次:
cursor2, data2 = conn.sscan('employees', cursor=cursor1, match=None, count=2)
print(data2)  # [b'John', b'Kiku', b'Tom', b'Maria']
  • sscan_iter(name,match=None,count=None):同字符串操作,用于迭代分批获取数据,避免内存消耗太大
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
for item in conn.sscan_iter('employees', match=None, count=None):
    print(item)
# b'Thanlon'
# b'John'
# b'Kiku'
# b'Tom'
# b'Maria'

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

  • zdd(name,mapping,nx,xx,ch,incr):在name对应的有序集合中添加元素(有两种方式)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('zset1', {'thanlon': 1, 'kiku': 2, 'Tom': 0})
  • zcard(name):获取name对应的有序集合元素的数量
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
print(conn.zcard('zset1'))  # 3
  • zcount(name,min,max):获取name对应的有序集合中分数在[min,max]之间的数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
print(conn.zcount('zset1', 0, 1))  # 2
  • zincrby(name,amount,value):自增name对应的有序集合的name对应的分数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
conn.zincrby('zset1', 10, 'thanlon')
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'kiku', b'thanlon']
  • zrange(name,start,end,desc=False,withscores=False,score_cast_func=float):按照索引获取name对应的有序集合的元素。参数:start是有序集合索引起始位置;end是有序集合索引结束位置 ;desc是排序规则,默认按照从小到大排序;withscores是是否获取元素的分数,默认是获取元素的值;score_cast_func是对分数进行数据转换的函数。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('name', {'Thanlon': 1, 'Kiku': 2, 'Tom': 0, 'Maria': -2})
print(conn.zrange('name', 0, 0))  # [b'Maria']
print(conn.zrange('name', 0, 0, desc=True))  # [b'Kiku']
print(conn.zrange('name', 0, 1))  # [b'Maria', b'Tom'], 0, 1只决定取的数量,不表示分数范围
  • zrank(name,value):获取值在name对应的有序集合中的排行(从0开始)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('name', {'Thanlon': 1, 'Kiku': 2, 'Tom': 0, 'Maria': -2})
print(conn.zrange('name', 0, -1))  # [b'Maria', b'Tom', b'Thanlon', b'Kiku']
print(conn.zrank('name', 'Thanlon'))  # 2,表示排第三位(是从0开始的)
  • zrangebylex(self, name, min, max, start=None, num=None):当有序集合的所有成员都具有相同的分数,有序集合的元素会根据成员的值来进行排序。对集合中的每个成员进行逐个字节的对比,并按照从低到高的顺序,返回排序后的集合成员。min是左区间,+和-分别表示正无限和负无限,(或者表示开区间,[表示 闭区间;max是右区间的值;start是对结果进行分片处理的索引位置,num是对结果进行分片处理,索引后面有num个元素。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100}) 
#  # 字节转换成数字来一个一个比较
print(conn.zrange('students', 0, -1)) # [b'Kiku', b'Maria', b'Thanlon']
ret = conn.zrangebylex('students', '-', '[Maria') # [b'Kiku', b'Maria']
ret2 = conn.zrangebylex('students', '-', '(Maria')# [b'Kiku']
print(ret)
print(ret2)
  • zrem(self, name, *values):删除name对应的有序集合值是value的成员
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
conn.zrem('students', 'Thanlon')  # 删除name对应有序集合中的Thanlon
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria']
  • zremrangebyrank(name,min,max):根据排行来删除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 0, 'Kiku': 1, 'Maria': 2})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
conn.zremrangebyrank('students', 0, 1)  # 删除排名在第一名到第二名
print(conn.zrange('students', 0, -1))  # [b'Maria']
  • zremrangebyscore(name, min, max):根据分数范围删除有序集合中的元素加
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
# 根据分数来删除有序集合里面的值,这里删除的是分数在0~59之间的,只有Thanlon是满足加的,所以删除它
conn.zremrangebyscore('students', 0, 59)
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria']
  • zremrangebylex(name, min, max):根据指定的范围的值删除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100})
#  # 字节转换成数字来一个一个比较
print(conn.zrange('students', 0, -1, withscores=True))  # [(b'Kiku', 100.0), (b'Maria', 100.0), (b'Thanlon', 100.0)]
conn.zremrangebylex('students', '-', '[Maria')
print(conn.zrange('students', 0, -1, withscores=True))  # [(b'Thanlon', 100.0)]
  • zscore(name, value):根据name对应有序集合中的value对应的分数
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zscore('students', 'Maria'))  # 100.0
  • zinterstore(self, dest, keys, aggregate=None):获取两个有序集合的交集,如果遇到相同的值不同的分数,则按照aggregate进行操作,aggregate的值有SUM 、MIN和MAX,默认是SUM。使用小写sum也对,不区分大小。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('bosses', 0, -1, withscores=True))  # [(b'Jack', 1.0), (b'Thanlon', 4.0)]
print(conn.zrange('employees', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 2.0)]
conn.zinterstore('dest', ['bosses', 'employees'])
print(conn.zrange('dest', 0, -1, withscores=True))  # [(b'Jack', 3.0)]
  • zunionstore( dest, keys, aggregate=None):获取两个有序集合的并集,如果遇到相同的值不同的分数,则按照aggregate进行操作,aggregate的值有SUM 、MIN和MAX
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('bosses', 0, -1, withscores=True))  # [(b'Jack', 1.0), (b'Thanlon', 4.0)]
print(conn.zrange('employees', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 2.0)]
conn.zunionstore('dest', ['bosses', 'employees'])
print(conn.zrange('dest', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 3.0), (b'Thanlon', 4.0)]
  • zscan(name, cursor=0, match=None, count=None,score_cast_func=float):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
cursor1, data1 = conn.zscan('students', cursor=0, match=None, count=None, score_cast_func=float)
print(data1)  # [(b'Thanlon', 59.0), (b'Kiku', 100.0), (b'Maria', 100.0)]
  • scan_iter(name, match=None, count=None,score_cast_func=float):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
for item in conn.zscan_iter('students', score_cast_func=float):
    print(item)
# (b'Thanlon', 59.0)
# (b'Kiku', 100.0)
# (b'Maria', 100.0)

⑥ 其它常用操作

  • delete(*names):删除redis任意一种数据类型
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.delete('teachers')
  • exists(*names):检查redis中的name是否存在
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.exists('students'))  # 1表示存在
  • keys(pattern=’*’):默认是所有的keys
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'bosses', b'dest_tmp', b'students']
print(conn.keys('bo?ses'))  # [b'bosses']
print(conn.keys('b*s'))  # [b'bosses']
print(conn.keys('b[ao]sses'))  # [b'bosses'],要么匹配bosses,否则匹配basses
  • expire(name, time):为某个redis的name设置超时时间,redis中设置超时时间的粒度比较小,只能对name对应的数据的整体做超时时间。比如,hash中一个name对应多个key-value,我们只能对这多个key-value整体设置超时时间,不可以对key-value做超时时间。
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.expire('students', time=100)  # 超时时间必须是integer类型的
  • rename(src, dst):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'employees', b'dest_tmp']
conn.rename('employees', 'bosses')
print(conn.keys())  # [b'bosses', b'dest_tmp']
  • move(name, db):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'bosses', b'dest_tmp']
conn.move('bosses', 15)
print(conn.keys())  # [b'dest_tmp']
  • randomkey():随机获取redis中的name
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.randomkey())#b'dest_tmp'
  • type(name):获取redis中name的数据类型
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.type('dest_tmp'))  # b'set'
  • scan(cursor=0, match=None, count=None):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.scan())  # (0, [b'dest_tmp'])
  • scan_iter(match=None, count=None):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
for item in conn.scan_iter():
    print(item)
# b'dest_tmp'
6. 管道

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

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pipe = conn.pipeline(transaction=True)
pipe.set('name', 'thanlon')
pipe.set('name', 'kiku')
pipe.execute()  # 整体提交,如果一条发生错误,整个就不会生效
7. Redis发布和订阅

发布者:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.publish('news', 'Pay Attention To!')

接收者1:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pb = conn.pubsub()
pb.subscribe('news')
while True:
    print(pb.parse_response()) # [b'message', b'news', b'Pay Attention To!']

接收者2:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pb = conn.pubsub()
pb.subscribe('news')
while True:
    print(pb.parse_response()) # [b'message', b'news', b'Pay Attention To!']
8. Redis面试题
  • redis和memcached的比较:redis不仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;memcached不支持主从,redis支持主从,可用于数据的备份,即master-slave模式的数据备份;Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  • redis中数据库默认有多少个数据库及作用:16个数据库;所有数据库保存到结构 redisServer 的一个成员 redisServer.db 数组中。当我们选择数据库 select number 时,程序直接通过 redisServer.db[number] 来切换数据库。有时候当程序需要知道自己是在哪个数据库时,直接读取 redisDb.id 即可。
  • python如何操作redis模块:安装redis模块(或库),然后使用redis模块与redis服务端创建连接之后,进行一系列redis的操作
  • 如何循环显示redis中某个列表比较大的数据量的每一个值:可以尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的io影响
  • redis如何实现主从复制和数据同步机制:在从redis数据库(slave)配置文件中添加replicaof参数用于绑定主库(master)的ip和端口;在slave启动时,会向其master发送一条SYNC消息,master收到slave的这条消息之后,将可能启动后台进程进行备份,备份完成之后就将备份的数据发送给slave。
  • redis中的sentinel的作用:sentinel是一个独立运行的进程,用于监控master-slave集群,一旦发现master宕机,会进行自动切换到slave。[用于监控redis集群中Master状态的工具]
  • 如何实现redis集群:采用主从模式,通过增加slave来增加并发读的能力,master的写能力是个瓶颈;还有hash slot的模式,将Redis的写操作分摊到了多个节点上,提高写的并发能力,扩容简单。
  • redis中默认有多少个哈希槽:16384个哈希槽
  • 简述redis的有哪几种持久化策略及比较:redis有RDB和AOF两种持久化策略,RDF相当于快照,保存数据块,还原数据快,适合灾难恢复。但是RDB只要符合要求就会照快照,会占用一部分系统资源,适用于内存比充足的机器。AOF是持续化占用极少的内存资源,采用日志记录redis操作。但是日志文件会特别大,不适用于灾难恢复,恢复效率远远低于RDB。适用于内存较小的机器。[简单回答:RDF是快照形式的,直接把内存中的数据保存到一个dump文件中;AOF是把所有的对redis的服务器进行修改的命令都存到一个文件里]
  • 列举redis支持的过期策略:定期删除和惰性删除策略,定期删除指的是每隔一定时间就抽取一些设置了过期时间的key,检查是否过期,如果过期了就把删除。惰性策略是在获取key的时候,如果此时的key已经过期,就会直接删除,不会返回任何东西。当然,内存中这还会存大量过期的的key,我们还可以使用内存淘汰机制。
  • 列举内存淘汰机制
volatile-lru 				从已设置过期时间的数据集中挑选最近最少使用的数据淘汰(默认)
volatile-ttl					从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random 		从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru					从数据集中挑选最近最少使用的数据淘汰(最常用的)
allkeys-random		从数据集中任意选择数据淘汰
no-enviction				禁止驱逐数据
  • mysql里有两千万数据,redis中只存二十万的数据,如何保证 Redis 中都是热点数据:redis 内存数据集大小上升到一定大小的时候,就会实施数据淘汰策略。可参考上一题理解着回答。
  • 写代码,基于redis的列表实现先进先出、后进先出队列和优先级队列
# 先进先出
import redis
'''
可以使用lpush和rpop或rpush和lpop
'''
pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('employees', 'thanlon')
conn.lpush('employees', 'kiku')
conn.lpush('employees', 'maria')
conn.lpush('employees', 'jack')
conn.lpush('employees', 'michael')
conn.lpush('employees', 'angle')
print(conn.lrange('employees', 0, -1))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
'''
[b'angle', b'michael', b'jack', b'maria', b'kiku', b'thanlon']
b'thanlon'
b'kiku'
b'maria'
b'jack'
b'michael'
b'angle'
'''
# 后进先出
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('employees', 'thanlon')
conn.lpush('employees', 'kiku')
conn.lpush('employees', 'maria')
conn.lpush('employees', 'jack')
conn.lpush('employees', 'michael')
conn.lpush('employees', 'angle')
print(conn.lrange('employees', 0, -1))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
'''
[b'angle', b'michael', b'jack', b'maria', b'kiku', b'thanlon']
b'angle'
b'michael'
b'jack'
b'maria'
b'kiku'
b'thanlon'
'''
# 优先级队列,采用任务入队的时候设置权值
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
'''
只执行一次添加元素
'''
# conn.lpush('bosses', 'thanlon')
# conn.set('bosses_score_thanlon', 2)
# conn.lpush('bosses', 'kiku')
# conn.set('bosses_score_kiku', 3)
# conn.lpush('bosses', 'tom')
# conn.set('bosses_score_tom', -1)

# 原来的队列
print(conn.lrange('bosses', 0, -1))  # [b'tom', b'kiku', b'thanlon']
# 排序后的任务队列
print(conn.sort('bosses', by='bosses_score_*'))  # [b'tom', b'thanlon', b'kiku']
# 取出优先级最高的任务
high_work = conn.sort('bosses', start=0, num=1, by='bosses_score_*', desc=True)
print(high_work)  # [b'kiku']
# 移除这个任务
conn.lrem('bosses', 0, high_work[0].decode('utf-8'))
'''
# 第一次
[b'tom', b'kiku', b'thanlon']
[b'tom', b'thanlon', b'kiku']
[b'kiku']第一优先级任务
# 第二次
[b'tom', b'thanlon']
[b'tom', b'thanlon']
[b'thanlon']第二优先级任务
[b'tom']
[b'tom']
[b'tom']第三优先级任务
'''
  • 如何基于redis实现消息队列:使用lpush向list的左端推送数据(发送消息),使用rpop从list的右端接收数据(接收消息)。
  • 如何基于redis实现发布和订阅:使用publish来发布消息,使用subscribe来接收订阅,获取订阅消息。
  • 消息队列和发布订阅的区别:“发布/订阅”模式包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。【 区别一:前者通过key队列方式实现,取出就删掉了,其他进程也取不到,阻塞进程。订阅发布可以支持多客户端获取同一个频道发布的消息。区别二:前者消息不处理会缓存在列表,后者不处理的话消息就丢失了。】
  • 什么是codis及其作用:codis是一个分布式redis解决方案,可以用于redis的扩容、支持在线数据迁移,可以自动进行数据分配。codis比较适合那种数据库比较大,但并发量不是特别高的系统。
  • 什么是twemproxy及其作用:twemproxy是一种代理分片机制,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis服务器,再原路返回。可以解决了单个Redis实例承载能力的问题,可用来扩张redis,Twemproxy需要更多的硬件资源和在redis性能有一定的损失(twitter测试约20%),但是能够提高整个系统的高可用(HA)也还是不错的。回答的时候说类似于nginx,是一种代理的存在。[twemproxy是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量。]
  • 写代码实现redis事务操作
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pipe = conn.pipeline(transaction=True)
pipe.set('name', 'thanlon')
pipe.set('age', 23)
pipe.execute()
  • redis中的watch命令的作用:watch( watch key[key...])命令用于在进行事务操作的最后一步(也就是在执行exec 之前)对某个key进行监视。如果这个被监视的key被改动,那么事务就被取消,否则事务正常执行。一般在mulit 命令前就用watch命令对某个key进行监控,如果想让key取消被监控,可以用unwatch命令。【当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的】
  • 基于redis如何实现商城商品数量计数器:使用redis的Incr自增和desr自减命令可以实现商城商品数量计数器。
  • 简述redis分布式锁redlock的实现机制:互斥,任何时刻只能有一个client获取锁。释放死锁,即使锁定资源的服务崩溃或者分区,仍然能释放锁。容错性,只要多数redis节点(一半以上)在使用,client就可以获取和释放锁。
  • 什么是一致性哈希,Python中是否有相应模块:一致性哈希简而言之就是不仅仅数据做哈希,机器也做哈希;python中有相应的模块,即:hashlib模块。
  • 如何高效的找到redis中所有以某某开头的key:使用keys命令的话,如果数据量比较大,可能会卡顿,不适用于生产环境,应该使用基于游标的迭代器来做。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章