Redis基础学习--持久化(数据备份与恢复)、复制、安全、通信协议、管理工具

来源:互联网 发布:智慧办公软件下载 编辑:程序博客网 时间:2024/06/01 09:49

一、持久化

1).RDB(数据备份与恢复)

1).备份
   Redis SAVE 命令用于创建当前数据库的备份。
   创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。
实例
redis 127.0.0.1:6379> SAVE
OK
该命令将在 redis 安装目录中创建dump.rdb文件。
2).恢复数据
    如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令,如下所示:
redis 127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/home/changwen/redis-3.2.5/src"
    以上命令 CONFIG GET dir 输出的 redis 安装目录为 "/home/changwen/redis-3.2.5/src"。

    Redis默认会将快照文件存储在当前目录的dump.rdh文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。
    理解Redis实现快照的过程对我们了解快照文件的特性有很大的帮助。快照的过程如下。
    (1) Redis使用fork函数复制一份当前进程(父进程)的副木(子进程);
    (2)父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件:
    (3)当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
    在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write )策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
    通过上述过程可以发现Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我可以通过定时备份RDB文件来实现Redis数据库备份。RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
    除了自动快照,还可以手动发送SAVE或bgsave命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。
    Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20^-30秒钟。
    通过RDB方式实现持久化,一旦 Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用Ao}方式进行持久化。

2).AOF方式
    默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
appendonly yes
    开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改。
    下面讲解AOF持久化的具体实现,假设在开启AOF持久化的情况下执行了如下4个命令:
SET foo 1
SET foo 2
SET foo 3
GET foo
    Redis会将前3条命令写入AOF文件中,此时AOF文件中的内容如下:
*2
$6
SELECT
$1
0
*3
$3
set
$3
foo
$1
1
*3
$3
set
$3
foo
$1
2
*3
$3
set
$3
foo
$1
3    可见AOF文件是纯文本文件,其内容正是Redis客户端向Redis发送的原始通信协议的内容,从中可见Redis确实只记录了前3条命令。然而这时有一个问题是前2条命令其实都是冗余的,因为这两条的执行结果会被第三条命令覆盖。随着执行的命令越来越多,AOF文件的大小也会越来越大,即使内存中实际的数据可能并没有多少。很自然地,我们希望Redis可以自动优化ADF文件,就上例而言,就是将前两条无用的记录删除,只保留第二条。实际上Redis也正是这样做的,每当达到一定条件时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自动执行重写外,我们还可以主动使用bgrewriteaof命令手动执行AOF重写。
    上例中的AOF文件重写后的内容为:    
*2
$6
SELECT
$1
0
*3
$3
SET
$3
foo
$1
3    可见冗余的命令己经被删除了。重写的过程只和内存中的数据有关,和之前的AOF文件无关,这与ROF很相似,只不过二者的文件格式完全不同。
    在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。
    需要注意的是虽然每次执行更改数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是事实上由于操作系统的缓存机制,数据井没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在Redis中我们可以通过appendfsync参数设置同步的时机:
# appendfsync always
appendfsync everysec
# appendfsync nc
    默认情况下Redis采用everysec规则,即每秒执行一次同步操作。always表示每次执行写入都会执行同步,这是最安全也是最慢的方式。no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安个的方式。一般情况下使用默认值everysec就足够了,既兼顾了性能又保证了安全。
    Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。

二、复制

    通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失。为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器,即使有一台服务器出现故障其他服务器依然可以继续提供服务。这就要求当一台服务器上的数据库更新后,可以自动将更新的数据同步到其他服务器上L, Redis提供了复制(replication)功能可以自动实现同步的过程。
2-1.配置
    同步后的数据库分为两类,一类是主数据库(master ),一类是从数据库(slave)。主数据库可以进行读写操作,当发生写操作时自动将数据同步给从数据库。而从数据库一般
是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
    在Redis中使用复制功能非常容易,只需要在 从数据库 的配置文件中加入"slaveof 主数据库IP 主数据库端口"即可,主数据库无需进行任何配置。
    为了能够更直观地展示复制的流程,下面将进行简单的演示。我们要在一台服务器上启动两个Redis实例,监听不同端,其中一个作为主数据库,另一个作为从数据库。首先我们不加任何参数来启动一个Redis实例作为主数据库:
./redis-server
    该实例默认监听6379端口。
    然后加上slaveof参数启动另一个Redis实例作为从数据库,并让其监听6380端口:
./redis-server --port 6380 --slaveof 127.0.0.1 6379
    此时在主数据库中的任何数据变化都会自动同步到从数据库中。我们打开redis-cli实例A并连接到主数据库:
./redis-cli
    再打开redis-cli实例B并连接到从数据库:
