QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

左耳朵耗子:我对 GitLab 误删除数据库事件的几点思考

  • 2017-02-06
  • 本文字数:5891 字

    阅读完需:约 19 分钟

更多左耳朵耗子的独家干货,请订阅极客时间出品的陈皓全年专栏《左耳听风》,一次订阅、永久阅读。即日起,戳此订阅立享以下两大福利:

福利一:原价 ¥199/ 年,极客时间新用户注册立减 ¥30

福利二:每邀请一位好友购买,你可获得 36 元现金返现,多邀多得,上不封顶,立即提现(提现流程:极客时间服务号 - 我的 - 现金奖励提现)

太平洋时间 2017 年 1 月 31 日晚上,GitLab 通过推特发文承认 300GB 生产环境数据因为 UNIX SA 的误操作,已经被彻底删除(后发文补充说明已经挽回部分数据),引起业界一片哗然。知名博主陈皓在其博客中详细回顾了此次事件,并做了思考和总结,聊聊架构经原作者授权发布此文。

昨天,GitLab.com 发生了一个大事,某同学误删了数据库,这个事看似是个低级错误,不过,因为 GitLab 把整个过程的细节都全部暴露出来了,所以,可以看到很多东西,而对于类似这样的事情,我自己以前也干过,而在最近的两公司中我也见过(Amazon 中见过一次,阿里中见过至少四次),正好通过这个事来说说一下自己的一些感想和观点吧。我先放个观点:你觉得有备份系统就不会丢数据了吗?

事件回顾

整个事件的回顾 GitLab.com 在第一时间就放到了 Google Doc 上,事后,又发了一篇 Blog 来说明这个事,在这里,我简单的回顾一下这个事件的过程。

首先,一个叫 YP 的同学在给 GitLab 的线上数据库做一些负载均衡的工作,在做这个工作时的时候突发了一个情况,GitLab 被 DDoS 攻击,数据库的使用飙高,在 block 完攻击者的 IP 后,发现有个 staging 的数据库 (db2.staging) 已经落后生产库 4GB 的数据,于是 YP 同学在 Fix 这个 staging 库的同步问题的时候,发现 db2.staging 有各种问题都和主库无法同步,在这个时候,YP 同学已经工作的很晚了,在尝试过多个方法后,发现 db2.staging 都 hang 在那里,无法同步,于是他想把 db2.staging 的数据库删除了,这样全新启动一个新的复制,结果呢,删除数据库的命令错误的敲在了生产环境上(db1.cluster),结果导致整个生产数据库被误删除(陈皓注:这个失败基本上就是 “工作时间过长” + “在多数终端窗口中切换中迷失掉了”)。

在恢复的过程中,他们发现只有 db1.staging 的数据库可以用于恢复,而其它的 5 种备份机制都不可用,第一个是数据库的同步,没有同步 webhook,第二个是对硬盘的快照,没有对数据库做,第三个是用 pg_dump 的备份,发现版本不对(用 9.2 的版本去 dump 9.6 的数据)导致没有 dump 出数据,第四个 S3 的备份,完全没有备份上,第五个是相关的备份流程是问题百出的,只有几个粗糙的人肉的脚本和糟糕的文档,也就是说,不但是是人肉的,而且还是完全不可执行的(陈皓注:就算是这些备份机制都 work,其实也有问题,因为这些备份大多数基本上都是 24 小时干一次,所以,要从这些备份恢复也一定是是要丢数据的了,只有第一个数据库同步才会实时一些)。

最终,GitLab 从 db1.staging 上把 6 个小时前的数据 copy 回来,结果发现速度非常的慢,备份结点只有 60Mbits/S,拷了很长时间(陈皓注:为什么不把 db1.staging 给直接变成生产机?因为那台机器的性能很差)。数据现在的恢复了,不过,因为恢复的数据是 6 小时前的,所以,有如下的数据丢失掉了:

  • 粗略估计,有 4613 的项目, 74 forks, 和 350 imports 丢失了;但是,因为 Git 仓库还在,所以,可以从 Git 仓库反向推导数据库中的数据,但是,项目中的 issues 等就完全丢失了。
  • 大约有±4979 提交记录丢失了(陈皓注:估计也可以用 git 仓库中反向恢复)。
  • 可能有 707 用户丢失了,这个数据来自 Kibana 的日志。
  • 在 1 月 31 日 17:20 后的 Webhooks 丢失了。

