搭建
部署
基于 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. |