./redis-cli -p 6380
    在实例A中(主数据库)使用SET命令设置一个键的值:
127.0.0.1:6379> set foo bar
OK
    此时在实例B(从数据库)中就可以获得该值了
127.0.0.1:6380> get foo
"bar"
   但在默认情况下 从数据库 是只读的,如果直接修改从数据库的数据会出现错误:
127.0.0.1:6380> set foo hi
(error) READONLY You can't write against a read only slave.    可以通过设置从数据库的配置文件中的slave-read-onle为on以使从数据库可写,但是对从数据库的任何更改都不会同步给任何其他数据库,并且一旦主数据库中更新了对
应的数据就会覆盖从数据库中的改动。
    配置多台从数据库的方法也一样,在所有的从数据库的配置文件中都加上slaveof参数指向同一个主数据库即可。
    除了通过配置文件或命令行参数设置slaveof参数,还可以在运行时使用SLAVEOF命令修改:
redis> SLAVEOP 127.0.0.1 6379
    如果该数据库已经是其他主数据库的从数据库了,SLAVEOF命令会停止和原来数据库的同步转而和新数据库同步。还可以使用slaveof no one来使当前数据库停正接收其他数据库的同步转成主数据库。

2-2.原理
    了解Redis复制的原理对日后运维有很大的帮助。
    当一个从数据库启动后,会向主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会重新执行上述操作,不支持断点续传
    实际的过程略微复杂一些,由于Redis服务器使用TCP协议通信,所以我们可以使用telnet工具伪装成一个从数据库来了解同步的具体过程。首先在命令行中连接主数据库(默认端口为6379,且没有任何从数据库连接):

changwen@ubuntu:~/redis-3.2.5/src$ telnet 127.0.0.1 6379Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.# 然后作为从数据库,我们先要发送PING命令确认主数据库是否可以连接:# 主数据库会回复+PGNG。如果没有收到主数据库的回复,则向用户提示错误。# 如果主数据库需要密码才能连接,我们还得发送auth命令进行验证ping+PONG# 而后向主数据库发送replconf 命令说明自己的端口号(这里随便选择一个)replconf listening-port 6381+OK# 这时就可以开始同步的过程了:向主数据库发送SYNC命令开始同步,此时主数据库# 发送回快照文件和缓存的命令。sync$1083REDIS0007�    redis-ver3.2.5�
    从数据库会将收到的内容写入到硬盘上的临时文件中,当写入完成后从数据库会用该临时文件替换RDB快照文件(RDB快照文件的位置就是持久化时配置的位置,由dir和dbfilename两个参数确定),之后的操作就和RDB持久化时启动恢复的过程一样了。需要注意的是在同步的过程中从数据库并不会阻塞,而是可以继续处理客户端发来的命令。默认情况下,从数据库会用同步前的数据对命令进行响应。可以配置slave-serve-stale-data参数为no来使从数据库在同步完成前对所有命令(除了info和slaveof)都回复错误:"SYNC with master in progress.”
    之后主数据库的任何数据变化都会同步给从数据库,同步的内容和Redis通信协议一样,比如我们在主数据库中执行set foo hi,通过telnet我们收到:
*3
$3
set
$3
foo
$2
hi
    在复制的过程中,快照无论在主数据库还是从数据库中都起了很大的作用,只要执行复制就会进行快照,即使我们关闭了RDB方式的持久化(通过删除所有save参数)。更进一步,无论是否启用了RDB方式的持久化,Redis在启动时都会尝试读取dir和dbfilename两个参数指定的RDB文件来恢复数据库。
从数据库不仅可以接收主数据库的同步数据,自己也可以同时作为主数据库存在.

2-4.读写分离
    通过复制可以实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率大于写,当单机的Redis无法应付大量的读请求时(尤其是较耗资源的请求,比如sort命令等)可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作。

2-5.从数据库持久化

    另一个相对耗时的操作是持久化,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。而当主数据库崩溃时,需要在从数据库中使用slaveof no one命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用slaveof命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
-----------------------------------------------------------------------------------------------------------------

三、安全

1.可信的环境

    Redis的安全设计是在“Redis运行在可信环境”这个前提下做出的,在生产环境运行时不能允许外界直接连接到Redis服务器上,而应该通过应用程序进行中转,运行在可信
的环境中是保证Redis安全的最重要方法。
    Redis的默认配置会接受来自任何地址发送来的请求,即在任何一个拥有公网IP的服务器上启动Redis服务器,都可以被外界直接访问到。要更改这一设置,在配置文件中修
改bind参数,如只允许本机应用连接Redis ,可以将bind参数改成:
bind 127.0.0.1
    bind参数只能绑定一个地址,如果想更自由地设置访问规则需要通过防火墙来完成.

