Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1869990
  • 博文数量: 152
  • 博客积分: 3730
  • 博客等级: 上尉
  • 技术积分: 3710
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-02 14:36
个人简介

减肥,运动,学习,进步...

文章分类

全部博文(152)

文章存档

2016年(14)

2015年(17)

2014年(16)

2013年(4)

2012年(66)

2011年(35)

分类: 服务器与存储

2016-07-22 10:21:06

Redis的管理主要包括持久化、复制、和安全。

通信协议

Redis通信协议是Redis客户端与Redis之间交流的语言,通信协议规定了命令和返回值的格式。了解协议对理解AOF文件格式和主从复制时主数据库向从数据库发送的内容等有帮助。对于开发redis客户端也必须了解基本的格式。支持两种通信协议:
      1、二进制安全的统一请求协议。
      2、比较直观的便于在telnet程序中输入的简单协议。
这两种协议只是命令的格式有区别,命令的返回值的格式是一样的。

简单协议,主要适合在telnet程序中和redis通信。简单协议的命令格式就是将命令和各个参数使用空格分隔开,Redis解析简单协议时只是简单的以空格分隔参数,因此无法输入二进制字符。

Redis有5中返回类型的格式, redis-cli的返回类型实际只是对这5种的封装。
    1、错误回复, 以-开头,并在后面跟上错误信息,最好以\r\n结尾。
    2、状态回复, 以+开头,并在后面跟上状态信息,最后以\r\n结尾。
    3、整数回复, 以:开头,后面跟上数字,最后以\r\n结尾。
    4、字符串回复, 已$开头,并在后面更少字符串的长度,并以\r\n分隔,接着是字符串的内容和\r\n。如果返回值是空结果,则返回$-1以空字符串相区别。
    5、多行字符串回复,以*开头,并在后面跟上字符串回复的组数,并以\r\n分隔,接下来后面跟的就是字符串回复的具体内容。也就是多行字符串符合包含了字符串回复

统一请求协议其命令格式和多行字符串回复的格式类型,发送命令时指定了后面字符串的长度,所以命令的每个参数都可以包含二进制的字符。返回格式是一样的,即包含了之前的5种类型。

Redis的AOF文件和主从复制时主数据库向从数据库发送的内容都使用了统一请求协议,开发redis客户端的建议直接使用统一请求协议。

持久化

Redis的性能很大程度上是因为数据保存在内存中,但为了使Redis在重启之后仍然能保证数据不丢失,需要将数据从内存中以某种形式同步到磁盘中,这个过程称为持久化。

Redis支持两种方式的持久化: RDB和AOF。
RDB方式的持久化是通过快照完成,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘。进行快照的条件可以由用户在配置文件中定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。RDB是Redis默认采用的持久化方式,在配置文件中已经预置了3个条件:
save 900 1
save 300 10
save 60 10000
save参数指定了快照条件,可以存在多个条件,条件之间是“或”的关系。save 900 1的意思是在15分钟(900秒钟)内有至少一个键被更改则进行快照。如果想要禁用自动快照,只需要将所有的save参数删除。Redis默认会将快照文件存储在当前目录的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。

快照的过程如下:
(1)Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
(2)父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
(3)当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。、

基本原理是:执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据

Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实现Redis数据库备份。实际上是说可以定期的复制快照生成的文件。RDB文件是压缩的二进制格式,比内存中的数据小,更有利于传输。

还可以手动执行快照,支持SAVE和BGSAVE两个命令,区别是SAVE是在主进程中执行快照操作,会阻塞其他请求,而BGSAVE是通过fork子进程进行快照操作。

Redis在启动时会自动读取RDB快照文件,将数据从硬盘载入内存。但载入的速率与数据大小有关。

根据上述的条件可知,RDB实际上不能保证绝对的安全,一旦Redis异常退出,会丢失最后一次快照以后更改的所有数据。

[root@node01 ~]# ll /var/lib/redis/dump.rdb 
-rw-r--r-- 1 root root 736 Jul 11 22:41 /var/lib/redis/dump.rdb   <<----此时的文件大小
[root@node01 ~]# redis-cli                  <<----执行一系列的操作
127.0.0.1:6379> set mykey6 200
OK
127.0.0.1:6379> set mykey7 200
OK
127.0.0.1:6379> set mykey8 200
OK
127.0.0.1:6379> set mykey9 200
OK
127.0.0.1:6379> set mykey10 200
OK
127.0.0.1:6379> set mykey20 200
OK
127.0.0.1:6379> set mykey30 200
OK
127.0.0.1:6379> set mykey30 400
OK
127.0.0.1:6379> exit
[root@node01 ~]# ll /var/lib/redis/dump.rdb 
-rw-r--r-- 1 root root 842 Jul 14 22:20 /var/lib/redis/dump.rdb              <<------数据写入到了文件中,说明内容有更新
[root@node01 ~]# 

AOF: append only file
默认Redis没有开启AOF的持久化,但可以通过appendonly yes开启。开启AOF持久化之后,每执行一条会更改Redis中的数据的命令。Redis就会将该命令写入磁盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同。默认是appendonly.aof。

在redis-cli中执行如下的操作,观察appendonly.aof中的输出如下:
[root@node01 ~]# redis-cli 
127.0.0.1:6379> 
127.0.0.1:6379> 
127.0.0.1:6379> set test 2000
OK
127.0.0.1:6379> 
[root@node01 ~]# tailf /var/lib/redis/appendonly.aof     
*2
$6
SELECT
$1
0
*3
$3
set
$4
test
$4
2000

AOF文件是纯文本文件,其内容正是Redis客户端向Redis发送的原始通信协议的内容。
根据上述的通信协议的回复内容来分析,这种输出是一个多行的输出:
*2是指一个2行的字符串输出,$6是指第一行字符串的长度为6,内容为SELECT,$1是字符串长度为1,内容为0。
*3是一个3行的字符串,第一行长度为3,内容为set,第二行长度为4,内容为test,第三行长度为4,内容为2000。

为了减少不必要的记录,Redis也会对AOF进行优化。每当达到一定条件时Redis就会自动重写AOF文件,这个条件可以在配置文件中设置:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage参数的意义是当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据。auto-aof-rewrite-min-size参数限制了允许重写的最小AOF文件大小,通常在AOF文件很小的情况下即使其中有很多冗余的命令我们也并不太关心。

在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。

AOF都会将命令记录在AOF文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在Redis中我们可以通过appendfsync参数设置同步的时机:
# appendfsync always
appendfsync everysec
# appendfsync no
默认情况下Redis采用everysec 规则,即每秒执行一次同步操作。always表示每次执行写入都会执行同步,这是最安全也是最慢的方式。no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安全的方式。一般情况下使用默认值everysec就足够了,既兼顾了性能又保证了安全。

复制

通过持久化功能,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  <<----同步完成


[root@node01 ~]# redis-cli
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
[root@node01 ~]# redis-cli -p 6380
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持久化时启动恢复一样。

[root@node01 ~]# telnet 127.0.0.1 6379
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命令认证。

阅读(4494) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~