处理不可复制的错误


73

假设您的团队编写的软件系统运行正常(非常令人惊讶!)。

有一天,一位工程师错误地运行了一些SQL查询,这些查询更改了一些数据库数据,然后忘记了。

一段时间后,您发现损坏/错误的数据,每个人都为解决该问题的代码部分以及原因而scratch之以鼻。同时,项目经理坚持认为,我们找到了导致它的代码部分。

您如何处理?


32
如果工程师忘记了它,您怎么知道那是怎么回事?您如何通过运行脚本而不是错误将其损坏?
DaveG '18 -10-25

18
一两天后,他顿悟了。这是一个假设,以防他从未记得过,很可能是这样。
Nik Kyriakides

12
这是一个假设。我敢肯定,如果他不记得,总理将让我们追逐这一切。我知道我会的
Nik Kyriakides

59
xkcd.com/583 ;)[NSFW语言]
Baldrickk

100
“假设您的团队编写的软件系统运行良好。”不要再嘲笑我了!
Paul D. Waite,

Answers:


134

显然,没有项目经理会花大量时间解决这个问题。他们想防止再次发生同样的情况。

为了实现这一目标,即使无法找到这种故障的根本原因,通常也可以采取一些措施

  • 尽早发现此类故障,以防它们再次发生
  • 减少再次发生相同故障的可能性
  • 使系统对特定类型的不一致更加健壮

例如,更详细的日志记录,更细粒度的错误处理或立即的错误信号发送可以帮助防止同一错误再次发生或找到根本原因。如果您的系统允许添加数据库触发器,则可能可以添加一个触发器,该触发器首先禁止引入不一致性。

考虑一下您所处环境中可能采取的适当行动,并向团队提出建议;我相信您的项目经理会很高兴。

有一天,一位工程师错误地运行了一些SQL查询,这些查询更改了一些数据库数据,然后忘记了。

正如其他人所提到的,禁止这样的过程也是一个好主意(如果您对系统的操作方式有影响)。不允许任何人运行更改数据库内容的无证即席查询。如果需要这样的查询,请确保有一个策略可以将查询及其执行日期,执行人员的姓名以及使用该查询的原因一起存储在文档中。


8
@NicholasKyriakides也许两者都有。所有这些都是常识性的措施,可简化“延迟”调试。它们可能是用无数过程编写的。
Nic Hartley

29
确实会不时发生生产系统中的某种严重问题,尽管付出了很大的努力却无法确定原因。最终,您将其归因于宇宙射线,并尝试改善报告(因此,如果再次发生,则有更大的机会找到原因)和缓解措施(因此,如果再次发生,则损害将最小),并查看是否重复。
大卫·史瓦兹

2
@Nicholas Kyriakides:几十年来的个人经历。
布朗

4
还应该注意的是,即使存在错误,也很有可能不再存在。有时您能做的最好的事情就是修复数据,并改进测试/过程以确保相同的问题不再发生。
kutschkem '18 -10-26

2
查找间歇性问题仅与记录日志有关,并找到一个可以在发生时检测到它们的阻塞点,然后从那里向后走以查明源头。有时,它需要一些令人不愉快的事情,例如触发器,或者使用带有错误日志的嘈杂代码来部署代码,只是为了了解错误的时间/位置。
AaronLS '18 -10-26

51

这不是错误

至少不在您的代码上。这是您过程中的错误。您的项目经理应该比代码更担心您的过程。

您如何处理?

很简单,不让工程师更改生产或共享开发数据库


假设这是一个共享的开发数据库:

理想情况下,如果有可能,请首先避免使用共享数据库。相反,每个开发人员的数据库都是短暂的。应该使用脚本将其自动化,否则测试成本会变得过高,并且有动力不进行测试。您可以在开发人员的工作站或中央服务器上拥有这些数据库。

