数据库如果断电,我们需不需要慌?

#

生产环境我们时时刻刻在向数据库发送着写入、新增、删除数据的请求,不知道各位有没有和我一样的顾虑,如果服务器突然断电或者死机,数据会不会丢失,甚至数据库会不会挂了再也无法恢复?

心大的同学可能会说,我们生产环境的数据有副本,不用慌!

那么正在写入中的数据呢?写入请求发给了数据库,还没收到成功/失败的响应,这时候数据库断电,你慌不慌?

Untitled

当然,作为数据库,自有它保障数据安全的方式,只要做好了合适的配置,就可以应对断电的情况。

今天我们就以 Elasticsearch 和 MySQL 为例来了解下数据库是如何保障数据安全的。

# 原理

# Elasticsearch

数据在 lucene 中的主要写入流程上如下图所示,

Untitled

从图上可以看出,只有 segment 落盘了,数据才是真正安全的。但是这会带来一个比较严重的问题:在 refresh 之后,commit 之前,数据已经可以被用户查到,然而断电后数据丢失,重启后这个数据无法被搜到。

因此 es 设计了translog,每次数据的写入,会在分词、加入倒排索引等重逻辑的 lucene 操作之前,数据的原始信息率先写入 translog。这就是 WAL (write-ahead-logging) 机制。

有了 translog 后,即使是没有落盘到 segment 的数据,崩溃想要恢复也有了依据,如下图所示,前2个阶段依靠 translog 恢复。

Untitled

当然 translog 文件本身也会有 fsync 的问题,可以通过配置选择 translog 文件 fsync 的时机,而这个时机最终决定了数据的可恢复性。

Untitled

Elasticsearch 比较常见的设置是:

index.translog.durability=async

index.translog.sync_interval=5s

这样配置下,最多可能丢失 5s 的数据。而 Elasticsearch 要保障数据支持崩溃恢复,比较极端的追求崩溃恢复的设置为:

index.translog.durability=request

每个 request 都会进行数据落盘。

# MySQL

数据更新操作在 MySQL中的流程如下图所示,

Untitled

其中崩溃恢复的核心是 redo log,innodb_flush_log_at_trx_commit 参数设置为 1 时,可以保障每次事务 commit 的时候 redo log 刷到磁盘。

Untitled

# 对比

#

  1. 为了提升性能,都充分利用了内存。由此也提升了数据安全问题的复杂度,需要保障内存中的数据在断电丢失后,有办法进行恢复。
  2. 为了解决上面的问题,都利用了 WAL (write-ahead-logging) 机制。
  3. 都需要关注 log 何时 fsync 到磁盘。

#

  1. log 作用不同:
    • Elasticsearch 的 translog 用于崩溃恢复
    • MySQL 的 redo log 用于崩溃恢复
    • MySQL 的 binlog 不支持崩溃恢复,主要用于数据的增量备份。可以支持主从复制,可以支持数据回溯,配合全量的快照,可以回到之前某一时刻的状态。
  2. log 内容不同:
    • translog 记录请求原始信息。
    • redo log 记录结构化之后的,具体 page 中的修改信息,详情可以参见庖丁解InnoDB之REDO LOG
    • binlog 记录的内容和 translog 更为类似,它的 statement 格式记录的是原始语句。
  3. log 保存时长不同:
    • translog 在每次 flush 完后都会清空,体积很小。
    • redo log 循环使用ib_logfile0、ib_logfile1… 体积也不会特别大。(仅讨论 crash-safe 问题的话,这一点应该属于相同点)
    • binlog 可以保存很久,时长完全取决于用户想要数据可追溯多久。

我们再重点关注下为什么 translog 和 redo log 同样用于 crash-safe,但记录的信息不同。

我想了很久,苦寻无果后翻阅 lucene 文档中查找 translog 信息时突然想起来,其实这个问题很简单。

因为他们所处的层级不同。

Elasticsearch 以 lucene 为引擎,但 lucene 本身没有 translog,因此 Elasticsearch 要在较高层级记录请求信息。而 InnoDB 作为 MySQL 的引擎,自身就可以拿到本次请求的数据结构化之后的信息。

Untitled

# Review

  1. 面对业界共同的问题,总是有相似的解决方案可供参考。

  2. 弄清楚自己的需求和实际的数据库配置之后,数据库的服务器断电不用慌。

  3. 回到我们最开始的一张图,数据库虽可以做到 crash-safe ,但不代表我们对重要业务可以把心放到肚子里。因为:

    1. MySQL 对在 crash 后对事务是否需要数据恢复的依据是 binlog 是否完整,无论 redo log 是否达到了 commit 状态,即无论这个事务是否最终提交完成,响应是否到达客户端。
    2. 图上的 request / response 其实本身就并不可靠。

    因此对于极其重要的业务来说,极端场景的业务完整性仍然需要保持关注。

    Untitled