Redis persistence demystified - part 1
关于Redis我的一部分工作是阅读博客,论坛以及twitter时间线(time line)。对于开发者来说,能够了解用户社区,非用户社区如果理解他正在开发的产品是非常重要的。据我所知,持久化特性是最易产生误解的Redis特性。
这篇博客中,我会尽力客观公正,不为Redis做宣传,不忽略可能让Redis出丑的诸多细节。我所期望的仅是说明Redis持久化机制,可靠性,以及和其他数据库系统相比较的优势。
操作系统与磁盘
首先需要考虑的是数据库的耐用性(durability)。为此,我们看看一个简单的写操作实现过程:
1. 客户端发送一个写入命令到数据库(数据在客户端内存中)
2. 数据库收到这个写入命令(数据在数据库内存中)
3. 数据库调用系统调用将数据写到磁盘上(数据在内核的buffer中)
4. 操作系统将写Buffer转交到磁盘控制器(数据在磁盘cache中)
5. 磁盘控制器实际将数据写入物理媒质(磁盘或者闪存)
注:上面仅是一个简化过程,实际上存在更多级的缓存。
实际数据库实现中,步骤2常常是一个复杂的缓存系统,有时写入是由不同线程或者进程处理的。然后数据库最终会将数据写入磁盘,以我们的角度看,这一点是有意义的地方。那就是,数据将从内存传送给内核(步骤3) - 或许理解为从用户空间到内核空间更合适一点。
另一个容易忽略细节的步骤3。更复杂的是大多数内核实现了不同层次的缓存,即文件系统级缓存(如linux中的页缓存)和一个更小的包含等待提交给磁盘的数据的buffer缓存。使用特定API可以跳过这两个缓存(如Linux的open系统调用中的O_DIRECT和O_SYNC标志),但以我们的角度看,我们可以将之视为一个不透明的缓存层(我们不知道细节)。当数据库实现了缓存,那么去使能page缓存以避免数据库和内核同时进行缓存就足够了。buffer缓存通常要打开,否则每次文件写入都要提交给磁盘,对于大多数应用来说这太慢了。
数据库通常要做的是调用系统调用,系统调用提交buffer缓存到磁盘。
什么时候我们的写操作是安全的
如果我们仅仅考虑数据库软件错误(进程被杀死或者崩溃)而不触及内核,那么写操作在成功执行完步骤3就可以认为是安全的。即write系统调用(或者其他系统调用)成功返回后。执行完这一步,即使数据库软件崩溃,内核也会负责将数据写入到磁盘控制器。
如果我们继续考虑更严重的事件,如断电,那么只有在执行完步骤5才是安全的,即当数据已经实际写入到物理设备。
我们可以认为最重要的步骤就是步骤3,4,5. 即:
数据库软件从用户空间传输数据到内核空间的频率
内核将buffer中数据写到磁盘控制器的频率
最后是磁盘控制器将数据写入物理设备的频率
注:
当我们讨论磁盘控制器时,我们实际是指磁盘控制器或者磁盘自己的缓存。在耐用性比较重要的场景,系统管理员通常去使能这一层的缓存。
对大多数系统来说,磁盘控制器默认只执行write through(只缓存读操作)。只有在有电池或者超级电容器进行断电保护的时候,激活write back模式(缓存写操作)才是安全的。
POSIX API
从数据库开发者的角度来看,我们感兴趣的是数据实际写入物理设备的过程,但最关注的是API在写入过程中所能提供的控制。
我们从步骤3开始,我们能够使用write系统调用将数据传递到内核buffer,所以我们的角度看,我们使用POSIX API尽可能的控制了数据的写入。然而,我们不能控制这个系统调用在成功返回之前所耗费的时间。内核buffer大小有限如果。如果磁盘不能应对应用程序的写入带宽要求,内核写buffer将会被耗尽,内核将会阻塞写入。当磁盘可以接收更多数据时,write系统调用才会返回。最终要实现的目标是将数据写入物理设备。
步骤4:在这一步,内核将数据传递到磁盘控制器。默认情况下,内核会尽量减少传递数据的频率,因为传递大数据块会更高效。例如,Linux默认会在write调用后30秒钟将数据提交到磁盘控制器。这意味着,如果在此期间出现失败,所有最近30秒写入的数据可能丢失。
POSIX API提供了一组系统调用强制内核将buffer中数据写入到磁盘:最有名的可能就是fsync系统调用(也可参考msync和fdatasync)。fsync为数据库系统提供了一种强制内核将数据写入磁盘的方法,但是你能想象的到,这代价不菲。只要内核buffer中有数据,每次调用fsync发起一次些操作。fsync将会阻塞调用进程,直至所有写入操作完成,在Linux系统中,如果耗时过长,其他对同一文件进行写入的线程也会被阻塞。
我们不能控制的
到目前为止,我们可以控制步骤3和4,那么步骤5呢?正式的回应是,我们不能使用POSIX API控制这一步。或许,某些内核实现将尽力告知驱动器将数据提交到物理设备,但控制器也可能为了优化写入小了对写入操作重新排序,不会立即将数据写入磁盘而是再等待几毫秒。这时我们无能为力。
在文章后面部分,我们将我们的应用场景简化为两个数据安全级别
使用write系统调用的写入的数据对进程失败是安全的
使用fsync系统调用的是对系统失败(如断电)安全的。实际上,我们知道犹豫控制器缓存我们不能保证这一点,但由于所有数据库系统都有这种问题,所以我们不考虑。此外系统管理员也常常使用特定工具以控制物理设备的行为。
注:不是所有数据库都使用POSIX API。一些私有数据库使用内核模块对硬件进行更多直接的控制。但是问题的主要特征保持不变。你可以使用用户空间buffer,内核buffer,并最终会将数据写入到磁盘以保证数据安全(是一个慢操作)。一个典型的使用内核模块的数据库是Oracle。
数据损坏:
在前一节,我们分析了系统高层(应用程序和内核)将数据写入到磁盘保障数据安全的问题。然而这仅仅是数据耐用性的一面。另外一点是:数据库(包括系统)失败后,数据库是否可读,或者其内部结构是否损坏导致数据不能正确读取,或者需要恢复工具重建数据。
例如,许多SQL和NoSQL数据库实现了某种形式的树数据结构存储数据和索引。这一数据结构将会在写操作时被修改。如果系统在写操作过程中停止工作,这一树数据结构是否仍旧正确。
一般来说,对数据损坏有三种层次的安全性:
数据库写入数据时不关心失败,让用户使用数据备份进行数据恢复,或者提供工具尽力重建数据。
数据库系统使用log操作以便在失败场景时能够重新恢复数据
数据库不修改已经写入的数据,而是仅以追加模式工作,所以不会发生数据损坏。
现在,我们了解所有评估数据库系统持久化层可靠性的因素。我们可以看看Redis的表现如何。Redis提供了两种不同的持久化选择,下面依次说明。
快照
Redis快照是最简单的持久化模式。它在某些条件满足时在某个时间点生成快照,如前一次快照2分钟后且至少有100个新的写入操作。这些条件可以通过用户配置文件实现,可以在不重启服务器的条件下修改。快照是一个单个.rdb文件,包含整个数据集。
快照的耐用性只能限定在用户指定的存储点。如果数据集每15分钟后存一次,那么在Redis实例崩溃或者更严重事件发生时,那么15分钟的写入将会丢失。从Redis事务的角度看,快照能够保证MULTI/EXEC事务可以完全写入快照,或者不写入。
RDB文件不会损坏,因为它是由一个子进程以追加的方式生成。新的rdb快照是一个临时文件,生成成功后,使用原子系统调用rename将其修改为最终文件。
Redis快照不能提供好的耐用性保证,因为在两次快照中间的可能多达几分钟的数据丢失是不可接受的,它只对不关注丢失最新数据的应用和场景适用。
然而,即使是使用另外一种更高级持久化模式-AOF时,仍旧建议打开快照功能,因为它提供的一个包含完整数据集的文件在进行数据备份时,将数据发送给其他数据中心进行灾难恢复,或者在重大软件错误严重损坏数据时进行数据回滚益处多多。
需要注意的是,Redis快照Redis使用快照实现主从同步。
仅追加文件(AOF)
仅追加文件或者简称为AOF,是主要的Redis持久化选项。它的工作方式很简单:内存中每一次修改数据集的写操作都会被写入日志。日志的格式和客户端同Redis之间的通信格式相同。因此AOF能够使用netcat经管道传递给另外一个Redis实例,或者说需要时易于解析。Redis重启时,通过重放所有操作重建数据集。
为了说明AOF如何实际工作我们做一个简单的严重,启动一个新的Redis 2.6实例并激活AOF模式:
./redis-server --appendonly yes
现在发送一个写命令给这个Redis实例。
redis 127.0.0.1:6379> set key1 Hello
OK
redis 127.0.0.1:6379> append key1 " World!"
(integer) 12
redis 127.0.0.1:6379> del key1
(integer) 1
redis 127.0.0.1:6379> del non_existing_key
(integer) 0
前三个操作实际修改了数据集,第四个没有修改,它只是试图删除一个不存在的key。下面是AOF文件的内容
$ cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
key1
$5
Hello
*3
$6
append
$4
key1
$7
World!
*2
$3
del
$4
key1
可以看到,最后一个DEL不存在,因为它没有对数据集进行任何修改。
简而言之,只有实际修改数据集的命令才会记入AOF文件。
Redis AOF仅仅时做追加操作,不会有数据损坏。但是问题是,AOF文件会不断增加,及时数据集已经被删除为空,当文件很大时怎么办呢?
Redis persistence demystified - part 1的更多相关文章
- Redis persistence demystified
https://redis.io/topics/persistence http://oldblog.antirez.com/post/redis-persistence-demystified.ht ...
- Redis persistence demystified - part 2
重写AOF 当AOF文件太大时,Redis将在临时文件重新写入新的内容.重写不会读取旧的AOF文件,而是直接访问内存中数据,以便让新产生的AOF文件最小,重写过程不需要读取磁盘. 重写完成后,Redi ...
- redis 持久化与备份策略 【转载】
本文转载自 http://blog.csdn.net/is_zhoufeng/article/details/10210353 持久化(persistence) 本文是 Redis 持久化文档 的中文 ...
- redis 持久化与备份策略
持久化(persistence) 本文是 Redis 持久化文档 的中文翻译. 这篇文章提供了 Redis 持久化的技术性描述,推荐所有 Redis 用户阅读. 要更广泛地了解 Redis 持久化,以 ...
- Redis 持久化深入--机制、可靠性及比较
本文是对 antirez 博客中 Redis persistence demystified 的翻译和总结.主要从Redis的持久化机制,提供何种程度的可靠性以及与其他数据库的比较三个方面进行讨论. ...
- 详解redis持久化
我们的Redis必须使用数据持久化吗?如果我们的Redis服务器只作为缓存使用,Redis中存储的所有数据都是从其他地方同步过来的备份,那么就没必要开启数据持久化的选项.Redis提供了将数据定期自动 ...
- Redis(7)——持久化【一文了解】
一.持久化简介 Redis 的数据 全部存储 在 内存 中,如果 突然宕机,数据就会全部丢失,因此必须有一套机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的 持久化机制, ...
- 转载:解密Redis持久化
本文内容来源于Redis作者博文,Redis作者说,他看到的所有针对Redis的讨论中,对Redis持久化的误解是最大的,于是他写了一篇长文来对Redis的持久化进行了系统性的论述.文章非常长,也很值 ...
- 【Redis】Redis 持久化之 RDB 与 AOF 详解
一.Redis 持久化 我们知道Redis的数据是全部存储在内存中的,如果机器突然GG,那么数据就会全部丢失,因此需要有持久化机制来保证数据不会一位宕机而丢失.Redis 为我们提供了两种持久化方案, ...
随机推荐
- Java Abstract class and Interface
Abstract Class 在定义class的时候必须有abstract 关键字 抽象方法必须有abstract关键字. 可以有已经实现的方法. 可以定义static final 的常量. 可以实现 ...
- iOS - OC 与 Swift 互相操作
前言 在 Swift 语言中,我们可以使用 Objective-C.C 语言编写代码,我们可以导入任意用 Objective-C 写的 Cocoa 平台框架.Objective-C 框架或 C 类库. ...
- apt-get下载的文件
1. http://kurenai.elastos.org/2013/05/02/ubuntu-apt-get%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/ http:// ...
- [转载] 理解 epoll 的事件触发机制
原文: http://weibo.com/p/1001603862394207076573?sudaref=weibo.com epoll的I/O事件触发方式有两种模式:ET(Edge Trigger ...
- wpf datagrid 如何让标头 及内容居中
头就是这么居中<DataGrid> <DataGrid.ColumnHeaderStyle> <Style TargetType="DataGridColumn ...
- CnPlugin 1.5.400
本软件CnPlugin是PL/SQL Developer工具插件,支持PL/SQL Developer 7.0以上版本.增加了PL/SQL Developer工具本身所没有的一些小功能,功能基本一些已 ...
- SQL SERVER 2008函数大全(含例子)
--SQL SERVER 2008 函数大全 /* author:TracyLee csdncount:Travylee */ /* 一.字符串函数: 1.ascii(字符串表达式) 返回字符串 ...
- VNC的安装与配置
一,安装tigervnc-server VNC软件包 [root@localhost ~]# yum install tigervnc-server 设置开机自启动 [root@localhost ~ ...
- 【服务器环境搭建-Centos】tmpfs,【转载】
转载来源:http://www.linuxidc.com/Linux/2013-12/93747.htm tmpfs介绍 tmpfs是一种虚拟内存文件系统,而不是块设备.是基于内存的文件系统,创建时不 ...
- OpenGL的视图变换、模型变换、投影变换、视口变换
产生目标场景的过程类似于用照相机进行拍照: (1) 把照相机固定在三角架上,并让他对准场景从不同位置观察场景(视图变换) gluLookAt (2) 对场景进行安排,使各个物体在照片中的位置是我们所希 ...