您的位置:首页 > 数据库 > Redis

redis笔记2--数据持久化和集群

2017-03-24 11:15 302 查看

数据持久化

数据持久化的用处:

1.恢复数据。
2.减少数据的运算,如:从关系型数据库加载数据到redis后,redis服务重启时不需要在去关系型数据库获取数据,直接读取硬盘上的备份即可。

快照方式



记录某个时刻的数据到硬盘上。
注意:快照这种方式,在上次快照保存后,下次快照保存之前,这之间写入redis的数据,如果redis服务崩溃了,这部分数据会丢失
启动快照的方法:

在客户端执行 bgsave命令,redis会新建一个子线程去保存快照,父线程继续响应执行各个命令。
客户端执行 save 命令,阻塞式,redis会停止任何命令的执行,直到快照保存完成。一般我们没有足够的内存来执行bgsave或是允许等待save存储快照完成的情况下执行该命令。
配置文件中配置save 参数。如:save  60 10000 ,每分钟至少10000次操作,redis会自动触发bgsave操作。
redis服务器接收到了shutdown命令,redis会执行save命令,同时阻止客户端再执行任何命令,然后关闭。
如果redis服务器连接了另一个redis服务器,并且执行了sync命令,主机会执行bgsave 操作来备份数据。

几种常见场景下的配置:

开发环境(development)

作为开发服务器,我们关心的是最小化快照的存储。一般可以设置规则为:save  900  1  。每15分钟保存一次。
触发保存快照的原则就是:不能触发太频繁,会耗费很多资源。也不能不触发或触发太少,容易丢失数据。

记录日志(aggregating logs)

为了恢复损失的数据,首先,我们需要知道我们丢失了什么数据。因此我们要记录操作信息到日志中。假如我们有一个函数,每当新的日志准备好处理时,就会调用这个函数。这个函数提供redis连接,日志文件路径,回调函数三个参数。在回调函数中,我们可以向日志中写入操作记录。(每次保存快照后,就新建一个日志文件,记录这次快照结束到下次快照保存之前这段时间内的操作记录。)

通过记录程序日志,我们就可以在服务器宕机后及时恢复丢失的数据。因为我们是pipeline中使用了事务控制,所以日志文件中只会记录执行完成的命令,不会记录处理了一部分的信息。

大数据(big data)

当我们存储的数据上GB时,使用快照方式会比较合适。但是随着内存占用的持续增长,执行bgsave操作的时间也会持续增加。

如果redis用了10多GB的内存,导致没有多余的内存来执行bgsave命令。可能会造成系统停止等一系列问题(从而降低系统性能甚至造成系统不可用)。

为了防止这种问题,我们需要停止自动保存快照功能,通过手动去调用save或是bgsave命令。如果是save命令,redis会阻塞直到快照保存完成。这种情况不会像bgsave一样去创建子线程处理备份,这样就不会有创建子线程的延迟,也不会有子线程和自己争夺资源,所以save命令会更快速的完成备份工作。
作者经验:

当redis服务器上有50GB数据时。使用bgsave命令,创建子线程需要花费大概15秒钟或更久,然后保存快照需要大概15-20分钟。如果是使用save命令,只需要3-5分钟即可。

实际运用中,每天凌晨3:00保存一个快照。通过脚本去停止客户端的连接,然后调用save命令去保存快照,保存完后再恢复客户端连接。
总结:

当我们可以处理潜在的数据丢失时,使用快照很方便。但是如果我们不能容忍15min或1hr或更大量的数据丢失时,使用append-only file方式来持久化会是比较好的选择。

AOF方式(append-only file)



每当有写命令执行时,记录命令到日志文件中,当server重启时,将这些写操作重新执行一遍。这种方式会记录每一次修改,最大限度保证数据的完整性。

这种方式,会记录每一次的数据改动到日志文件中,每次需要恢复数据,就将日志记录的信息从头到尾再执行一遍。
通过设置appendonly  yes 参数

文件同步(File Syncing)

当将文件保存到硬盘上时,过程如下:
1.调用file.write()方法,将内容写到缓存中。
2.调用file.flush(),将缓存中的数据刷新保存到硬盘。(程序只是发送一个写磁盘的请求,具体有操作系统去执行,会阻塞。执行完后数据就保存在磁盘上了)。
appendfsync:参数配置