如果出于某种原因,您绝对必须拥有一个共享数据库,则应使用固定装置 -本质上,该固定装置可以在每次需要使用数据库时将其设置为良好状态。这样可以避免开发人员被其他人的更改所困扰。

如果您需要对数据库进行永久更改,则应将其提交到源代码管理中。设置数据库,使开发人员无权直接对其进行写操作,并拥有一个从源代码管理中提取更改并应用更改的程序。

最后,从关于如何调试事物的描述中,听起来好像您没有使用CI使用CI。设置起来有点麻烦,但是从长远来看,它将节省很多时间,更不用说让您不必担心无法复制的数据库错误。您现在只需要担心heisenbugs


假设这是一个生产数据库:

如果您的开发人员正在更改生产数据库,那么即使更改绝对正确,很多事情还是出了差错。

开发人员永远不应访问生产数据库。绝对没有理由这样做,因此很多事情可能会变得非常非常错误。

如果需要修复生产数据库中的某些内容,请先备份,然后在其他(开发)实例上还原该备份,然后在该开发数据库中进行播放。一旦认为已准备好修复(在源代码控制中!),您就可以重新进行还原,应用此修复程序并查看结果。然后,在再次备份之后(理想情况下阻止并发更新),您可以修复生产实例,理想情况下是通过软件修补程序。

如果您需要测试生产数据库中的某些内容...不,您不需要。无论需要执行什么测试,都应该在开发实例中执行。如果您需要一些数据来进行测试,则可以在其中获得该数据。


12
那么,您推荐的解决方案是时间旅行?
Benubird

7
尽管对于给出的示例来说,这是一个不错的解决方案,但该问题具有处理无法复制的错误以及希望他们说服这些错误的管理人员的更一般的上下文。这不仅适用于数据库问题和权限管理,还可以应用。我觉得这个答案实际上并没有回答预期的问题,只是给出的例子。
凯尔·沃德

@KyleWardle同意。我认为布朗博士的答案很好地涵盖了一般情况(详细的日志记录和错误处理,保护条件)。我主要添加了我的信息,因为我发现没人首先提到导致问题的过程失败
goncalopp

2
@Benubird我认为答案可以归结为“您处理此问题的方法可以防止它再次发生”。我认为您不能从软件工程的角度“解决”损坏的生产数据库。
goncalopp

1
您不会更改代码以将数据放入dev数据库。在我工作过的所有地方(包括大型公司),开发人员都可以自由插入测试数据,并使用与应用程序相同的凭据。
戴维·康拉德

13

生产数据库应具有完全访问日志记录和基于角色的访问控制。因此,您应该有充分的证据证明WHO何时对数据库执行了什么操作,从而将注意力从代码转移到了较差的操作安全性上。


2
听起来他们可能不知道确切的数据损坏时间,这可能使得很难弄清他们需要调查哪些日志。
Nathanael

3
不幸的是,在追踪其中之一时,我们发现它也在浪费日志。(是的,该错误是真实的。)
约书亚

结合日志记录和计划的作业检查数据完整性(即使只是整夜),也意味着可以尽早发现问题并加以解决。如果您要非常小心,请要求同行审查以进行更改。
基思(Keith)

在我工作过的所有地方,开发人员都使用应用程序使用的相同凭据连接到数据库,因此访问日志只会显示该ID进行更改的时间,而不是由人工而不是由程序完成的。我想您可以将时间戳记与应用程序日志进行比较,以查看应用程序当时是否正在执行将写入数据库的任何操作。
戴维·康拉德

@DavidConrad:为什么开发人员可以访问该应用在生产中使用的凭据?您应该使用某种机密管理,以使这些凭据甚至无法从生产应用程序服务器中读取,除非您的应用程序服务帐户可以读取。
丹尼尔·普里登

6

在这种情况下,您最终确实找到了原因,但是以您没有的假设为前提...

