Redis
Redis 是一种 NoSQL 数据库,它的数据默认是存储在内存中的,同时 Redis 可以定时将内存中的数据同步到硬盘中。Redis 比 Memcached 支持更多的数据结构,除了 bool、int、float、string 基本数据类型,还支持 list(列表)、set(集合)、sorted set(有序集合)、hash(hash表)。
Redis使用场景
Redis 的使用场景非常多,包括但不限于以下场景。
-
登录会话存储:可以把能识别客户端的数据存储在 Redis 中,如 token、session 等。
-
在线人数/计数器:如现在非常火的直播的实时变动的在线人数、新浪微博的点赞数等,为了提高响应速度,都可以把数据存储在 Redis 中。
-
作为消息队列:如在使用 Celery 实现异步操作时,Redis 可以作为中间人。 常用的数据缓存:可以把一些网站中经常会用到的数据放到 Redis 中,以提高加载速度。
-
首页数据缓存:一个网站的首页访问频率是最高的,可以把首页中部分的数据放到 Redis 中。
-
好友关系:如微博的好友关系极其复杂,如果每次获取好友关系时都要查找数据库,那么响应速度将慢到无法忍受。这时就可以把好友关系存储到 Redis 中。
-
发布和订阅功能:Redis 有发布和订阅功能,可以用来做聊天软件。
Redis和Memcached比较
Memcached 和 Redis 都是非常优秀的缓存系统。Memcached 的优点是轻量级和占用服务器资源少,缺点是功能少。而 Redis 的优点是功能更强大,配置项比 Memcached 更多一些,缺点是对服务器的要求比较高。Memcached 和 Redis 的比较如表 8-1 所示。

Redis在Ubuntu中的安装与使用
Redis 是没有 Windows 平台的官方支持版本的,如果要在生产环境中使用 Redis,建议在生产环境上使用 Linux 系统。作为学习,可以使用非官方发布的 Windows 版本的 Redis。下面分别讲解在 Windows 和 Linux 系统上安装和使用 Redis。
在 windows 系统上安装和使用 Redis
-
下载链接: https://github.com/tporadowski/redis/releases ,下载 msi 文件即可。
-
安装步骤:首先双击 msi 文件,在打开的 Redis on Windows Setup 对话框中选择安装路径并选中 Add the Redis installation folder to the PATH environment variable 复选框,然后单击 Next 按钮,如图 8-3 所示。

进入设置端口号和防火墙的界面,Redis 默认端口号是 6379,然后再把 Redis 服务的防火墙关掉(如果不关掉防火墙,会导致其他计算机无法访问本机 Redis 服务),如图 8-4 所示。
再次单击 Next 按钮,会出现设置允许 Redis 占用最大内存的界面,默认是无限,这个对于我们只是用于学习来讲影响不大,可设可不设。接着单击 Next 按钮,然后单击 Install 按钮,稍等片刻即可完成安装。
-
使用:打开 cmd 命令行终端,然后执行 redis-cli 命令,即可进入 Redis 命令行,然后按照 8.2.4 节中的命令操作 Redis 即可。
在 Linux 系统上安装 Redis
在 Linux 系统的版本中,Ubuntu 版简单易用且长期支持。这里以 Ubuntu 系统为例进行讲解。