因为 GitLab 把整个事件的细节公开了出来,所以,也得到了很多外部的帮助,2nd Quadrant 的 CTO – Simon Riggs 在他的 blog 上也发布文章 Dataloss at GitLab 给了一些非常不错的建议:

  • 关于 PostgreSQL 9.6 的数据同步 hang 住的问题,可能有一些 Bug,正在 fix 中。
  • PostgreSQL 有 4GB 的同步滞后是正常的,这不是什么问题。
  • 正常的停止从结点,会让主结点自动释放 WALSender 的链接数,所以,不应该重新配置主结点的 max_wal_senders 参数。但是,停止从结点时,主结点的复数连接数不会很快的被释放,而新启动的从结点又会消耗更多的链接数。他认为,GitLab 配置的 32 个链接数太高了,通常来说,2 到 4 个就足够了。
  • 另外,之前 GitLab 配置的 max_connections=8000 太高了,现在降到 2000 个是合理的。
  • pg_basebackup 会先在主结点上建一个 checkpoint,然后再开始同步,这个过程大约需要 4 分钟。
  • 手动的删除数据库目录是非常危险的操作,这个事应该交给程序来做。推荐使用刚 release 的 repmgr。
  • 恢复备份也是非常重要的,所以,也应该用相应的程序来做。推荐使用 barman (其支持 S3)。
  • 测试备份和恢复是一个很重要的过程。

看这个样子,估计也有一定的原因是——GitLab 的同学对 PostgreSQL 不是很熟悉。

随后,GitLab 在其网站上也开了一系列的 issues,其 issues 列表在这里 Write post-mortem (这个列表可能还会在不断更新中)。

  • infrastructure#1094 – Update PS1 across all hosts to more clearly differentiate between hosts and environments
  • infrastructure#1095 – Prometheus monitoring for backups
  • infrastructure#1096 – Set PostgreSQL’s max_connections to a sane value
  • infrastructure#1097 – Investigate Point in time recovery & continuous archiving for PostgreSQL
  • infrastructure#1098 – Hourly LVM snapshots of the production databases
  • infrastructure#1099 – Azure disk snapshots of production databases
  • infrastructure#1100 – Move staging to the ARM environment
  • infrastructure#1101 – Recover production replica(s)
  • infrastructure#1102 – Automated testing of recovering PostgreSQL database backups
  • infrastructure#1103 – Improve PostgreSQL replication documentation/runbooks
  • infrastructure#1104 – Kick out SSH users inactive for N minutes
  • infrastructure#1105 – Investigate pgbarman for creating PostgreSQL backups

从上面的这个列表中,我们可以看到一些改进措施了。挺好的,不过我觉得还不是很够。

因为类似这样的事,我以前也干过(误删除过数据库,在多个终端窗口中迷失掉了自己所操作的机器……),而且我在亚马逊里也见过一次,在阿里内至少见过四次以上(在阿里人肉运维的误操作的事故是我见过最多的),但是我无法在这里公开分享,私下可以分享。在这里,我只想从非技术和技术两个方面分享一下我的经验和认识。

我的思考:技术方面 人肉运维

一直以来,我都觉得直接到生产线上敲命令是一种非常不好的习惯。我认为,一个公司的运维能力的强弱和你上线上环境敲命令是有关的,你越是喜欢上线敲命令你的运维能力就越弱,越是通过自动化来处理问题,你的运维能力就越强。理由如下:

  1. 如果说对代码的改动都是一次发布的话,那么,对生产环境的任何改动(包括硬件、操作系统、网络、软件配置……),也都算是一次发布。那么这样的发布就应该走发布系统和发布流程,要被很好的测试、上线和回滚计划。关键是,走发布过程是可以被记录、追踪和回溯的,而在线上敲命令是完全无法追踪的。没人知道你敲了什么命令。
  2. 真正良性的运维能力是——人管代码,代码管机器,而不是人管机器。你敲了什么命令没人知道,但是你写个工具做变更线上系统,这个工具干了什么事,看看工具的源码就知道了。