首先,分析发生了什么变化。如果系统以前运行良好,请仔细查看最近完成的所有操作,可能会发现导致错误的更改。系统地检查您的版本控制,CI /部署系统和配置控制,以查看是否有任何更改。运行git bisect或等效的机制来执行二进制搜索。检查日志。搜寻您不知道的日志。与有权访问该系统的所有人进行交谈,以查看他们最近是否做过任何事情。对于您的问题,如果您在此过程中足够详尽,则有望显示出被遗忘的SQL查询。

第二,仪器仪表。如果您无法直接找到错误的原因,请在该错误周围添加检测以收集有关该问题的数据。问问自己“如果我可以在命令中重现此错误,我想在调试器中查看什么”,然后记录下来。根据需要重复操作,直到您对问题有了更好的了解。正如Doc Brown所建议的,添加与错误相关的状态的日志记录。添加断言以检测损坏的数据。例如,如果您的错误是应用程序崩溃,请添加崩溃日志记录机制。如果您已经有一个不错的,请在崩溃日志中添加注释,以记录可能与崩溃相关的状态。考虑是否可能涉及并发问题,并进行测试以行使线程安全性

第三,弹性。错误是不可避免的,因此请问问自己如何改善系统,使其更具弹性,以便更轻松地从错误中恢复。您的备份是否可以改进(或存在)?更好的监视,故障转移和警报?更多冗余?更好的错误处理?相互分离依赖服务?您能否围绕数据库访问和手动查询改进流程?充其量,这些事情将使您的错误的后果减轻一些,而在最坏的情况下,它们仍然可能是一件好事。


5
  1. 向项目经理解释您认为最可能的原因是手动数据库访问。
  2. 如果他们仍然希望您查找导致此问题的代码,请再看一下该代码。
  3. 请在几个小时后(或其他适当的时间)回来,并说找不到导致该问题的任何代码,因此您仍然认为最可能的原因是手动数据库访问。
  4. 如果他们仍然希望您查找代码,请询问他们希望您花费多少时间。巧妙地提醒他们,执行此操作时不会使用功能X,错误Y或增强功能Z。
  5. 花尽可能多的时间。如果您仍然认为最可能的原因是手动数据库访问,请告诉他们。
  6. 如果他们仍然希望您查找代码,请升级该问题,因为这显然已成为您团队时间的无用功。

您可能还需要考虑是否应该增加额外的过程,以减少将来手动数据库访问引起此类问题的可能性。


1
我不知道其中一名工程师进行了手动更新,而工程师几乎从未直接在数据库上运行查询。这只是一件一次性的事情,而忘记了。我们花了一天的时间并准备花整整一周的时间来找出问题所在。我的问题是,如果您找不到原因并且无法建议可能的原因,会发生什么。
Nik Kyriakides

5
“我的问题是,如果您找不到原因并且无法建议可能的原因,会发生什么。”这就是发明了“无法解决-无法复制”标志的确切原因。
esoterik '18 -10-25

4

当客户报告他们的数据库损坏时,我正在大型机数据库产品的开发团队中工作。光盘上位的内部状态意味着无法通过数据库软件读取数据库的意义上的损坏。在大型机世界中,客户向您支付了数百万美元,因此您需要认真对待这一点。这是我们所做的:

步骤0:通过修复数据库来帮助客户重新启动并运行。

步骤1:通过以十六进制级别检查磁盘上的文件,我们确定损坏是系统的:同一损坏有很多实例。因此,这肯定是在数据库软件级别造成的。确实,它足够系统,我们认为可以排除多线程问题。

在消除了许多其他理论之后,我们找到了一个实用程序,该实用程序可用于数据库的物理重组。它似乎是唯一可以在适当级别访问数据的代码。然后,我们发现了一种运行该实用程序的方法,该方法具有精心选择的选项,从而重现了该问题。客户无法确认或否认这是他们所做的,但是由于这是我们可以提出的唯一解释,因此我们确定这是可能的原因,他们别无选择,只能接受我们的诊断。 。

