代码改变世界

数据库损坏指南(1)--概述

2023-01-20 09:31  abce  阅读(140)  评论(0编辑  收藏  举报

一、概念与类比

对于数据库,它是关于存储在磁盘上的数据的格式。当数据库产品(如PostgreSQL、MySQL或MongoDB)对磁盘进行写操作时,会使用某种格式来执行。当从磁盘读取数据时,数据库产品期望磁盘上数据的格式相同;磁盘上的任何部分数据格式不合适就是损坏。

总的来说,损坏只是一种不恰当的格式或数据序列。

损坏是不可读的数据格式的结果。我们知道,数据是以位(bit)的形式存储在磁盘上的。现在,在整数或数字的情况下,转换很简单。但是对于字符,每台机器都被设计成以字节(byte)的形式转换数据,字节是一组8位,每个字节都代表一个字符。从00000000(0)到11111111(255),每个字节有256种不同的组合。

为了以字符的形式读取字节,设计了一些格式,如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?被存储为How are you¿,字符"¿"在英语中是不可用的,因此那些只能解析英语的字符集可能无法识别该字符。因此,它将无法读取该文本,并通过将其标记为不可读而抛出错误。在这里,只有一个字符无法识别,但整个文本将被标记为损坏的数据。

 

二、产生的原因

这点很神奇,因为我们可能永远都不知道任何损坏的真正原因。正如我上面提到的,损坏归因于比特/字节的变化,但是很难确定是哪个进程/线程导致了这种变化。这就是为什么任何与损坏相关的测试用例实际上都是不可复制的。我们唯一能做的就是找出可能的原因。

一些可能的原因如下:

·硬件问题

当RAID盘设计不合理或控制器故障时,可能会导致硬盘无法正常写入数据。在非raid硬盘中,机械设备也应该正常工作,因为硬盘故障也会导致比特无法正常存储。

严重的I/o也可能导致损坏。

·操作系统的Bug

有时,由于内核或代码有问题,操作系统会错误地对数据进行编码,然后将其写入磁盘。有时,I/o的效率很低时,操作系统会产生损坏的数据。

·数据库产品中的Bug

在有些情况下,数据库产品本身有时会在磁盘上存储错误的数据,或者由于低效的算法,它以错误的格式保存数据。

 

三、损坏的种类

每个数据库都包含不同类型的文件,例如数据文件、WAL文件、提交日志等等。这些文件包含各种数据库对象的数据,如表、索引、物化视图、WAL记录等。当这些数据库文件损坏时,一些查询会检索错误的数据或返回错误,

或者一些操作(例如恢复,重放)可能无法正常工作。作为一名DBA,需要确定哪些特定的对象会因为这种损坏而受到影响。为便于理解,将损坏分为不同类型;其中一些如下所示:

·数据损坏:

当data/toast页面存储错误的数据(就格式而言)时,在读取时可能会变得无法识别。因此,数据库会报错。

·WAL损坏:

WAL/Redo/Transaction日志文件以特定的格式存储数据,当读取它们时,WAL条目被解析和应用。在WAL损坏的情况下,WAL条目是不可解析的,这会影响WAL应答操作。

·页头损坏:

数据库中最底层的存储单位是块/页,它实际存储实际记录。为了保持数据完整性,一些信息存储在称为页头的单独部分中。页头中的任何不当信息都是页头损坏。这会影响数据的完整性。

四、总结

在磁盘上存储数据时,比特/字节的变化会导致损坏。当一个数据库产品(例如MySQL, PostgreSQL)没有得到预期格式的数据时,就是发生数据损坏。

数据库中的数据可能由于各种原因而损坏,例如硬件故障和有bug的OS/内核/数据库产品​。