always:每次redis的写命令都会触发保存记录到磁盘,可以保证最小的数据丢失,但是会影响redis性能(由于频繁的io操作)。
everysec:每秒同步一次,明确同步写命令到磁盘
no:让操作系统控制同步到磁盘
作为中和的选择,可以设置为everysec。在保证数据安全的同时也能提供一个不错的性能。对大多数普通应用来说,每秒同步和不做持久化相比,这之间没有多大的性能损失(即每秒同步不会造成明显的性能损失)。

当硬盘跟不上写入数据的速度时,redis会减缓写入速度来适应硬件驱动的最大写入效率。

no选项不建议使用。

这种情况下,完全交给操作系统处理,不会有性能上的损失,但是一旦发生宕机,丢失的数据我们无法获取或预测。而且,如果我们用的硬盘写入速度不够快,redis会执行到缓存区写满了才刷新到硬盘,这会导致redis变慢,在向磁盘写数据的时候也会阻塞。

append-only files 方式很灵活,缺点就是附件文件比较大。

重写/压缩aof文件

通过附加文件(append-only files)的方式,我们可以最小化数据丢失,并且最小化持久化数据到硬盘的时间。
但是随着时间的推移,aof文件会持续增长。可能造成磁盘空间不足。更常见的是,当我们重启redis服务器时,会重新执行aof日志文件里的命令,当aof文件很大时,启动redis会花费很长时间。

为了解决这个问题:

使用bgrewriteaof命令:会删除重复的命令。执行方式域bgsave命令类似。

创建一个子线程,重写附加文件(快照中的问题,子线程时间延迟,内存消耗同样存在,并且更严重。因为aof文件可能是快照文件dump的好几倍)

当aof重写时,操作系统需要删除aof文件,删除10多GB的文件会导致系统挂起数秒钟。
配置文件方式调用重写:

auto-aof-rewrite-percentage 100:表示当aof文件比上次增长了一倍(100%)时
auto-aof-rewrite-min-size  64mb:aof文件至少有64mb大

如果重写太频繁,可以适当调整参数(将100调大),尽管可能造成redis重启花费更长时间。

如果允许,建议备份快照和最新的重写的aof文件到其他服务器。

集群

集群在关系型数据库中很常见,主机(master)发送写数据到多个从机(slaves),从机执行所有的查询命令。redis也采用了这种模式。

           虽然redis速度很快,但是任然有很多场景下,光单机的redis提供服务是不够的。实际应用中,对set和zset集合的操作可能涉及成千上万,甚至上百万条数据。当涉及到上百万条数据时,set集合的 操作会花费数秒。

            
            在主机向集群中其他服务器发送初始化数据拷贝后,客户端向主机写入数据,都会同步更新到从机上。以后查询都是通过负载均衡连接到其中的一个从机去查询,而不是直接连接主机了。

集群配置

当从机连接到主机时,主机会执行一个bgsave操作。为了配置集群,需要保证快照配置中的dir和dbfilename参数正确有效,且可读。

尽管从机自己有很多控制状态的配置选项,其中只有一个选项是真正需要的:slaveof  host  port。当redis启动时,就会把这个地址的机器当作主机去连接。如果是一个运行中的系统,可以通过slaveof  host  port命令去操作。



slaveof  no  one :停止与主机的同步更新

集群启动过程

概述:当slave连接master时,master会立刻保存一个快照,然后发送给slave。
详细步骤:



        在集群中,redis会设法保持大多数的服务器同步,除了网络带宽不够快的情况,或者是主机没有足够的内存空间来创建子线程进行快照保存,或是记录积压的写命令的内存不够。
        尽管不是必须,但是最好还是保证redis主机只用了系统50-65%的内存,预留出30-45%的备用内存空间来执行bgsave命令和记录积压命令(command backlogs)

slave的配置很简单,可以在配置文件中配置slaveof host port,或是在运行的时候执行slaveof命令。
           如果用的是配置文件方式,redis在启动初始化时就会先加载快照或aof文件,然后连接到主机执行上面表中的流程。如果是命令方式,redis会立刻连接主机,如果连接成功,就会执行上面表中的流程。

同步过程中,slave会刷新所有的数据

