够了,既兼顾了性能又保证了安全。
复制
通过持久化功能,Redis保证了即使在服务器重启情况下也不会损失数据,但由于数据存储在一台服务器上,服务器的硬盘出现故障也会导致数据丢失。为了避免单点故障,希望将数据库复制多个副本以部署在不同的服务器上,即使有一台服务器出现故障其他服务器依然可以继续提高服务。要求当一台服务器上的数据更新后可以自动将更新的数据同步到其他区服务器上,Redis提高了复制功能可以自动实现同步过程。
同步数据库分为两类: 一类是主数据库,一类是从数据库。主数据库可以进行读写操作,当发生写操作时自动将数据同步给从数据库。而从数据库一般只是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
在redis中使用复制功能很简单,只需要在从数据库的配置文件中加入:
slaveof 主数据库的IP 主数据库端口
主数据库中的任何数据变化都会自动同步到从数据库。默认情况下从数据库是只读的,如果直接修改从数据库的数据会出现错误。但可以设置从数据库配置文件的slava-read-only为no使得从数据库可写,对从数据库的任何更改都不会同步给任何其他数据库,并且主数据库更新了对应的数据会覆盖从数据库中的改动。
[
root@node01 ~]# redis-server --port 6380 --slaveof 127.0.0.1 6379
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 2.8.19 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in stand alone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6380
| `-._ `._ / _.-' | PID: 6229
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[6229] 14 Jul 23:07:03.803 # Server started, Redis version 2.8.19
[6229] 14 Jul 23:07:03.803 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[6229] 14 Jul 23:07:03.803 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
[6229] 14 Jul 23:07:03.803 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
[6229] 14 Jul 23:07:03.819 * DB loaded from disk: 0.016 seconds
[6229] 14 Jul 23:07:03.819 * The server is now ready to accept connections on port 6380
[6229] 14 Jul 23:07:04.806 * Connecting to MASTER 127.0.0.1:6379 <<----连接到主数据库
[6229] 14 Jul 23:07:04.806 * MASTER <-> SLAVE sync started
[6229] 14 Jul 23:07:04.806 * Non blocking connect for SYNC fired the event.
[6229] 14 Jul 23:07:04.806 * Master replied to PING, replication can continue... <<----发送PING,测试服务器可连接
[6229] 14 Jul 23:07:04.806 * Partial resynchronization not possible (no cached master)
[6229] 14 Jul 23:07:04.817 * Full resync from master: 579c87d6621682f163fbfd40811d3f161cde64ca:1 <<----开始同步
[6229] 14 Jul 23:07:04.938 * MASTER <-> SLAVE sync: receiving 28 bytes from master
[6229] 14 Jul 23:07:04.938 * MASTER <-> SLAVE sync: Flushing old data <<-----同步旧数据
[6229] 14 Jul 23:07:04.938 * MASTER <-> SLAVE sync: Loading DB in memory <<----导入数据到内存中
[6229] 14 Jul 23:07:04.938 * MASTER <-> SLAVE sync: Finished with success <<----同步完成
127.0.0.1:6379> set testkey 1000
OK
127.0.0.1:6379> set testkey1 1000
OK
127.0.0.1:6379> set testkey2 100
OK
127.0.0.1:6379> set testkey3 200
OK
127.0.0.1:6379> set testkey4 400
OK
127.0.0.1:6379> set testkey5 500
OK
127.0.0.1:6379> set testkey6 600
OK
127.0.0.1:6379> set testke76 100
OK
127.0.0.1:6379> set testke8 200
OK
127.0.0.1:6379> set testke9 100
OK
127.0.0.1:6379> set testke10 2100
OK
127.0.0.1:6379> set testke10 2100
OK
127.0.0.1:6379> set testke10 3100
OK
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> exit
127.0.0.1:6380> get testke*
(nil)
127.0.0.1:6380> get testke10
"3100"
127.0.0.1:6380> get testke10
"3100"
127.0.0.1:6380> get testke20
(nil)
127.0.0.1:6380> get testke9
"100"
127.0.0.1:6380>
从上述的例子可知两个数据库之间进行了复制。
SLAVEOF命令会停止和原来数据库的同步转而和新数据库同步。
还可以使用SLABEOF NO ONE来使当前数据库停止接收其他数据库的同步转成主数据库。
复制的基本原理
当一个从数据库启动后,会向主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照(RDB持久化的过程),并将保存期间接收到的命令缓存起来,当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后会再入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会重新执行该操作,不支持断点续传功能。
可以使用telnet工具模拟一个从数据库了解具体过程:
> 在命令行中连接主数据库。
> 发送PING命令确认主数据库是可以连接的。
> 主数据库若正常会回复+PONG,如果没有则提示错误,若需要密码,则需呀发送AUTH命令进行验证。
> 向主数据库发送REPLCONF命令说明从数据库的端口号。
> 接下来开始同步,向主数据库发送SYNC命令同步,主数据库发送回快照文件和缓存的命令。
> 从数据库会将收到的内容写入磁盘的零时文件中,当写入完成后数据库用该临时文件替换RDB快照文件,之后的操作就和RDB持久化时启动恢复一样。
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
PING
+PONG
REPLCONF listening-port 6382
+OK
sync
$165
REDIS0006testkey3testkey2testtestkey6testkey4testkey1testke10testkey5testke9testke8testkeytestke76?T
$4
PING
*1
$4
PING
*1
$4
PING
*2
$6
SELECT
$1
0
*3
$3
set
$8
testke10
$4
2100
*1
$4
PING
*3
$3
set
$8
testke10
$4
2100
*3
$3
set
$8
testke10
$4
2100
*3
$3
set
$8
testke10
$3
200
*3
$3
set
$8
testke10
$4
2001
*3
$3
set
$8
testke10
$4
2002
*3
$3
set
$8
testke10
$4
2003
*1
$4
PING
*3
$3
set
$8
testke10
$4
2005
*3
$3
set
$8
testke10
$4
2006
*3
$3
set
$8
testke10
$4
2007
*3
$3
set
$8
testke10 <<----master设置的值
$4
2008
*1
$4
PING
*1
$4
PING
*1
$4
PING
*1
$4
PING
*3
$3
set
$9
testke100
$2
20
*1
$4
PING
*1
$4
PING
*1
$4
PING
*1
$4
PING
同步的过程中从数据库并不会阻塞,而是可以继续处理客户端发来的命令。默认情况下,从数据库会用同步前的数据对命令进行响应。可以配置slave-serve-stale-data参数为no来使从数据库在同步完成前对所有命令(除了INFO和SLAVEOF)都回复错误:"SYNC with master in progress." 。之后主数据库的任何数据变化都会同步给从数据库,同步的内容和Redis通信协议一样。
复制可以实现读写分离以提高服务器的负载能力,在常见的场景中读的频率大于写,当单机的Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作,从而提高整体的性能。
高性能的主从控制
由于持久化时相对耗时的操作,为了提高性能,可以通过复制建立一个从数据库,并在从数据库中启用持久化,而在主数据库中禁用持久化。当从数据库崩溃时,重启后主数据库自动将数据同步过来,不会担心数据丢失,而当主数据库崩溃时,需要在从数据库中使用SLAVOF NO ONE命令将从数据库提升为主数据库继续服务,并在原来的主数据库启动后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可将数据同步回去。该方案涉及到主备切换的功能,在运用时可能需要做一些限制。
安全
Redis运行在可信的环境是保证Redis安全的最重要方法。Redis的默认配置会接受到来自任何地址的请求,但为了保证安全性,可以在配置文件通过修改bind参数。
还可以在配置文件中设置requirepass参数来设置一个密码。这样客户端每次连接到Redis时都需要发送密码,否则Redis拒绝执行客户端发送来的命令。发送命令使用AUTH命令,如auth password。
配置redis复制时,若主数据库设置了密码,需要在从数据库的配置文件中通过masterauth参数设置主数据库的密码,使从数据库连接主数据库时自动使用AUTH命令认证。