如何实现事务的持久性
对于单节点数据库, 持久性通常意味着数据已被写入非易失性存储设备,比如硬盘 或 SSD。在写入执行过程中,通常还涉及预写日志等 ,这样万一磁盘数据损坏还可以进行恢复。
而对于支持远程复制的数据库, 持久性则意味着数据已成功复制到多个节点。
为了实现持久性的保证,数据库必须等到这些写入或复制完成之后才能报告事务成功提交。
完美的持久性是不存在的。如果所有的硬盘和所有的备份同时都被销毁了, 那么数据库也无能为力。
持久性最早意味着是写入磁带来存档,之后演变为写入 磁盘 或 SSD。最近,持久性又代表着多节点间复制。没有哪一项技术可以提供绝对的持久性保证。这些技术都只是帮助降低风险的手段, 应该组合使用这些持久化技术,包括写入磁盘、 复制到远程机器以及备份等。
事务重做日志 Redo Log
数据写入到磁盘中其实是非常消耗性能,并且随机写入比顺序写入的性能更差,如果将每一个事务所有的操作结果,都实时并且随机写入到非易失性存储设备中,那么这样的数据库性能非常差。
所以,我们可以先将事务的操作结果存储在内存中,然后将操作结果顺序写入日志文件中,这样就避免了事务的操作结果随机写入磁盘的性能问题了。
事务的操作结果存储在内存,并且操作结果顺序写入日志文件,然后再提交事务,这样一来,哪怕事务提交后,机器突然崩溃了,在机器故障恢复后,系统仍然能够通过日志文件,恢复已经提交的事务的操作结果。
所以,通过顺序写入日志的形式,避免了非易失性存储设备随机写入性能差的问题,并且达到了事务提交时,事务的操作结果都写入存储设备的目的。
这个日志叫做:重做日志(Redo Log)。
日志:Redo Log 和 Undo Log
通过数据冗余进一步提高数据的持久性
只通过 Redo Log 或 WAL,不能完美地解决数据持久性的问题。
虽然 Redo Log 能保证在机器故障恢复后,系统仍然能够通过日志文件,恢复已经提交的事务的操作结果,但是当存储设备出现故障(比如数据都不可读),那么 日志文件 和 持久化数据 都有可能丢失。
因此我们需要通过数据冗余进一步提高持久性。
数据冗余方案的实现思路有两个:
- 磁盘阵列:在磁盘内部冗余数据
- 增加副本:网络复制数据
磁盘阵列
通过磁盘阵列,从磁盘内部通过冗余数据来解决。比如 RAID 1,我们将多块硬盘组成一个磁盘阵列,磁盘阵列中每块磁盘都有一个或多个是副本磁盘。事务的每一次写入都同时写入所有的副本硬盘,这样只要不是所有的副本磁盘同时出现故障,我们都可以正常从磁盘上读到数据,不会影响数据的持久性。
还有一种磁盘阵列的方式是 RAID 5 ,它是通过冗余校验数据的方法来保障持久性。
增加副本
磁盘阵列的方法确实可以解决数据的持久性问题,但是由于磁盘阵列上多块硬盘的地理位置通常都是在一起的,这样如果出现自然灾害(比如地震、火灾和洪水等),可能会导致整个磁盘阵列上的硬盘都不可用,那么就不能保证数据的持久性了。
对于地理位置相近的问题,我们可以使用增加副本的方式解决。
数据通过网络复制,将副本分布到不同的数据中心、城市或者大洲,进一步提高数据的持久性。
提高持久性:双机架构 & Binary Log