另外,有人说,以后不要用 rm 了,要用 mv,还有人说,以后干这样的事时,一个人干,另一个人在旁边看,还有人说,要有一个 checklist 的强制流程做线上的变更,还有人说要增加一个权限系统。我觉得,这些虽然可以 work,但是依然不好,因为:

  • 如果要解决一个事情需要加更多的人来做的事,那这事就做成劳动密集型了。今天我们的科技就是在努力消除人力成本,而不是在增加人力成本。而做为一个技术人员,解决问题的最好方式是努力使用技术手段,而不是使用更多的人肉手段。人类区别于动物的差别就是会发明和使用现代化的工具,而不是使用更多的人力。另外,这不仅仅因为是,人都是会有这样或那样的问题(疲惫、情绪化、急燥、冲动……),而机器是单一无脑不知疲惫的,更是因为,机器干活的效率和速度是比人肉高出 N 多倍的。
  • 增加一个权限系统或是别的一个 watch dog 的系统完全是在开倒车,权限系统中的权限谁来维护和审批?不仅仅是因为多出来的系统需要多出来的维护,关键是这个事就没有把问题解决在 root 上。除了为社会解决就业问题,别无好处,故障依然会发生,有权限的人一样会误操作。对于 GitLab 这个问题,正如 2nd Quadrant 的 CTO 建议的那样,你需要的是一个自动化的备份和恢复的工具,而不是一个权限系统。
  • 像使用 mv 而不 rm,搞一个 checklist 和一个更重的流程,更糟糕。这里的逻辑很简单,因为,1)这些规则需要人去学习和记忆,本质上来说,你本来就不相信人,所以你搞出了一些规则和流程,而这些规则和流程的执行,又依赖于人,换汤不换药,2)另外,写在纸面上的东西都是不可执行的,可以执行的就是只有程序,所以,为什么不把 checklist 和流程写成代码呢(你可能会说程序也会犯错,是的,程序的错误是 consistent,而人的错误是 inconsistent)?

最关键的是,数据丢失有各种各样的情况,不单单只是人员的误操作,比如,掉电、磁盘损坏、中病毒等等,在这些情况下,你设计的那些想流程、规则、人肉检查、权限系统、checklist 等等统统都不管用了,这个时候,你觉得应该怎么做呢?是的,你会发现,你不得不用更好的技术去设计出一个高可用的系统!别无它法。

关于备份

一个系统是需要做数据备份的,但是,你会发现,GitLab 这个事中,就算所有的备份都可用,也不可避免地会有数据的丢失,或是也会有很多问题。理由如下:

  1. 备份通常来说都是周期性的,所以,如果你的数据丢失了,从你最近的备份恢复数据里,从备份时间到故障时间的数据都丢失了。
  2. 备份的数据会有版本不兼容的问题。比如,在你上次备份数据到故障期间,你对数据的 scheme 做了一次改动,或是你对数据做了一些调整,那么,你备份的数据就会和你线上的程序出现不兼容的情况。
  3. 有一些公司或是银行有灾备的数据中心,但是灾备的数据中心没有一天 live 过。等真正灾难来临需要 live 的时候,你就会发现,各种问题让你 live 不起来。你可以读一读几年前的这篇报道好好感受一下《以史为鉴,宁夏银行 7 月系统瘫痪最新解析》。

所以,在灾难来临的时候,你会发现你所设计精良的“备份系统”或是“灾备系统”就算是平时可以工作,但也会导致数据丢失,而且可能长期不用的备份系统很难恢复(比如应用、工具、数据的版本不兼容等问题)。

我之前写过一篇《分布式系统的事务处理》,你还记得下面这张图吗?看看 Data Loss 那一行的,在 Backups, Master/Slave 和 Master/Master 的架构下,都是会丢的。

