上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

一旦发生数据丢失、数据损坏,造成的影响就会非常大,这就要求业务系统有一个完善的机制以应对这些场景带来的灾难(服务器宕机、数据库崩溃或损坏、硬件故障等),比如之前的案例,2018年,腾讯云硬盘由于磁盘静默错误,导致创业公司线上生产数据完全丢失 。为此,常见的应对方式有备份、冗余、灾备、快照、高可用等等 。对于数据库来说,还有闪回等方式 。
服务器硬件简单来说就是CPU + 内存 + 磁盘(磁盘控制器也是一个重要的组成),对于一般的服务器优先级来说,主要都是受限于CPU,主要因为:网络开销(http)、虚拟机(应用服务器)、应用程序代码……


上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

文章插图
x86架构的CPU目前主流是Intel和AMD(此处只谈x86架构的CPU,毕竟现在绝大多数数据库、中间件等还是跑在x86服务器上),Intel的处理器核心速度要比AMD快,但是价格和相关部件也更加昂贵,而AMD在多核处理器的价格上更有优势,并且使用AMD处理器的服务器性能通常不错,处理器设计能够使每个核心最大程度地利用内存 。对于PostgreSQL9.6以后的版本来说,引入了并行机制,那么这种情况下AMD的优势就发挥出来了,我们可以使用一定的并行特性处理查询;对于较低的版本,那么为了尽可能快地运行,Intel就更为合适一点 。
但是,对于数据库服务器来说,就不是这样了,往往都是受限于磁盘(IO),比如:
针对大表的顺序扫描索引扫描带来的随机IO检查点、后台写等消耗IO大户ACID中的持久化...

上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

文章插图


这些都主要受磁盘的影响 。当然随着SSD等磁盘技术的平民化,以及动辄上百GB内存的普及,I/O层面的性能问题得到了有效缓解 。
花样Cache在存储系统中,Cache几乎无处不在,文件系统有Cache,存储有Cache,RAID控制器上有Cache,磁盘上也有Cache 。操作系统的写缓存一般都可以达到GB的规模,RAID控制器上的缓存一般在128MB ~ 512MB,SAN上的缓存也达到GB,磁盘上的cache,一般是16M ~ 64M 。
在PostgreSQL中,实际是在写操作后马上调用fsync(fsync = on),wal_sync_method参数则用来控制使用哪种方法进行fsync 。PostgreSQL为了保证数据的一致性,对于redo log支持Direct IO,Direct IO会绕过文件系统的Cache(对于Shared Buffer则只有Buffer IO),但是,OS不知道存储这一层,虽然绕过了文件系统层面的Cache,但是依然可能写在存储的Cache上 。一般存储都有Cache,为了提高性能,写操作在Cache上完成就返回给OS了,也即write back,为了保证掉电时Cache中的内容不会丢失,存储一般都有电池保护,这些电池可以供存储在掉电后工作一定时间,保证Cache中的数据被刷入磁盘,不会丢失 。另外一些控制器卡会监控电池的健康状况,当没有电池或电池不足时,会自动从write back切换到write through的模式 。
另外很多存储厂商都明确表示,存储中磁盘的Cache是禁用的,为了保证数据可靠性,而存储本身又提供了非常大的Cache,相比较而言,磁盘上的Cache就不再那么重要 。可以参考下面的图片,一次IO经历了多少Cache才到磁盘上 。


上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

文章插图

上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

文章插图
很多人都误认为使用write就能将数据写入到磁盘上,然而这是错误的 。一般情况下,对文件的write只会更新内存中的页缓存,这些页缓存不会立刻刷入磁盘,操作系统的 flusher线程会在满足以下条件时将数据落盘:
1)空闲内存下降到了特定的阈值,需要释放脏页占用的内存空间;
2)脏数据持续了一定时间,最老的数据就会被写入磁盘;
3)用户进程执行sync或者fsync系统调用;
如果我们想要将数据立刻刷入磁盘,就需要在执行write后立刻调用fsync等函数,当 fsync等函数返回后,数据库才会通知调用方数据已经成功写入 。PostgreSQL认为系统提供的fsync调用是可靠的,即写到了持久化的存储 。


上 建议收藏,数据库为什么会丢失数据?(数据库丢失)

文章插图
然后下面还有更底层的Raid Cache、Disk Cache等,虽说大多数Raid卡或企业级SSD可以通过电容残余的电量,将Disk Cache里的数据持久化下来,但是请不要相信所有磁盘都有这个功能 。所以这个可以叫做"说谎的驱动器",虽然返回写成功了,但是不一定实际写入了 。因此不要轻易使用易失缓存,可以使用有掉电保护的易失缓存 。在个人工作过程中,还有幸暂未遇到因为回写缓存,系统崩溃导致PostgreSQL无法使用的例子 。
至此,我们可以看到在PostgreSQL中,一个物理IO是经历了一系列的Cache之后,最终被写入到磁盘上 。
其他意外除了上面介绍的因为各种Cache的存在导致数据没有及时刷入磁盘带来的数据丢失风险,还有就是常见的人为错误 。
人为错误是造成数据丢失的首要原因 。在2018年腾讯云数据丢失事故中,我们会发现,虽然事故的起因是硬件故障,但是最终导致数据完整性受损的还是运维人员的不当操作,可以参照官方说法:https://mp.weixin.qq.com/s/8JSPY6vHPhg8pX0JwjqttQ
第一是正常数据搬迁流程默认开启数据校验,开启之后可以有效发现并规避源端数据异常,保障搬迁数据正确性,但是运维人员为了加速完成搬迁任务,违规关闭了数据校验;
第二是正常数据搬迁完成之后,源仓库数据应保留24小时,用于搬迁异常情况下的数据恢复,但是运维人员为了尽快降低仓库使用率,违规对源仓库进行了数据回收 。
因此减少人为错误的最好方式是将数据的备份和运维等操作标准化,使用自动化的流程处理涉及数据安全的操作,这样才能降低人为干预带来的风险 。
除此之外,还有不可预知的硬件错误,比如上述事件中的磁盘静默错误,一个较好的做法是部署那些已经在市场上经过长时间检验的硬件设备,这样可以通过既往经验获取较为真实可靠的硬件故障率 。这里可以看一下google的一个故障趋势调研:Failuer Trends in a Large Disk Drive Population,https://wenku.baidu.com/view/3fc77221dd36a32d7375817c.html
【上 建议收藏,数据库为什么会丢失数据?(数据库丢失)】文章部分素材源自:PostgreSQL学徒