2.数据库密码

    除此之外,还可以通过配置文件中的requirepass 参数为Redis设置一个密码。例如:
requirepass TAFK(@^!ji^XAL}[sYhSxIWTn5}$s7JF
    客户端每次连接到Redis时都需要发送密码,否则Redis会拒绝执行客户端发来的命令。例如:
redis>GET foo
(error) ERR operation not permitted
    发送密码需要使用auth命令,之后就可以执行任何命令了 就像这样:
redis>AUTN TAFK(@ ji"7CA1." [s7Ch5xIrTn5n$a7,T}
OK
    由于Redis的性能极高,并且输入错误密码后Redis并不会进行主动延迟(考虑到Redis的单线程模型),所以攻击者可以通过穷举法破解Redis的密码(1秒内能够尝试十几万个密码),因此在设置时一定要选择复杂的密码。
    提示:配置Redis复制的时候如果主数据库设置了密码,需要在从数据库的配置文件中通过masterauth参数设置主数据库的密码,以使从数据库连接主数据库时自动使用auth命令认证。

3.命名命令

    Redis支持在配置文件中将命令重命名,比如将flushall命令重命名成一个比较复杂的名字,以保证只有自己的应用可以使用该命令口就像这样:
rename-command FLUSHALL oyfekmj}mwxq5a9c8usofuo369x0it2k
    如果希望直接禁用某个命令可以将命令重命名成空字符串:
rename-command FLUSHALL ""
    注意:无论设置密码还是重命名命令,都需要保证配置文件的安全性,否则就没有任何意义了。

---------------------------------------------------------------------------------------------------------------

四、通信协议

    Redis通信协议是Redis客户端与Redis之间交流的语言,通信协议规定了命令和返回值的格式。了解Redis通信协议后不仅可以理解AOF文件的格式和主从复制时主数据库向从数据库发送的内容等,还可以开发自己的Redis客户端(不过由于几乎所有常用的语言都有相应的Redis客户端,需要使用通信协议直接和Redis打交道的机会确实不多)。
    Redis支持两种通信协议,一种是二进制安全的统一请求协议(unified request protocol),一种是比较直观的便于在telnet程序中输入的简单协议。这两种协议只是命令的格式有区别,命令返回值的格式是一样的。
1.简单协议
    简单协议适合在telnet程序中和Redis通信。简单协议的命令格式就是将命令和各个参数使用空格分隔开,如"exists foo"等。由于Redis解析简单协议时只是简单地以空格分隔参数。所以无法输入二进制字符。我们可以通过telnet程序测试;

changwen@ubuntu:~/redis-3.2.5/src$ telnet 127.0.0.1 6379Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.set foo bar+OKget foo$3barlpush plist 1 2 3:3lrange plist 0 -1*3$13$12$11errorcommand-ERR unknown command 'errorcommand'
    我们在telnet程序中输入的5条命令恰好展示了Redis的5种返回值类型的格式,这些展现形式是经过了redis-cli封装的,而上面的内容才是Redis真正返回的格式.下面分别介绍。
1).错误回复
    错误回复(error reply)以-开头,并在后面跟上错误信息,最后以\r\n结尾:
-ERR unknown command 'errorcommand'\r\n
2).状态回复
    状态回复〔status reply)以+开头,并在后面跟上状态信息,最后以\r\n结尾:
+OK\r\n
3).整数回复
    整数问复(integer reply)以:开头,并在后面跟上数字,最后以\r\n结尾:
:3\r\n
4).字符串回复
   字符串回复(bulk reply)以$开头,并在后面跟上字符串的长度,并以\r\n分隔,接着是字符串的内容和\r\n:
$3\r\n
5).多行字符串回复
    多行字符串回复(multi-bulk reply)以*开头,并在后面跟上字符串回复的组数,并以\r\n分隔。接着后面跟的就是字符串回复的具体内容了:
*3\r\n$1\r\n3\r\n$1\r\n2\r\n$1\r\n1\r\n

2.统一请求协议
    统一请求协议是从Redis 1.2开始加入的,其命令格式和多行字符串回复的格式很类似,如SET foo bar的统一请求协议写法是“*3\r\n$3\r\nset\r\n$3\r\n  foo\r\n$3\r\nbar\r\n”。还是使用telnet进行演示:

changwen@ubuntu:~/redis-3.2.5/src$ telnet 127.0.0.1 6379Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.*3$3set$3  foo$3bar+OK
    同样发送命令时指定了后面字符串的长度,所以命令的每个参数都可以包含二进制的字符。统一请求协议的返回值格式和简单协议一样,这里不再赘述。
    Redis的AOF文件和主从复制时主数据库向从数据库发送的内容都使用了统一请求协议。如果要开发一个和Redis直接通信的客户端,推荐使用此协议。如果只是想通过telnet向Redis服务器发送命令则使用简单协议就可以了。