就是为了保证数据一致性:当slave连接到master时,任何当前内存中保存的数据都会被清除,替换成从master机器发送过来的数据。

警告:redis不支持主机和主机之间的复制

有时候可能会出现下面这种配置:两台redis服务器相互做主从关系(都配置slaveof指向对方)。显然这种配置是不起作用的。两台机器会来回通信,依赖于我们连接哪台机器去查询,可能会导致我们获取的数据不一致或者根本获取不到数据。

当多个slave尝试去连接redis时,可能会有不同的情况发生



         对大多数情况,redis会保证只做必要的工作。某些情况下,slave会在不恰当的 时机去连接主机,这样会导致主机做更多的工作。另一方面,多个slave在同时连接主机时,最初用来保证slave同步的带宽会占用很多资源,可能造成其他的命令很难通过,同时可能造成网络速度变慢,影响同一网络下的其他设备。

主/从服务器链(Master/slave chains)

        当我们去添加很多个slave节点时,会发现有时候网络跟不上(尤其是在互联网上或是两个数据中心之间)。由于主机和从机之间没有什么区别,slave节点也可以有自己的slave节点,这样就可以形成主/从服务器链
         当读负载明显高出写负载时,或者是当读数据的请求量超出了一个单机redis的处理范围。常见的处理方法就是给主机添加从节点来分摊压力。
         当负载持续增长时,总会有某一个时刻,单个的redis主机服务器无法及时同步数据到所有的slave节点(或者是在同步或连接是超载了)。为了缓解这种问题,我们可以建立一个能够进行主/从复制的中间层的redis节点,如下图:



        说回aof数据备份方式,这种方式会同步所有的写操作到硬盘中,以此防止数据的丢失,但是也严重限制了服务器的性能。或者设置成每秒同步一次,性能会好很多,但是可能丢失这一秒钟内的数据。
        对于上面的问题,可以结合使用集群复制和aof文件备份方式来解决上面的问题。
        为了保证数据存放在多个机器的磁盘上,必须显示的设置主机和从机。通过配置appendonly  yes和appendfsync  everysec两个参数,可以使这组集群机器每秒同步数据到硬盘。但是我们必须等待数据一一同步到各个从节点。

验证硬盘写操作(verifying disk writes)

要检查写入主节点的数据是否同步到了从节点很简单,只需要在每次重要数据操作之后都输出一个唯一的临时文件,然后在slave节点上去验证这个文件。
通过
        info
命令查看redis服务器的各个状态信息

系统故障处理(handling system failures)

            如果我们将redis作为我们应用的唯一数据库,就必须保证我们永远不丢失数据。不像传统数据库的4个特性:原子性(atomicity),一致性(consistency),隔离性(isolation)和持久性(durability)。redis需要做一些额外的工作来保证数据的一致性。

1.验证快照和aof文件

         当系统崩溃时,我们有工具来帮助自己恢复数据。
redis-check-aof   :检测aof文件的状态
redis-check-dump    :检测dump快照文件的状态



          如果提供了--fix参数,命令就会修复这个参数指定的aof文件。通过扫描aof文件,查找未完成或错误的命令,从第一个错误的命令开始,丢弃后面所有的部分。
          目前没有修复损坏的快照文件的工具,尽管我们同样可以发现第一个错误命令发生的地方,但是因为快照本身被压缩了,中途错误可能导致文件不可读取。由于这个原因,建议对重要的快照文件保留多个备份,在恢复的同时通过计算sha1和sha256来验证内容。
         checksums  and  hashes:CRC family checksum适合发现网络传输或磁盘损坏的错误。hash密码适合发现任意的错误。

2.替换故障的主机(replacing a failed master)

场景:
          A机器跑了一个redis的master节点,B机器跑了一个slave节点。由于某些目前无法确定的原因,A机器失去了网络连接。但是我们有一个C机器安装了。
方案:
         B机器执行save命令,保存当前最新的快照文件,拷贝快照文件到C
机器的指定目录。启动C机器加载快照数据到内存中。告诉B机器去连接C机器,作为其slave几点。

B机器执行save命令
拷贝dump.rdb到C机器的redis目录下
启动C机器
B机器执行slaveof  host  port 指向C机器。
关键字:redis  sentinel(哨兵):该工具可以自动检测处理节点宕机的情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: