搭建
部署
基于 centos 6.5
安装
下载安装包
1 | wget http://download.redis.io/redis-stable.tar.gz |
解压安装包
1 | tar -zxvf redis-stable.tar.gz |
编译、安装
1 | cd redis-stable |
注: make
命令时可能会报错,如果提示 gcc command
不识别,自行安装 gcc
;
启动
加上 &
号使 Redis
以后台程序方式运行;加参数 --protected-mode no
可以使无保护模式启动;
1 | redis-server ./path/to/conf-file & |
或者在配置文件修改 daemonize
的值为 yes
,也可以使 Redis
在后台启动;
检测
检测后台进程是否存在
1 | ps -ef |grep redis |
检测 6379 端口是否在监听
1 | netstat -lntp | grep 6379 |
使用 redis-cli
客户端检测连接是否正常
1 | redis-cli [-h localhost -p 6379] |
如果外部无法访问,检查配置文件是否开启外部访问
1 | # bind 127.0.0.1 |
持久化
Redis
有两种持久化的方式:快照(RDB
文件)和追加式文件(AOF
文件):
RDB
持久化方式是在一个特定的间隔保存某个时间点的一个数据快照。AOF
(Append only file
)持久化方式则会记录每一个服务器收到的写操作。数据恢复时,这些记录的操作会逐条执行从而重建出原来的数据。写操作命令记录的格式跟Redis
协议一致,以追加的方式进行保存。
RDB
RDB
就是Snapshot
存储,是默认的持久化方式。按照一定的策略周期性的将数据保存到磁盘。对应产生的数据文件为 dump.rdb
,通过配置文件中的save
参数来定义快照的周期。Redis
支持将当前数据的快照存成一个数据文件实现持久化。而一个持续写入的数据库如何生成快照呢。Redis
借助了fork
命令的copy on write
机制。在生成快照时,将当前进程fork
出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB
文件。
Client
也可以使用 save
或者 bgsave
命令通知 redis
做一次快照持久化。save
操作是在主线程中保存快照的,由于 redis
是用一个主线程来处理所有 client
的请求,这种方式会阻塞所有 client
请求,所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘 io
操作,可能会严重影响性能。
Redis
的 RDB
文件不会坏掉,因为其写操作是在一个新进程中进行的。当生成一个新的 RDB
文件时,Redis
生成的子进程会先将数据写到一个临时文件中,然后通过原子性 rename
系统调用将临时文件重命名为 RDB
文件。这样在任何时候出现故障,Redis
的 RDB
文件都总是可用的。并且 Redis
的 RDB
文件也是 Redis
主从同步内部实现中的一环。
主从同步:
第一次
Slave
向Master
同步的实现是:Slave
向Master
发出同步请求,Master
先dump
出rdb
文件,然后将rdb
文件全量传输给slave
,然后Master
把缓存的命令转发给Slave
,初次同步完成。
第二次 以及以后的同步实现是:
Master
将变量的快照直接实时依次发送给各个Slave
。但不管什么原因导致Slave
和Master
断开重连都会重复以上两个步骤 (完整 + 增量) 的过程。
Redis
的主从复制是建立在内存快照的持久化基础上的,只要有Slave
就一定会有内存快照发生。
工作原理
Redis
调用fork()
,产生一个子进程。- 父进程继续处理
client
请求,子进程把内存数据写到一个临时的RDB
文件。由于os
的写时复制机制(copy on write
)父子进程会共享相同的物理页面,当父进程处理写请求时os
会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数据是fork
时刻整个数据库的一个快照。 - 当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出
优缺点
优点:
RDB
文件是一个很简洁的单文件,它保存了某个时间点的Redis
数据,很适合用于做备份。你可以设定一个时间点对RDB
文件进行归档,这样就能在需要的时候很轻易的把数据恢复到不同的版本。RDB
很适合用于灾备。单文件很方便就能传输到远程的服务器上。RDB
的性能很好,需要进行持久化时,主进程会fork
一个子进程出来,然后把持久化的工作交给子进程,自己不会有相关的I/O
操作。- 比起
AOF
,在数据量比较大的情况下,RDB
的启动速度更快。
缺点:
RDB
容易造成数据的丢失。假设每 5 分钟保存一次快照,如果Redis
因为某些原因不能正常工作,那么从上次产生快照到Redis
出现问题这段时间的数据就会丢失了。RDB
使用fork()
产生子进程进行数据的持久化,如果数据比较大的话可能就会花费点时间,造成Redis
停止服务几毫秒。如果数据量很大且CPU
性能不是很好的时候,停止服务的时间甚至会到 1 秒。
AOF
快照并不是很可靠。如果服务器突然 Crash
了,那么最新的数据就会丢失。而 AOF
文件则提供了一种更为可靠的持久化方式。每当 Redis
接受到会修改数据集的命令时,就会把命令追加到 AOF
文件里,当你重启 Redis
时,AOF
里的命令会被重新执行一次,重建数据。
工作原理
redis
调用fork
,现在有父子两个进程- 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
- 父进程继续处理
client
请求,除了把写命令写入到原来的aof
文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题 - 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件
- 现在父进程可以使用临时文件替换老的
aof
文件,并重命名,后面收到的写命令也开始往新的aof
文件中追加
优缺点
优点:
- 比
RDB
可靠。你可以制定不同的fsync
策略:不进行fsync
、每秒fsync
一次和每次查询进行fsync
。默认是每秒fsync
一次。这意味着你最多丢失一秒钟的数据。 AOF
日志文件是一个纯追加的文件。就算服务器突然Crash
,也不会出现日志的定位或者损坏问题。甚至如果因为某些原因(例如磁盘满了)命令只写了一半到日志文件里,我们也可以用redis-check-aof
这个工具很简单的进行修复。- 当
AOF
文件太大时,Redis
会自动在后台进行重写。重写很安全,因为重写是在一个新的文件上进行,同时Redis
会继续往旧的文件追加数据。新文件上会写入能重建当前数据集的最小操作命令的集合。当新文件重写完,Redis
会把新旧文件进行切换,然后开始把数据写到新文件上。 AOF
把操作命令以简单易懂的格式一条接一条的保存在文件里,很容易导出来用于恢复数据。例如我们不小心用FLUSHALL
命令把所有数据刷掉了,只要文件没有被重写,我们可以把服务停掉,把最后那条命令删掉,然后重启服务,这样就能把被刷掉的数据恢复回来。
缺点:
- 在相同的数据集下,
AOF
文件的大小一般会比RDB
文件大。 - 在某些
fsync
策略下,AOF
的速度会比RDB
慢。通常fsync
设置为每秒一次就能获得比较高的性能,而在禁止fsync
的情况下速度可以达到RDB
的水平。 - 在过去曾经发现一些很罕见的
BUG
导致使用AOF
重建的数据跟原数据不一致的问题。
日志重写
随着写操作的不断增加, AOF
文件会越来越大。例如你递增一个计数器 100 次,那么最终结果就是数据集里的计数器的值为最终的递增结果,但是 AOF
文件里却会把这 100 次操作完整的记录下来。而事实上要恢复这个记录,只需要 1 个命令就行了,也就是说 AOF
文件里那 100 条命令其实可以精简为 1 条。所以 Redis
支持这样一个功能:在不中断服务的情况下在后台重建 AOF
文件。
工作原理如下:
Redis
调用fork()
,产生一个子进程。- 子进程把新的
AOF
写到一个临时文件里。 - 主进程持续把新的变动写到内存里的
buffer
,同时也会把这些新的变动写到旧的AOF
里,这样即使重写失败也能保证数据的安全。 - 当子进程完成文件的重写后,主进程会获得一个信号,然后把内存里的
buffer
追加到子进程生成的那个新AOF
里。
我们可以通过配置设置日志重写的条件:
1 | 在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成DISK IO上的冲突。 |
要禁用自动的日志重写功能,我们可以把百分比设置为0:
1 | auto-aof-rewrite-percentage 0 |
数据损坏修复
如果因为某些原因(例如服务器崩溃)AOF
文件损坏了,导致 Redis
加载不了,可以通过以下方式进行修复:
- 备份
AOF
文件。 - 使用
redis-check-aof
命令修复原始的AOF
文件:redis-check-aof --fix
- 可以使用
diff -u
命令看下两个文件的差异。 - 使用修复过的文件重启
Redis
服务。
从 RDB 切换到 AOF
这里只说 Redis >= 2.2
版本的方式:
- 备份一个最新的
dump.rdb
的文件,并把备份文件放在一个安全的地方。 运行以下两条命令:
1
2$ redis-cli config set appendonly yes
$ redis-cli config set save ""第二条命令是用来禁用
RDB
的持久化方式,但是这不是必须的,因为你可以同时启用两种持久化方式。- 确保数据跟切换前一致。
- 确保数据正确的写到
AOF
文件里。
总结
从上面看出,RDB
和 AOF
操作都是顺序 IO
操作,性能都很高。而同时在通过 RDB
文件或者 AOF
日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读。
到底选择什么呢?下面是来自官方的建议:
通常,如果你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。如果你可以接受灾难带来的几分钟的数据丢失,那么你可以仅使用 RDB
。很多用户仅使用了 AOF
,但是我们建议,既然 RDB
可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用 RDB
。
在数据恢复方面:RDB
的启动时间会更短,原因有两个
- 一是
RDB
文件中每一条数据只有一条记录,不会像AOF
日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。 - 另一个原因是
RDB
文件的存储格式和Redis
数据在内存中的编码格式是一致的,不需要再进行数据编码工作,所以在CPU
消耗上要远小于AOF
日志的加载。
注意:
上面说了 RDB
快照的持久化,需要注意:在进行快照的时候(save
),fork
出来进行 dump
操作的子进程会占用与父进程一样的内存,真正的 copy-on-write
,对性能的影响和内存的耗用都是比较大的。比如机器 8G 内存, Redis
已经使用了 6G 内存,这时 save
的话会再生成 6G,变成 12G,大于系统的 8G。这时候会发生交换;要是虚拟内存不够则会崩溃,导致数据丢失。所以在用 redis
的时候一定对系统内存做好容量规划。
目前,通常的设计思路是利用 Replication
机制来弥补 aof
、snapshot
性能上的不足,达到了数据可持久化。即 Master
上 Snapshot
和 AOF
都不做,来保证 Master
的读写性能,而 Slave
上则同时开启 Snapshot
和 AOF
来进行持久化,保证数据的安全性。
主从示例
现在开启三个 redis
服务器,分别对应三个不同的端口: 6379、6380、6381;
三台服务器,由 端口 6379
担当主服务器 master
, 端口 6380
担当从服务器 slave1
, 端口 6381
担当从服务器 slave2
;
配置:
master
的配置:
- 关闭
rdb
备份; aof
备份可要可不要;如果打开,则从服务器没有必要开启;如果关闭,把slave1
的aof
备份开启;
slave1
的配置:
1 | # 端口与进程文件设置 |
slave2
的配置:
1 | # 端口与进程文件设置 |
FAQ
1.如果误操作 flushdb
或 flushall
,怎么办?
答: 通过 aof
恢复:立即执行 shutdown nosave
;将 aof
文件中的和 flush
操作有关的进行删除;然后,重启 Redis
服务器;
2.如何手动修改主从关系?
答:假设 6379 这个 master
宕机了,这时想设置 6380 这个 slave
主机为 master
主机, 做以下步骤:
1) 使 6380 不继续做 master
主机;(命令:slaveof no one
)。修改 readonly
参数为 no
;(命令:config set slave-read-only no
)
2) 其它的 slave
从机再指定新的这台 6380 新 master
主机,命令该 slave
为新 master
主机的 slave
;(命令:slaveof [ip] [port]
)
附录
官方的配置文件例子
1 | Redis configuration file example. |