所以说,如果你要让你的备份系统随时都可以用,那么你就要让它随时都 Live 着,而随时都 Live 着的多结点系统,基本上就是一个分布式的高可用的系统。因为,数据丢失的原因有很多种,比如掉电、磁盘损坏、中病毒等等,而那些流程、规则、人肉检查、权限系统、checklist 等等都只是让人不要误操作,都不管用,这个时候,你不得不用更好的技术去设计出一个高可用的系统!别无它法。(重要的事,得再说一篇)

另外,你可以参看我的另一篇《关于高可用系统》,这篇文章中以 MySQL 为例,数据库的 replication 也只能达到 两个 9。

AWS 的 S3 的的高可用是 4 个加 11 个 9 的持久性(所谓 11 个 9 的持久性 durability,AWS 是这样定义的,如果你存了 1 万个对象,那么丢一个的时间是 1000 万年),这意味着,不仅仅只是硬盘坏,机器掉电,整个机房挂了,其保证可以承受有两个设施的数据丢失,数据还是可用的。试想,如果你把数据的可用性通过技术做到了这个份上,那么,你还怕被人误删一个结点上的数据吗?

我的思考:非技术方面 故障反思

一般说来,故障都需要反思,在 Amazon,S2 以上的故障都需要写 COE(Correction of Errors),其中一节就是需要 Ask 5 Whys,我发现在 GitLab 的故障回顾的 blog 中第一段中也有说要在今天写个 Ask 5 Whys。关于 Ask 5 Whys,其实并不是亚马逊的玩法,这还是算一个业内常用的玩法,也就是说不断的为自己为为什么,直到找到问题的概本原因,这会逼着所有的当事人去学习和深究很多东西。在 Wikipedia 上有相关的词条 5 Whys,其中罗列了 14 条规则:

  • 你需要找到正确的团队来完成这个故障反思。
  • 使用纸或白板而不是电脑。
  • 写下整个问题的过程,确保每个人都能看懂。
  • 区别原因和症状。
  • 特别注意因果关系。
  • 说明 Root Cause 以及相关的证据。
  • 5 个为什么的答案需要是精确的。
  • 寻找问题根源的频,而不是直接跳到结论。
  • 要基础客观的事实、数据和知识。
  • 评估过程而不是人。
  • 千万不要把“人为失误”或是“工作不注意”当成问题的根源。
  • 培养信任和真诚的气氛和文化。
  • 不断的问“为什么”直到问题的根源被找到。这样可以保证同一个坑不会掉进去两次。
  • 当你给出“为什么”的答案时,你应该从用户的角度来回答。

工程师文化

上述的这些观点,其实,我在我的以住的博客中都讲过很多遍了,你可以参看《什么是工程师文化?》以及《开发团队的效率》。其实,说白了就是这么一个事——如果你是一个技术公司,你就会更多的相信技术而不是管理。相信技术会用技术来解决问题,相信管理,那就只会有制度、流程和价值观来解决问题。

这个道理很简单,数据丢失有各种各样的情况,不单单只是人员的误操作,比如,掉电、磁盘损坏、中病毒等等,在这些情况下,你设计的那些流程、规则、人肉检查、权限系统、checklist 等等统统都不管用,这个时候,你觉得应该怎么做呢?是的,你会发现,你不得不用更好的技术去设计出一个高可用的系统!别无它法(重要的事得说三遍)。

事件公开

很多公司基本上都是这样的套路,首先是极力掩盖,如果掩盖不了了就开始撒谎,撒不了谎了,就“文过饰非”、“避重就轻”、“转移视线”。然而,面对危机的最佳方法就是——“多一些真诚,少一些套路”,所谓的“多一些真诚”的最佳实践就是——“透明公开所有的信息”,GitLab 此次的这个事给大家树立了非常好的榜样。AWS 也会把自己所有的故障和细节都批露出来。