-------------------------------------------------------------------------------------------------------------

五、管理工具

1.redis-cli
   是Redis自带的命令行客户端。redis-cli可以执行大部分的Redis命令,包括查看数据库信息的info命令,更改数据库设置的config 命令和强制进行RDB快照的SAVE命令等,下面会介绍几个管理Redis时非常有用的命令。
1).耗时命令日志
    当一条命令执行时间超过限制时,Redis会将该命令的执行时间等信息加入耗时命令日志(slow log)以供开发者查看.可以通过配置文件的slowlog-log-slower-than参数设置这一限制,要注意单位是微秒(1 000 000微秒相当于1秒),默认值是10 D00。耗时命令日志存储在内存中,可以通过配置文件的slowlog-max-len参数来限制记录的条数。
    使用slowlog GET命令来获得当前的耗时命令日志,如;
每条口志都由以下4个部分组成:
(1)该日志唯一ID:
(2)该命令执行的UNIX时间;
(3)该命令的耗时时间,单位是微秒:
(4)命令及其参数.
    提示:为了产生一些耗时命令日志作为演示,这里将slowlog-log-slower-than参数值设置为0,即记录所有命令.如果设置为负数则会关闭耗时命令日志。
2).命令监控
    Redis提供了monitor 命令来监控Redis执行的所有命令,redis-cli同样支持这个命令,如在redis-cii中执行monitor :
redis>monitor
OK
    这时Redis执行的任何命令都会在redis-cli中打印出来,如我们打开另一个redis-cli执行SET foo bar命令,在之前的redis-cli中会输出如下内容:
1355805981.885237[0 127.0.0.1:57339] "SET" "foo" "bar"
    monitor 命令非常影响Redis的性能,一个客户端使用monitor 命令会降低Redis将近一半的负载能力。所以MONITOR命令只适合用来调试和纠错。

2.phtRedisAdmin
    Redis同样有一个PHP开发的网页端管理工具phpRedisAdmino。phpRedisAdmin支持以树形结构查看键列表,编辑键值,导入/导出数据库数据,查看数据库信息和查看键信息等功能。
1).安装
get clone https://gethub.com/ErikDubbleboer/phpRedisAdmin.git
cd phpRedisAdmin
    phtRedisAdmin依赖PHP的Redi客户端redis,所以还需要执行下面两个命令下载Redis:
git submodule init
git submodule update
2).配置数据库连接
    下载完phpRedisAdmin后需要配置Redis的连接信息。默认phpRedisAdmin会连接到127.0.0.1,端口6379,如果需要更改或者添加数据库信息可以编辑includes文件夹中的config.inc.php文件。
3).使用phpRedisAdmin
    安装PHP和Web服务器(如Nginx),并将phpRedisAdmin文件夹存放到网站目录中即可访问,如图所示。    
    phpRedisAdmin自动将kedis的键以“:”分隔并用树形结构显示出来,十分直观。如post:l和post:2两个键都在post树中。
    点击一个键后可以查看键的信息,包括键的类型、生存时间及键值。并且可以很方便地编辑。
4).性能
    phpRedisAdmin在获取键列表时使用的是KEYS*命令,然后对所有的键使用TYPE命令来获取其数据类型,所以当键非常多的时候性能并不高(对于一个有一百万个键的Redis数据库,在一台普通个人计算机上使用KEYS*命令大约会花费几十毫秒)。由于Redis使用单线程处理命令,所以对生产环境下拥有大数据量的数据库来说不适宜使用phpRedisAdmin管理。

3.Rdbtools
    Rdbtools是一个Redis的快照文件解析器,它可以根据快照文件导出JSON数据文件、分析Redis中每个键的占用空间情况等。Rdbtools是使用Python开发的。
1).安装Rdbtools
    使用如下命令安装Rdbtools
git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-reb-tools
sudo python setup.py install
2).生成快照文件
    如果没有启用RDB持久化,可以使用SAVE命令手动使Redis生成快照文件。
3).将快照导出为JSON格式
    快照文件是二进制格式,不利于查看,可以使用Rdbtools来将其导出为JSON格式,命令如下:
rdb --command json /path/to/dump.rdb > output_filename.json
其中/path/to/dump.rdb是快照文件的路径,output_filename.json为要导出的文件路径。
4).生成空间使用情况报告
    Rdbtools能够将快照文件中记录的每个键的存储情况导出为CSV文件,可以将该CSV文件导入到Excel等数据分析工具中分析来了解Redis的使用情况。命令如下:
rdb -c memory /path/to/dump.rdb > output_filename.csv
    导出的CSV文件的字段及说明如表所示。





0 0
原创粉丝点击