行业动态 Industry dynamic
当前位置:首页 > 新闻中心 > 行业动态
我不小心删除了所有的数据
发布日期:2011-12-09 阅读次数:548 字体大小: 标签:程序员

  昨天,我和在 Famigo 公司的同事 CodyShaun 一起去参加 MongoDallas 研讨会。我们在几个月前听说了这个会议,感到去这个会议将会是次有趣的活动。我们公司几乎所有的东西都是存储在 MongoDB 里的,Cody 会在这个会议上做一次演讲介绍我们的使用情况。

  会议办的非常好,进行的过程中没有出什么意外情况。(跟上次活动一样,10gen 公司给会议提供了大量的饮料。)午餐期间,我们跟 GameStop 公司的几个家伙侃大山。其中有个人问我们在正式环境服务器上做过的最糟的一件事情是什么。我想不出什么,但 Cody 给大家讲了一个他在以前的岗位上的一个故事。是他把完全重写的代码放到服务器上后,整个环境立即崩溃了。

  可结果却是,我在下午实现了我对生产环境犯下的最大的错误。

  午餐之前,在两个演讲之间,我检查了一下我们的服务器,看看是否一切正常。我发现了一个异常,跟保持唯一数据值有关。我们的 API 中的一个竞争关系的条件语句导致了数据库中的两个账户保存了相同的 email 地址,但每个账户的 email 地址必须是唯一的。

  我迅速的定位了问题,在我们的缺陷跟踪系统了添加了一条记录,描述了问题的原因,以及产生冲突的账户。我删除了这个账户,因为它没有跟任何数据关联,我们的客户在下次登录时,系统会自动初始化一条记录。

  然后,我继续查找,看看数据库中是否还有其它产生冲突的账户。我循环数据库里的每个账户,依次保持它们(没有做任何改变);有问题的数据会在保持时抛出异常信息。我在 Python 的交互 shell 里编码,所以当时的代码并没有保留下来,但它们大概是这样的:

    from mongoengine import connect
from models import Family
connect ('the-production-database')
for family in Family.objects:
family.save()

  代码执行完并没有出现异常,于是我关掉了笔记本,把注意力重新放到会议上。几个小时后,Cody 收到了大量的报告服务器响应变慢的邮件。他迅速的打开了笔记本,我在旁边看着他的屏幕。当我看到这一幕时,几乎诱发了我的心脏病:

>>> Family.objects.count ()
38

  这数量少了好几个数量级!我们极度不安,从会议厅里溜了出去。

  事情很快就明白了,我们的帐户信息,而且只是帐户信息,被弄丢了。我查看新近出现的账户信息,把它们加入的时间和我最后一次提交操作的时间对比。它们不可思议的接近。

  不幸的是,我的屏幕会话没有足够的回滚信息来让我看看今天早些时间究竟做了什么。因为我是在交互式 shell 里执行的,我找不到任何历史记录。最大可能的猜测,我应该是干了类似这样的事情:

for family in Family.objects:    
family.delete ()

  我晕倒!执行savedelete 操作都不会返回任何信息,所以在看着帐户信息在屏幕上滚动时没有发现任何的异常。(我并不确认究竟是怎么回事,但这是最简单的解释。奥坎氏简化论在这里打倒了我的自负。)

  会场的网速很差劲,而且找不到电源插座,于是我们收拾起东西,匆忙的想找一家附近咖啡馆。结果发现,达拉斯市中心所有的咖啡馆下午 4 点钟全关门了。幸运的是,它们提供 24 小时的免费 wifi,于是我们就在一家星巴克外面安营扎寨,开始了工作。

  (达拉斯这个地方要比我们预想的冷的多。当我们离开奥斯汀时,那里是华氏 80 度,阳光明媚。而在达拉斯,这里一直 40 度,阴天,有风。我们三个穿着T恤、牛仔裤的人挤在笔记本前,希望能在冻僵前尽快解决问题。)

  这周早期,我们有个数据库备份,我们把它导入到了我们的开发环境中,Cody 把它恢复到了一个独立的数据库里。我写了一个脚本,把丢失的账户信息一一从一个数据库导入另一个数据库。很幸运,进行的很顺利,所有的信息都恢复了。

  剩下还有一些要做的事情,要检查所有对这些数据的引用都指向了正确的地方,但最重要的大火是已经被扑灭了。11月 17 号,它一直保留下来,成为了我们的备份宣传日