redis入门——服务器篇
@(Redis)[服务器, 配置文件, 发布订阅, 事务]
- redis入门服务器篇
- redis服务器配置文件
- redis服务器基本命令
- redis服务器的持久化
- RDB持久化
- AOF持久化
- redis服务器的发布与订阅
- redis服务器的事务
- redis事务的几个命令
- 使用方法
- 简单的开启事务和提交事务
- 事务错误的解决办法
- 放弃事务
- 使用watch命令实现乐观锁
redis服务器配置文件
在redis服务器启动时,可以指定配置文件,官方已经提供好了默认的配置文件了,文件名为redis.conf
,可以在Redis的安装目录中找到。在启动服务器时,指定对应的配置文件就能运行了。例如使用redis-server redis.conf
就能加载对应配置文件了。
redis服务器基本命令
- 测试与服务器的连接是否仍然生效
ping
127.0.0.1:6401> ping
PONG
127.0.0.1:6401>
- 打印一个特定的信息 message
ECHO message
127.0.0.1:6401> echo "Switch"
"Switch"
127.0.0.1:6401> echo "Kity"
"Kity"
127.0.0.1:6401> echo "Switch Kity"
"Switch Kity"
127.0.0.1:6401>
- 请求服务器关闭与当前客户端的连接
QUIT
EXIT
127.0.0.1:6401> quit
[root@iZ28xuvyce3Z bin]# redis-cli -p 6401
127.0.0.1:6401> exit
[root@iZ28xuvyce3Z bin]#
- 切换到指定的数据库
SELECT index
127.0.0.1:6401> select 0
OK
127.0.0.1:6401> select 1
OK
127.0.0.1:6401[1]> select 2
OK
127.0.0.1:6401[2]> select 15
OK
127.0.0.1:6401[15]> select 16
(error) ERR invalid DB index
127.0.0.1:6401> select 99
(error) ERR invalid DB index
127.0.0.1:6401> select 0
OK
127.0.0.1:6401>
PS:redis
默认配置了16个数据库,编号为[0~15]
。可以在配置文件中配置databases number
,这表示该redis
服务器一共有number
个数据库。
- 返回当前数据库的 key 的数量
DBSIZE
127.0.0.1:6401> keys *
1) "bit"
2) "customer:3"
3) "sname4"
4) "names"
5) "customer:2"
6) "zname"
7) "name"
8) "customer:1"
9) "names2"
10) "sname2"
11) "sname"
12) "age"
127.0.0.1:6401> dbsize
(integer) 12
127.0.0.1:6401> select 1
OK
127.0.0.1:6401[1]> keys *
(empty list or set)
127.0.0.1:6401[1]> dbsize
(integer) 0
127.0.0.1:6401[1]> select 0
OK
127.0.0.1:6401>
- 获取服务器的信息和统计
INFO [section]
127.0.0.1:6401> info
# Server
redis_version:3.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:8333461cdd6cf033
redis_mode:standalone
os:Linux 3.10.0-123.9.3.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:19391
run_id:232fab68ad28a2e529438d3768505cd0e8ac2ea9
tcp_port:6401
uptime_in_seconds:16695
uptime_in_days:0
hz:10
lru_clock:4460082
config_file:/usr/local/redis/bin/redis.conf
# Clients
connected_clients:1
......
......
info可以获取指定select的信息,有如下几个select:
server 记录了 Redis 服务器的信息
Select | 解释 |
server | 记录了 Redis 服务器的信息 |
clients | 记录了已连接客户端的信息 |
memory | 记录了服务器的内存信息 |
persistence | 记录了跟 RDB 持久化和 AOF 持久化有关的信息 |
stats | 记录了一般统计信息 |
replication | 主/从复制信息 |
cpu | 记录了 CPU 的计算量统计信息 |
commandstats | 记录了各种不同类型的命令的执行统计信息 |
cluster | 记录了和集群有关的信息 |
keyspace | 记录了数据库相关的统计信息 |
all | 返回所有信息 |
default | 返回默认选择的信息 |
- 清空当前数据库中的所有 key
- FLUSHDB
127.0.0.1:6401> select 1
OK
127.0.0.1:6401[1]> set name "Switch"
OK
127.0.0.1:6401[1]> dbsize
(integer) 1
127.0.0.1:6401[1]> flushdb
OK
127.0.0.1:6401[1]> dbsize
(integer) 0
127.0.0.1:6401[1]> select 0
OK
127.0.0.1:6401>
- 清空整个 Redis 服务器的数据
FLUSHALL
127.0.0.1:6401> dbsize
(integer) 12
127.0.0.1:6401> select 1
OK
127.0.0.1:6401[1]> set name "Switch"
OK
127.0.0.1:6401[1]> dbsize
(integer) 1
127.0.0.1:6401[1]> flushall
OK
127.0.0.1:6401[1]> dbsize
(integer) 0
127.0.0.1:6401[1]> select 0
OK
127.0.0.1:6401> dbsize
(integer) 0
127.0.0.1:6401>
PS:请谨慎使用flushall
和flushdb
命令,因为一旦使用这两个命令,前者会将redis
服务器中所有数据库的数据都清空,后者会将当前数据库的数据清空。
redis服务器的持久化
Redis 提供了多种不同级别的持久化方式:
- RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
- AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。
- Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。
- 你甚至可以关闭持久化功能,让数据只在服务器运行时存在。
RDB持久化
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
RDB是Redis默认采用的持久化方式,在redis.conf
配置文件中默认有此下配置:
save 900 1
save 300 10
save 60 10000
save 开头的一行就是持久化配置,可以配置多个条件(每行配置一个条件),每个条件之间是“或”的关系,save 900 1
表示15分钟(900秒钟)内至少1个键被更改则进行快照,save 300 10
表示5分钟(300秒)内至少10个键被更改则进行快照,save 60 10000
表示1分钟(60秒)内至少10000个键被更改则进行快照。
在redis.conf中:
- 配置dir
指定rdb快照文件的位置
- 配置dbfilenam
指定rdb快照文件的名称
如下就是rdb默认配置
dir ./
dbfilename dump.rdb
除了通过配置自动保存以外,也可以通过调用 SAVE
或者 BGSAVE
, 手动让 Redis 进行数据集保存操作。这种持久化方式被称为快照(snapshot)。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。
AOF持久化
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly
参数开启:
appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir
参数设置的,默认的文件名可以通过appendfilename参数修改。
默认配置如下:
dir ./
appendfilename "appendonly.aof"
除了配置AOF的目录和文件名之外,还可以通过appendfsync
配置自动保存时间。它有三个取值always
:一有修改就保存,everysec
:每秒保存一次,no
:不保存。
默认配置如下:
# appendfsync always
appendfsync everysec
# appendfsync no
注意:如果AOF和RDB同时开启,使用AOF文件恢复数据。因为AOF的数据完整性更高。
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。
举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。
然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。
执行 BGREWRITEAOF
命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。
Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 以后则可以自动触发 AOF 重写, 具体信息请查看 2.4 以后的示例配置文件。
redis服务器的发布与订阅
SUBSCRIBE
、 UNSUBSCRIBE
和 PUBLISH
三个命令实现了发布与订阅信息泛型(Publish/Subscribe messaging paradigm), 在这个实现中, 发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端), 而是将信息发送给频道(channel), 然后由频道将信息转发给所有对这个频道感兴趣的订阅者。
发送者无须知道任何关于订阅者的信息, 而订阅者也无须知道是那个客户端给它发送信息, 它只要关注自己感兴趣的频道即可。
对发布者和订阅者进行解构(decoupling), 可以极大地提高系统的扩展性(scalability), 并得到一个更动态的网络拓扑(network topology)。
比如说, 要订阅频道 foo 和 bar , 客户端可以使用频道名字作为参数来调用 SUBSCRIBE 命令:
redis> SUBSCRIBE foo bar
当有客户端发送信息到这些频道时, Redis 会将传入的信息推送到所有订阅这些频道的客户端里面。
正在订阅频道的客户端不应该发送除 SUBSCRIBE
和 UNSUBSCRIBE
之外的其他命令。 其中, SUBSCRIBE
可以用于订阅更多频道, 而 UNSUBSCRIBE
则可以用于退订已订阅的一个或多个频道。
SUBSCRIBE
和 UNSUBSCRIBE
的执行结果会以信息的形式返回, 客户端可以通过分析所接收信息的第一个元素, 从而判断所收到的内容是一条真正的信息, 还是 SUBSCRIBE
或 UNSUBSCRIBE
命令的操作结果。
PS:因为redis
的发布与订阅用的不多,这里只是简单的给出文档中发布订阅的介绍,具体可以参考官方文档。
redis服务器的事务
redis
服务器中的事务,和MySQL
这样的关系型数据库的事务有着本质上的区别,如果要说的形象点,那么redis
的事务只是简单批处理而已。
事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
redis事务的几个命令
-
MULTI
:标记一个事务块的开始。事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由EXEC
命令原子性(atomic)地执行。 -
EXEC
:执行所有事务块内的命令。假如某个(或某些) key 正处于WATCH
命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么EXEC
命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。 -
DISCARD
:取消事务,放弃执行事务块内的所有命令。如果正在使用WATCH
命令监视某个(或某些) key,那么取消所有监视,等同于执行命令UNWATCH
。 -
WATCH
:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 -
UNWATCH
:取消WATCH
命令对所有 key 的监视。如果在执行WATCH
命令之后,EXEC
命令或DISCARD
命令先被执行了的话,那么就不需要再执行UNWATCH
了。因为事务已经被执行或者被取消了。
使用方法
简单的开启事务和提交事务
127.0.0.1:6401> set number 1
OK
127.0.0.1:6401> SADD names "Switch"
(integer) 1
# 开启事务
127.0.0.1:6401> multi
OK
127.0.0.1:6401> incr number
QUEUED
127.0.0.1:6401> incr number
QUEUED
127.0.0.1:6401> sadd names "Tom"
QUEUED
127.0.0.1:6401> incrby number 5
QUEUED
127.0.0.1:6401> sadd names "Tom"
QUEUED
# 执行事务
127.0.0.1:6401> exec
1) (integer) 2
2) (integer) 3
3) (integer) 1
4) (integer) 8
5) (integer) 0
# 查看结果
127.0.0.1:6401> get number
"8"
127.0.0.1:6401> smembers names
1) "Switch"
2) "Tom"
127.0.0.1:6401>
EXEC
命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。
当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED
的状态回复(status reply), 这些被入队的命令将在 EXEC
命令被调用时执行。
事务错误的解决办法
127.0.0.1:6401> multi
OK
127.0.0.1:6401> set list "Error List"
QUEUED
127.0.0.1:6401> rpop list
QUEUED
127.0.0.1:6401> set list "Error"
QUEUED
127.0.0.1:6401> hmset student name "Switch" gender "man"
QUEUED
127.0.0.1:6401> hgetall student
QUEUED
127.0.0.1:6401> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
4) OK
5) 1) "name"
2) "Switch"
3) "gender"
4) "man"
127.0.0.1:6401>
在redis
事务中,有两种错误,一种是入队命令本身就是错的,这种会错误会在入队命令执行时,直接将错误信息返回给客户端。另一种错误是入队命令没错,但是命令执行出错了。就如同上面的例子,对String
类型的键做右出队操作,这条命令本身没有任何错误,可以对键进行出队操作,不过当执行该命令的时候,发现该键不是列表类型的。就会报错误的数据类型错误。
从上面的例子也可以看出,即使事务中有某条/某些命令执行失败了, 事务队列中的其他命令仍然会继续执行 —— Redis 不会停止执行事务中的命令。
放弃事务
127.0.0.1:6401> set name "Switch"
OK
127.0.0.1:6401> multi
OK
127.0.0.1:6401> set name "Kity"
QUEUED
127.0.0.1:6401> discard
OK
127.0.0.1:6401> get name
"Switch"
127.0.0.1:6401> get list
"Error"
可以看到,当DISCARD
命令被执行时,事务被放弃,事务的队列也被清空了,客户端也从事务状态退出了。
使用watch命令实现乐观锁
127.0.0.1:6401> set number 1
OK
127.0.0.1:6401> SADD names "Switch"
(integer) 1
# 监视names是否被修改
127.0.0.1:6401> watch names
OK
127.0.0.1:6401> multi
OK
127.0.0.1:6401> incr number
QUEUED
127.0.0.1:6401> incr number
QUEUED
# 另一个客户端执行 127.0.0.1:6401> sadd names "Kity" 操作
127.0.0.1:6401> sadd names "Tom"
QUEUED
127.0.0.1:6401> incrby number 5
QUEUED
127.0.0.1:6401> sadd names "Zad"
QUEUED
# 可以看到执行结果为nil,这代表事务失败
127.0.0.1:6401> exec
(nil)
当 EXEC
被调用时, 不管事务是否成功执行, 对所有键的监视都会被取消。
另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。
使用无参数的 UNWATCH
命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH
命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。
——参考《Redis命令参考》
——参考《Redis官方文档》