2021-04-01

数据库的持久化等级

Views: 3250 | Add Comments

数据持久化(Durability)是数据库系统的最基础功能之一. 我们把数据写入数据库, 期望未来能从数据库中再读出来, 即使中间经过了数据库进程重启或者计算机掉电重启, 数据依然在. 但是, 持久化被划分为许多等级, 每个等级所能承受的外界变化程度(容灾能力)不同. 之所以划分持久化等级, 直接原因是因为性能(单请求的处理耗时, Response Time), 间接原因是成本.

磁盘持久化

掉电重启级别的容灾能力, 是单机系统最低限度的持久化, 所以, 把数据写入磁盘, 才能称为持久化.

如果数据只写入内存, 无论是用户进程管理的内存, 还是操作系统内核管理的内存, 都不算是持久化, 特别的, 即使写入磁盘驱动器自身的缓冲区, 也不算是持久化. 只要数据没有真正到达磁盘的硬件本体, 那么就无法容忍掉电故障, 也即所谓的断电丢数据.

标准IO提供的 write() 系统调用, 虽然常常被称为写文件, 但是, 数据一般(除非使用 DIRECT IO)仅仅是拷贝到内存(page cachre), 并没有和磁盘做任何交互, 当然不算持久化.

系统API提供了 fsync() 调用, 真正地将数据传输到磁盘, 也即真正的”写”磁盘. 所以, 当 fsync() 返回时, 一般认为数据已经持久化. 但是, 有说法[4]表明, posix fsync() 本身并没有要求持久化, 只要求操作系统将数据发送给磁盘. 所以, 如果磁盘本身有 cache, 那么我们不能期望数据已经持久化.

经过了这些理论分析之后, 我们看看实践在遇到的情况. 有不少同学说:

Redis 速度好快, 写一次数据花不了 1ms.

如果我们从数据持久化的角度去看待这个说法, 就会发现说法本身漏洞百出. 常规的 Redis 配置(aof, fsync everysec), 所谓的写数据, 仅仅是 write() 调用, 数据还在内存中, 最长要等 1 秒钟之后才调用 fsync(), 按照我们前面的分析, 也就是根本就没有做持久化, 掉电会丢数据. 而我们说”写数据速度非常快”, 其实是隐含了持久化数据的速度非常快, 显然, 这和事实不符.

有些同学说:

MySQL 的速度没有 Redis 快, 写一次数据要花 3ms.

事实如此, 因为 MySQL 采取的策略是”真持久化”, 也即数据真正地”写入”磁盘, 理论上掉电不会丢数据. 拿内存操作和磁盘操作做这种比较, 实在不严谨.

多副本持久化

单机磁盘的持久化, 虽然能容忍掉电, 但是, 如果机器永久掉电或者磁盘损坏, 数据便会丢失. 因此, 我们需要通过多副本来提供更高级别的持久化水平, 把数据通过网络复制到多台机器上, 那么即使一台机器损坏, 数据依然存在.

现在我们需要思考一个问题, 是否每一台机器都要”立即”(也即 fsync)做磁盘持久化呢? 事实上, 考虑到多台机器同时发生掉电或者内存损坏的机率, 即使所有机器都没有立即做持久化, 但只要数据到达了所有机器的内存, 我们依然可以认为数据已经持久化了. 当然, 这里面需要概率上的数字去分析.

基于概率的考虑, 特别是加上时间因素对概率的影响考虑, 我们有理由在多副本复制组的架构下采取更宽松的单机持久化策略, 例如, 定期地调用 fsync().

持久化级别对响应时间(性能)的影响

单机的真持久化依赖于 fsync, 多副本的持久依赖网络对用户, 分布式强一致性持久化一般是前两者这和, 因此它们经常被认为是”慢”的. 而通常被认为”快”的低级别持久化, 是异步持久, 有可能丢失异步过程短时间的数据.

单机异步持久化(丢数据) 单机持久化 多副本强一致持久化
慢慢

需要特别指出的是, “性能”一词并不仅仅限于响应时间(RT, Response Time), 还包括吞吐量(QPS), 所以, 快和慢不能全面地反映性能.

为什么要关注持久化等级?

用户对持久化和性能的追求不是绝对的, 是可以妥协的, 用户有时候降低持久化级别来追求更快的响应速度, 但有时候为提高持久化级别不得不放弃响应速度, 鱼和熊掌不可兼得.

弄清了持久化级别之后, 我们再针对具体的业务需求进行分析, 以决定我们选择哪种级别的持久化能力. 如果没有弄清楚, 只会犯了外行只片面追求性能的错误, 不仅贻笑大方, 还会在业务上犯错.

参考资料

  1. Can Applications Recover from fsync Failures?
  2. Power Failure Testing with SSDs
  3. Reliability Analysis of SSDs Under Power Fault
  4. Everything You Always Wanted to Know About Fsync()

Related posts:

  1. Linux 核心编程 – fsync, write
  2. Redis被bgsave和bgrewriteaof阻塞的解决方法
  3. SSDB在大数据量日志分析中的应用案例
  4. Redis 的作者狂喷某 NoSQL 数据库
  5. 在线状态服务在网站系统中的应用
Posted by ideawu at 2021-04-01 23:09:56

Leave a Comment