步骤2:然后,我们对该软件进行了两项更改:(a)通过“是的,我知道我在做什么”的用户界面,更难以意外地导致这种效果,以及(b)引入新的日志文件,以便如果再次发生,我们将记录用户的操作。

因此,基本上,(a)修复损坏并恢复运行状态,(b)找到根本原因,(c)采取一切必要措施来防止再次发生,或者如果再次发生,则能够轻松诊断。


3

根据我的经验,您的老板想要的是某种程度的保证,即这种情况不会再次发生。如果是没有代码的原因,那么可以通过统一测试确保这一点,因此,假设您已经在代码库中进行了测试,则解决方案应该在数据库中添加“测试”。我要引用唐·吉尔曼(Don Gilman),因为他钉在那儿:

生产数据库应具有完全访问日志记录和基于角色的访问控制。因此,您应该有充分的证据证明WHO何时对数据库执行了什么操作,从而将注意力从代码转移到了较差的操作安全性上。

而且,您还应该具有在生产中更改数据的标准操作程序。例如,没有DBA应该更改数据,没有开发人员应该自己执行更改,并且他们应该按照SOP中的规定,通过邮件或票证相互正式要求更改。

在某处必须有这样的报价,否则,您可以在上面引用我:

有一个很好的理由说明厨师不是负责清洁厕所的人。


1

对于不可复制的错误,必须完成几件事。

  1. 为此创建票证

创建一个票证,并记录您在票证中可以想到的所有内容。还要检查此“错误”是否已经记录过,并将票证链接在一起。最终,您可能会获得足够的凭单,以建立如何重现该错误的模式。这包括用于尝试避免的解决方法。即使这是唯一的实例,如果是第一次,最终将是第二次。当您确实找到原因时,请关闭故障单并说明原因,以便您对再次发生的情况有很清楚的了解(错误合并中丢失的修复程序)

  1. 进行强化分析

查看系统,发生什么故障以及如何发生故障。尝试查找可以更新的代码区域,以减少失败的可能性。一些例子...

  • 配有专用的呼叫(如更换特殊的代码execute(<query>)executeMyStoredProcedure(<params>)
  • 每晚运行验证脚本以验证数据完整性(以便下次可以在24小时内检测到)
  • 添加/改进日志记录和归档(备份)。
  • 更改不正确的安全性限制(例如,仅读取数据的人员/程序没有写许可;不允许不负责生产的开发人员登录到生产服务器)
  • 在缺少的地方添加数据验证/卫生

这可能无法修复该错误,但是即使不能解决该错误,该系统现在也更加稳定/安全,因此仍然值得。

  1. 添加系统警报

Kinda是2的一部分,但是发生了一些事情,您需要知道何时再次发生。您应该创建一些运行状况检查脚本/程序来监视系统,以便可以在错误重新出现后24小时内向管理员发出警报(延迟越短越好,在合理范围内)。这将使清理更加容易。(请注意,除了数据库的日志外,操作系统还应该记录登录者以及他们执行的任何未读操作。至少,应该有到该计算机的网络流量日志)


0

您的问题不是由软件故障引起的,而是由摆弄数据库的人引起的。如果您将出错的地方称为“错误”,那么您的错误很容易重现:当某人对数据库进行了愚蠢的事情时,事情总是会出错。还有一些方法可以避免这种“错误”,方法是不允许手动或使用未经测试的软件修改数据库,并严格控制谁可以修改数据库。

如果仅将数据库中的错误称为“错误”,那么您就没有不可复制的错误,根本就没有错误。您可能有一个错误报告,但也有证据表明该问题不是由错误引起的。因此,您可以关闭错误报告,而不是“不可复制”,而可以关闭“损坏的数据库”之类的信息。有错误报告的情况并不罕见,调查表明没有错误,但是用户使用了错误的软件,用户的期望是错误的,等等。

在那种情况下,您仍然知道存在不想重复的问题,因此您将采取与第一种情况相同的操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.