-
安装命令:apt install redis-server。
-
卸载命令:apt purge --auto-remove redis-server。
-
启动命令:Redis 安装完成后会自动启动,可以通过 ps aux|grep redis 命令进行查看。如果想手动启动,可以通过 service redis-server start 命令启动。
-
停止命令:service redis-server stop。
-
使用:在连接 redis-server 之前,要先启动 redis-server 服务,命令为 service redis-server start。启动 redis-server 后,再使用 redis-cli 命令进行连接,语法如下。
redis-cli -h [ip] -p [端口]
redis-server 默认的端口号是 6379,连接本机的 redis-server 命令如下。
redis-cli -h 127.0.0.1 -p 6379
在连接到 redis-server 后,就可以使用 8.2.4 节中的命令对 redis-server 进行操作了。
Redis操作命令
Redis 操作命令在 Windows 和 Linux 系统中都是一样的,相关命令介绍如下。
添加数据
添加数据使用 set 命令,语法如下。
set key value EX timeout
如果 key 之前已经存在,则会进行覆盖。EX 参数设置的是过期时间,如果没有 EX 参数,则意味着数据永远不会过期,示例命令如下。
set username zhiliao EX 60
或
set username zhiliao
或者可以在使用 setex 命令添加数据时就设置过期时间,示例命令如下。
setex username 60 zhiliao
列表操作
在列表左边添加元素,语法如下。
lpush key value
将 value 插入 key 所指向的列表的最开始位置。如果 key 不存在,则会创建一个空的列表,并且执行 lpush 操作。当 key 存在但不是列表类型时,将会返回一个错误。
在列表右边添加元素,语法如下。
rpush key value
将 value 插入列表 key 的末尾。如果 key 不存在,则会创建一个空的列表,并且执行 rpush 操作。当 key 存在但不是列表类型时,将会返回一个错误。
查看列表中的元素,语法如下。
lrange key start stop
返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定,如果要左边的第 1 个元素到最后一个元素,则语法如下。
lrange key 0 -1
移除列表左边的元素,语法如下。
lpop key
移除并返回列表右边的元素,语法如下。
rpop key
移除并返回列表中指定的元素,语法如下。
lrem key count value
以上命令将删除列表 key 中 count 个值为 value 的元素。
获取列表中指定位置的元素,语法如下。
lindex key index
以上命令将获取列表 key 中索引为 index 的元素。
获取列表中元素个数,语法如下。
llen key
删除指定元素,语法如下。
lrem key count value
以上命令将删除列表 key 中 count 个值为 value 的元素。如果 count>0,则从左向右搜索,移除与 value 相等的元素,数量为 count。如果 count<0,则从右向左搜索,移除与 value 相等的元素,数量为 count 的绝对值。如果 count=0,则移除列表中所有与 value 相等的值。
集合操作
集合是无序的,并且里面的元素不能重复。下面来讲解集合的操作命令。 添加元素,语法如下。
sadd key value1 value2…
通过sadd命令可以一次性添加多个元素。 查看元素,语法如下。
smembers key
移除元素,语法如下。
srem key value1 value2
通过srem命令可以一次性删除多个元素。 查看集合中元素个数,语法如下。
scard key
获取多个集合的交集,语法如下。
sinter key1 key2…
获取多个集合的差集,语法如下。
sdiff key1 key2…
哈希(hash)操作
哈希(hash)可以简单理解为 Python 中的字典,操作 hash 的相关命令如下。
添加新值,语法如下。
hset key field value
示例命令如下。
hset website baidu baidu.com
以上示例命令中,如果website这个key不存在,则会在redis-server中创建一张名为website的哈希表。 获取哈希表中field的值,语法如下。
hget key field
如果field已经在哈希表中存在,旧值将会被覆盖。示例命令如下。
hget website baidu
删除某个field,语法如下。
hdel key field
获取某张哈希表中所有的field,语法如下。
hkeys key
获取某张哈希表中所有的field和value,语法如下。
hgetall key
获取某张哈希表中所有的值,语法如下。
hvals key
判断哈希表中是否存在某个field,语法如下。
hexists key field
事务操作
Redis 事务可以一次性执行多个命令,具有隔离性和原子性。隔离性意味着在事务中执行的所有命令都会按顺序执行,不会被其他命令干扰。原子性意味着在事务中的命令,要么全部都执行,要么全部都不执行。下面来学习事务的相关命令。
开启一个事务,语法如下。
multi
执行以上命令后,接下来的所有命令都将在这个事务中执行。 执行事务,语法如下。
exec
exec命令会将multi和exec中的操作一并提交。 取消事务,语法如下。
discard
discard命令会将multi和discard中的操作全部取消。 监视key,语法如下。
watch key1 key2…
以上命令监视一个或者多个key,如果在事务执行之前,这些key被其他命令修改了,那么事务将中断执行。 取消所有key的监视,语法如下。
unwatch
同步数据到硬盘
Redis可以通过配置实现自动同步数据到硬盘。同步的策略有两种:第一种是RDB(Redisdatabase),第二种是AOF(append only file),可以通过修改/etc/redis/redis.conf配置文件切换不同的同步策略。下面分别来讲解这两种策略的相关配置及其优缺点。
RDB策略
RDB策略的相关配置内容如下。
-
开启和关闭:RDB默认是开启模式的,如果想要关闭,则把配置文件中所有的save配置项都注释就可以关闭了。
-
同步机制:可以指定某个时间内执行多少个命令进行同步。如1min内执行了两次命令,就做一次同步。
-
存储内容:存储的是Redis里面具体的值。
-
存储文件路径:根据dir和dbfilename配置项来指定路径和具体的文件名。
RDB策略的优点如下。
-
存储数据到文件中会进行压缩,文件体积比使用AOF策略小。
-
因为存储的是Redis中具体的值,所以在恢复的时候速度比使用AOF策略快。
-
非常适合用于备份。
RDB策略的缺点如下。
-
RDB配置规则为多少时间内执行了多少条命令才进行同步数据,因为采用压缩机制,RDB在同步的时候要重新保存整个Redis中的数据,因此一般我们最少会设置5min以上才进行一次同步。在这种情况下,一旦服务器发生故障,就会造成5min的数据丢失。
-
在进行数据同步时,Redis会调用fork函数生成一个子进程来同步数据,在数据量比较大的情况下,会非常耗时。
AOF策略
AOF策略的相关配置内容如下。
-
开启和关闭:在/etc/redis/redis.conf配置文件中设置appendonly为yes,即可开启AOF,设置为no则可关闭AOF。
-
同步机制:每秒同步或者每次执行命令后同步数据。
-
存储内容:存储的不是真实的数据,而是每次执行的命令。
-
存储文件路径:根据dir以及appendfilename来指定具体的路径和文件名。
AOF策略有如下优点。
-
AOF策略是每秒或者每次发生写操作时都会同步数据,因此即使服务器发生故障,最多只会损失1s的数据。
-
AOF存储的是Redis命令,并且直接把新增的命令追加到AOF文件后面,因此备份的效率比使用RDB策略高。
-
如果AOF文件比较大,那么Redis会自动进行重写,只保留最小的命令集合。
AOF策略有如下缺点。
-
AOF文件因为没有压缩,因此体积比使用RDB策略大。
-
AOF是在每秒或者每次执行命令时都进行备份,因此如果并发量比较高,则效率会比较慢。
-
因为AOF备份的是命令,因此在灾难恢复时Redis会重新执行AOF中的命令,速度不及使用RDB策略。
设置密码
默认情况下,连接Redis是不需要密码的,这存在风险。我们可以通过配置/etc/redis/redis.conf文件中的requirepass实现加密访问,配置示例如下。
requirepass zhiliao
上述配置中,将密码设置为zhiliao,重启redis-server后通过redis-cli重新连接redis-server,然后使用命令auth password命令授权,示例命令如下。
auth zhiliao
只有成功授权后,才可以执行操作Redis的命令。
Python操作Redis
因为Redis是装在Linux系统上的,而我们经常会在Windows系统上编程,因此如果想要在其他机器上连接Redis,则必须先在/etc/redis/redis.conf文件中设置允许其他机器通过本机的IP地址连接。设置的配置项为bind,示例如下。
bind 0.0.0.0
通过以上配置,其他机器都可以通过redis-server所在机器的IP地址或域名进行连接了。
使用Python操作Redis,还需要通过一个第三方包python-redis,安装命令如下。
pip install redis
安装完python-redis后,就可以用Python来操作Redis了,相关操作方法如下。
连接Redis
假设 Redis 所在机器的 IP 地址为 192.168.174.130,并且监听默认的 6379 端口号,那么使用以下代码即可实现连接 Redis。
# 从 redis 包中导入 Redis 类
from redis import Redis
# 初始化 Redis 实例
xtredis = Redis(host='192.168.174.130', port=6379)
字符串操作
字符串操作示例代码如下。
# 添加一个值进去,并且设置过期时间为 60s,如果不设置,则永远不会过期
xtredis.set('username', 'xiaotuo', ex=60)
# 获取一个值
print(xtredis.get('username'))
# 删除一个值
xtredis.delete('username')
列表操作
列表操作示例代码如下。
# 给 languages 列表往左边添加一个 python
xtredis.lpush('languages', 'python')
# 给 languages 列表往左边添加一个 php
xtredis.lpush('languages', 'php')
# 给 languages 列表往左边添加一个 javascript
xtredis.lpush('languages', 'javascript')
# 获取 languages 列表中的所有值
print(xtredis.lrange('languages', 0, -1))
集合操作
字符串操作示例代码如下。
# 给集合 team 添加一个元素 xiaotuo
xtredis.sadd('team', 'xiaotuo')
# 给集合 team 添加一个元素 datuo
xtredis.sadd('team', 'datuo')
# 给集合 team 添加一个元素 slice
xtredis.sadd('team', 'slice')
# 获取集合中的所有元素
print(xtredis.smembers('team')) # 输出: {'datuo', 'xiaotuo', 'slice'},无序的