虽然我是作为PostgreSQL DBA写这篇文章的,但任何人都可以阅读这一页,因为每个数据库中的损坏概念都是一样的。
读完这篇博文后,我们应该了解什么是数据库损坏以及它是如何发生的。
作为DBA,我们不希望在系统中看到损坏;然而,有一些制度经常出现损坏现象。每当它出现在大型数据库中时,检测和修复它就变得很有挑战性,因为我们可能看不到任何迹象。在我15年的DBA工作经验中,我认为损坏是最难解决的问题,因为任何损坏的表面原因实际上都是不可预测的。换句话说,我们可能不知道问题的实际原因;因此,很难获得RCA。
在这一系列博客中,我将介绍各种类型的损坏以及发现和修复它们的方法。
这篇博客文章将对数据库损坏的基础知识有所帮助。
概念与类比
为了简单地解释它,我将以西班牙语为例。下图中有文本。

在这里,以上文本是西班牙语。对于任何不懂西班牙语的人来说,他们有可能阅读它吗?直截了当的答案是“不”。
任何人都会问:“一个不懂西班牙语的人怎么会读?”。为了结束这种好奇,图片用英语写着“再见”。
同样的事情也发生在软件产品上。所有软件都被编程为以其自己预定义的格式进行读写,并且可能无法以任何其他软件产品支持的任何其他格式进行读写。例如,Python代码不能在C、Java或Perl中编译、读取或执行。
就数据库而言,它是关于存储在磁盘上的数据的格式。当数据库产品(如PostgreSQL、MySQL或MongoDB)在磁盘上写入时,它会使用某种格式执行操作。
在从磁盘读取数据时,数据库产品希望在那里使用相同的格式;磁盘上数据的任何部分如果格式不合适,都将被破坏。
总之,损坏只不过是一种不正确的格式或数据序列。
这是怎么发生的?
如前一节所述,损坏是无法读取的数据格式造成的。正如我们所知,数据以位的形式存储在磁盘上。现在,在整数或数字的情况下,转换很简单。但对于字符,每台机器都被设计成以字节的形式转换数据,字节是由八位组成的一组,每个字节代表一个字符。每个字节有256种不同的组合,从00000000(0)到11111111(255)。
为了以字符形式读取字节,设计了一些格式,如ASCII、EBCDIC、BCD等。它们也称为编码方案。在所有这些方案中,ASCII(美国信息交换标准代码)更受欢迎。在这种格式中,每个字节(全部256个组合)都被分配一个特定字符。
像这样:
01000001(65) – A
00101100(44) – ,
下面是查看所有ASCII代码的链接。
https://www.rapidtables.com/code/text/ascii-table.html
在这里,如果任何字节以意外的位序列存储,机器将读取不同的字符。
例如:
假设字符A(65)存储为11000001(193),而不是01000001(65),即“Á”(不是英文字母A)。
现在,在这些提到的编码方案中,一些字符是人类可读的,其余的不是。但是,需要注意的另一点是,并非所有的软件产品都是用来破译所有字符的。因此,在任何情况下,如果任何位置的字节发生更改,则数据库可能无法读取字符,从而无法读取数据。那些不可读或不可解析的数据被视为损坏的数据。
例如:
How are you?以“你好”的形式存储,字符“?”在英语中不可用,因此那些只能解析英语的字符集可能无法识别该字符。因此,它将无法读取该文本,并通过将其标记为不可读而抛出错误。在这里,只有一个字符无法识别,但整个文本将被标记为损坏的数据。万一你怎么样?以“你好”的形式存储,字符“?”在英语中不可用,因此那些只能解析英语的字符集可能无法识别该字符。因此,它将无法读取该文本,并通过将其标记为不可读而抛出错误。在这里,只有一个字符无法识别,但整个文本将被标记为损坏的数据。
原因
这真的很神秘,因为我们可能永远不知道任何形式损坏的真正原因。如前所述,损坏归因于位/字节的变化,但很难确定是什么进程/线程导致了这种变化。这就是为什么任何与腐败相关的测试用例实际上都不可复制。我们唯一能做的就是探索可能的原因。
一些可能的原因如下。
硬件问题:
当RAID磁盘设计不正确或控制器出现故障时,它可能无法在磁盘上正确写入数据。在非RAID磁盘中,机械设备应该正常工作,因为位也由于磁盘故障而无法正确存储。
严重的I/O也可能导致损坏。
操作系统中的错误:
有时,由于内核或代码有缺陷,操作系统会错误地编码数据,然后将其写入磁盘。有时,操作系统会产生损坏的数据,而阻止I/O的效率很低。
数据库产品中的错误:
在许多情况下,产品本身有时在磁盘上存储错误的数据,或者由于算法效率低下,它以错误的格式保存数据。
损坏的类型
每个数据库都包含不同类型的文件,如数据文件、WAL文件、提交日志等。这些文件包含各种数据库对象的数据,例如表、索引、物化视图、WAL记录等。当这些数据库文件损坏时,某些查询检索错误数据或返回错误,或者某些操作(例如恢复、回放)可能无法按预期工作。作为DBA,您需要确定哪些特定对象由于这种损坏而受到影响。为便于理解,将腐败分为不同类型;其中一些如下。
索引损坏:
通常,索引在列中保留特定值(或值集)的指针。每当要求索引返回指针(PostgreSQL中的ctid,Oracle中的rowid)时,它就会获取这些指针并将其返回给请求者。
在损坏的情况下,由于磁盘上的错误位,磁盘上保存了指向任何值的错误指针。因此,它返回错误的记录。
数据损坏:
当数据/toast页面存储错误数据(就格式而言)时,在读取相同数据时可能无法识别。因此,它们会被数据库出错。
WAL损坏:
WAL/Redo/Transaction log文件以特定格式存储数据,在读取数据时,解析并应用WAL条目。在WAL损坏的情况下,WAL条目不可解析,这会影响WAL回复操作。
页眉损坏:
数据库中最低的存储单元是块/页,它实际上存储了实际记录。为了保持数据完整性,一些信息存储在称为页眉的单独部分中。页眉中的任何不正确信息都是页眉损坏。这会影响数据完整性。
总结
在磁盘上存储数据时,位/字节的变化会导致损坏。当数据库产品(例如MySQL、PostgreSQL)无法以预期的格式获取数据时,这就是损坏。
数据库中的数据可能由于各种原因而损坏,例如硬件故障和操作系统/内核/数据库产品有缺陷。因此,数据在存储到磁盘之前会意外更改。虽然它被错误地存储在磁盘上,因此文件,它影响了软件产品的各种功能;为了便于理解哪些特定领域受到影响,将损坏分为各种类型,例如索引损坏、数据损坏等。
这是数据库损坏博客系列中的第一篇文章;其他博客很快就会发布。敬请期待!
原文标题:Database Corruption: An Overview
原文作者:Ninad Shah
原文链接:https://www.percona.com/blog/database-corruption-an-overview/