事情本来就做错了,而公开所有的细节,会让大众少很多猜测的空间,有利于抵制流言和黑公关,同时,还会赢得大众的理解和支持。看看 GitLab 这次还去 YouTube 上直播整个修复过程,是件很了不起的事,大家可以到他们的 blog 上看看,对于这样的透明和公开,一片好评。

2017-02-06 16:525143

评论

发布
暂无评论
发现更多内容

10个比较不错的 JavaScript 库

编程江湖

JavaScript 前端开发

比特币挖矿与源码解析

恒生LIGHT云社区

比特币 区块链 挖矿

你可能不信,52小时能做出7款超酷产品!

LigaAI

程序员 技术 技术人生 技术分享 hackathon

【1分钟调研赢好礼】HarmonyOS Connect 视频课堂用户反馈问卷

HarmonyOS开发者

HarmonyOS

以 Vuex 为引,一窥状态管理全貌

杨成功

JavaScript Vue 大前端 vuex

Hive查询的18种方式

编程江湖

大数据 hive

Kubernetes 集群无损升级实践

vivo互联网技术

容器 云原生 服务器集群 Kubernetes 集群

龙智宣布与ConnectALL成为合作伙伴 进一步提升DevOps解决方案水平

龙智—DevSecOps解决方案

DevOps ConnectALL 价值流 价值流管理

【征集令】寻找2022年鸿蒙智联“出行新爆款产品”

HarmonyOS开发者

HarmonyOS

spring 通过xml文件进行依赖注入

田镇珲

书单 | “实战派”系列,每一本都是学好用好一门技术的“航空母舰”

博文视点Broadview

netty系列之:netty对SOCKS协议的支持

程序那些事

Java Netty 程序那些事 SOCKS 12月日更

【LeetCode】在 D 天内送达包裹的能力Java题解

Albert

算法 LeetCode 12月日更

Go语言逆向技术:常量字符串

华为云开发者联盟

字符串 go语言 字符 逆向技术 常量字符串

超细!细说Zookeeper选举的一个案例(下)

恒生LIGHT云社区

Go golang zookeeper Go 语言

读《思辨与立场》-07思维的标准

wood

28天写作 批判性思维 思辨与立场

龙智第四次荣登“2021上海软件和信息技术服务业高成长百家”名单

龙智—DevSecOps解决方案

上海软件和信息技术服务业

【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变,小白也能看懂

Tom弹架构

Java log4j 安全漏洞

TDinsight——基于Grafana的TDengine零依赖监控解决方案

TDengine

数据库 tdengine 时序数据库 后端技术

建木持续集成平台v2.1.0发布

Jianmu

DevOps CI/CD 开源社区

容器技术正在颠覆传统,重构整个软件世界

巨子嘉

容器 云原生

Java开发Excel数据导入mysql的实用小技巧

@零度

Java MySQL

Redisson:这么强大的实现分布式锁框架,你还没有?

华为云开发者联盟

redis 分布式 分布式锁 可重入锁 Redisson框架

前端开发之JS中filter()的使用

@零度

JavaScript 前端开发

即构科技 RTC 实践与深度解析 | 内容合集

ZEGO即构

音视频 RTC 内容合集 技术实践 技术专题合集

先进开发团队,先用 Apifox,做“API 文档先行”理念的先行者!

狐哥说技术

Apifox API swagger API文档

GaussDB(DWS)中共享消息队列实现的三大功能

华为云开发者联盟

线程 数据同步 GaussDB(DWS) 共享消息队列 共享消息

COG云原生优化遥感影像,瓦片切分的最佳实践

华为云开发者联盟

云原生 遥感影像 瓦片切分 云上遥感影像文件 华为云地理遥感平台

对话龙智专家,共探DevSecOps实践难点

龙智—DevSecOps解决方案

DevOps DevSecOps

大数据开发hadoop之yarn基础架构详解

@零度

大数据 hadoop YARN

Sentinel-Go 源码系列(三)滑动时间窗口算法的工程实现

捉虫大师

Go sentinel-go

左耳朵耗子:我对GitLab误删除数据库事件的几点思考_数据库_陈皓_InfoQ精选文章