假设您的团队编写的软件系统运行正常(非常令人惊讶!)。
有一天,一位工程师错误地运行了一些SQL查询,这些查询更改了一些数据库数据,然后忘记了。
一段时间后,您发现损坏/错误的数据,每个人都为解决该问题的代码部分以及原因而scratch之以鼻。同时,项目经理坚持认为,我们找到了导致它的代码部分。
您如何处理?
假设您的团队编写的软件系统运行正常(非常令人惊讶!)。
有一天,一位工程师错误地运行了一些SQL查询,这些查询更改了一些数据库数据,然后忘记了。
一段时间后,您发现损坏/错误的数据,每个人都为解决该问题的代码部分以及原因而scratch之以鼻。同时,项目经理坚持认为,我们找到了导致它的代码部分。
您如何处理?
Answers:
显然,没有项目经理会花大量时间解决这个问题。他们想防止再次发生同样的情况。
为了实现这一目标,即使无法找到这种故障的根本原因,通常也可以采取一些措施
例如,更详细的日志记录,更细粒度的错误处理或立即的错误信号发送可以帮助防止同一错误再次发生或找到根本原因。如果您的系统允许添加数据库触发器,则可能可以添加一个触发器,该触发器首先禁止引入不一致性。
考虑一下您所处环境中可能采取的适当行动,并向团队提出建议;我相信您的项目经理会很高兴。
有一天,一位工程师错误地运行了一些SQL查询,这些查询更改了一些数据库数据,然后忘记了。
正如其他人所提到的,禁止这样的过程也是一个好主意(如果您对系统的操作方式有影响)。不允许任何人运行更改数据库内容的无证即席查询。如果需要这样的查询,请确保有一个策略可以将查询及其执行日期,执行人员的姓名以及使用该查询的原因一起存储在文档中。
这不是错误
至少不在您的代码上。这是您过程中的错误。您的项目经理应该比代码更担心您的过程。
您如何处理?
很简单,不让工程师更改生产或共享开发数据库。
假设这是一个共享的开发数据库:
理想情况下,如果有可能,请首先避免使用共享数据库。相反,每个开发人员的数据库都是短暂的。应该使用脚本将其自动化,否则测试成本会变得过高,并且有动力不进行测试。您可以在开发人员的工作站或中央服务器上拥有这些数据库。
如果出于某种原因,您绝对必须拥有一个共享数据库,则应使用固定装置 -本质上,该固定装置可以在每次需要使用数据库时将其设置为良好状态。这样可以避免开发人员被其他人的更改所困扰。
如果您需要对数据库进行永久更改,则应将其提交到源代码管理中。设置数据库,使开发人员无权直接对其进行写操作,并拥有一个从源代码管理中提取更改并应用更改的程序。
最后,从关于如何调试事物的描述中,听起来好像您没有使用CI。 使用CI。设置起来有点麻烦,但是从长远来看,它将节省很多时间,更不用说让您不必担心无法复制的数据库错误。您现在只需要担心heisenbugs!
假设这是一个生产数据库:
如果您的开发人员正在更改生产数据库,那么即使更改绝对正确,很多事情还是出了差错。
开发人员永远不应访问生产数据库。绝对没有理由这样做,因此很多事情可能会变得非常非常错误。
如果需要修复生产数据库中的某些内容,请先备份,然后在其他(开发)实例上还原该备份,然后在该开发数据库中进行播放。一旦认为已准备好修复(在源代码控制中!),您就可以重新进行还原,应用此修复程序并查看结果。然后,在再次备份之后(理想情况下阻止并发更新),您可以修复生产实例,理想情况下是通过软件修补程序。
如果您需要测试生产数据库中的某些内容...不,您不需要。无论需要执行什么测试,都应该在开发实例中执行。如果您需要一些数据来进行测试,则可以在其中获得该数据。
生产数据库应具有完全访问日志记录和基于角色的访问控制。因此,您应该有充分的证据证明WHO何时对数据库执行了什么操作,从而将注意力从代码转移到了较差的操作安全性上。
在这种情况下,您最终确实找到了原因,但是以您没有的假设为前提...
首先,分析发生了什么变化。如果系统以前运行良好,请仔细查看最近完成的所有操作,可能会发现导致错误的更改。系统地检查您的版本控制,CI /部署系统和配置控制,以查看是否有任何更改。运行git bisect或等效的机制来执行二进制搜索。检查日志。搜寻您不知道的日志。与有权访问该系统的所有人进行交谈,以查看他们最近是否做过任何事情。对于您的问题,如果您在此过程中足够详尽,则有望显示出被遗忘的SQL查询。
第二,仪器仪表。如果您无法直接找到错误的原因,请在该错误周围添加检测以收集有关该问题的数据。问问自己“如果我可以在命令中重现此错误,我想在调试器中查看什么”,然后记录下来。根据需要重复操作,直到您对问题有了更好的了解。正如Doc Brown所建议的,添加与错误相关的状态的日志记录。添加断言以检测损坏的数据。例如,如果您的错误是应用程序崩溃,请添加崩溃日志记录机制。如果您已经有一个不错的,请在崩溃日志中添加注释,以记录可能与崩溃相关的状态。考虑是否可能涉及并发问题,并进行测试以行使线程安全性。
第三,弹性。错误是不可避免的,因此请问问自己如何改善系统,使其更具弹性,以便更轻松地从错误中恢复。您的备份是否可以改进(或存在)?更好的监视,故障转移和警报?更多冗余?更好的错误处理?相互分离依赖服务?您能否围绕数据库访问和手动查询改进流程?充其量,这些事情将使您的错误的后果减轻一些,而在最坏的情况下,它们仍然可能是一件好事。
您可能还需要考虑是否应该增加额外的过程,以减少将来手动数据库访问引起此类问题的可能性。
当客户报告他们的数据库损坏时,我正在大型机数据库产品的开发团队中工作。光盘上位的内部状态意味着无法通过数据库软件读取数据库的意义上的损坏。在大型机世界中,客户向您支付了数百万美元,因此您需要认真对待这一点。这是我们所做的:
步骤0:通过修复数据库来帮助客户重新启动并运行。
步骤1:通过以十六进制级别检查磁盘上的文件,我们确定损坏是系统的:同一损坏有很多实例。因此,这肯定是在数据库软件级别造成的。确实,它足够系统,我们认为可以排除多线程问题。
在消除了许多其他理论之后,我们找到了一个实用程序,该实用程序可用于数据库的物理重组。它似乎是唯一可以在适当级别访问数据的代码。然后,我们发现了一种运行该实用程序的方法,该方法具有精心选择的选项,从而重现了该问题。客户无法确认或否认这是他们所做的,但是由于这是我们可以提出的唯一解释,因此我们确定这是可能的原因,他们别无选择,只能接受我们的诊断。 。
步骤2:然后,我们对该软件进行了两项更改:(a)通过“是的,我知道我在做什么”的用户界面,更难以意外地导致这种效果,以及(b)引入新的日志文件,以便如果再次发生,我们将记录用户的操作。
因此,基本上,(a)修复损坏并恢复运行状态,(b)找到根本原因,(c)采取一切必要措施来防止再次发生,或者如果再次发生,则能够轻松诊断。
根据我的经验,您的老板想要的是某种程度的保证,即这种情况不会再次发生。如果是没有代码的原因,那么可以通过统一测试确保这一点,因此,假设您已经在代码库中进行了测试,则解决方案应该在数据库中添加“测试”。我要引用唐·吉尔曼(Don Gilman),因为他钉在那儿:
生产数据库应具有完全访问日志记录和基于角色的访问控制。因此,您应该有充分的证据证明WHO何时对数据库执行了什么操作,从而将注意力从代码转移到了较差的操作安全性上。
而且,您还应该具有在生产中更改数据的标准操作程序。例如,没有DBA应该更改数据,没有开发人员应该自己执行更改,并且他们应该按照SOP中的规定,通过邮件或票证相互正式要求更改。
在某处必须有这样的报价,否则,您可以在上面引用我:
有一个很好的理由说明厨师不是负责清洁厕所的人。
对于不可复制的错误,必须完成几件事。
创建一个票证,并记录您在票证中可以想到的所有内容。还要检查此“错误”是否已经记录过,并将票证链接在一起。最终,您可能会获得足够的凭单,以建立如何重现该错误的模式。这包括用于尝试避免的解决方法。即使这是唯一的实例,如果是第一次,最终将是第二次。当您确实找到原因时,请关闭故障单并说明原因,以便您对再次发生的情况有很清楚的了解(错误合并中丢失的修复程序)
查看系统,发生什么故障以及如何发生故障。尝试查找可以更新的代码区域,以减少失败的可能性。一些例子...
execute(<query>)
与executeMyStoredProcedure(<params>)
这可能无法修复该错误,但是即使不能解决该错误,该系统现在也更加稳定/安全,因此仍然值得。
Kinda是2的一部分,但是发生了一些事情,您需要知道何时再次发生。您应该创建一些运行状况检查脚本/程序来监视系统,以便可以在错误重新出现后24小时内向管理员发出警报(延迟越短越好,在合理范围内)。这将使清理更加容易。(请注意,除了数据库的日志外,操作系统还应该记录登录者以及他们执行的任何未读操作。至少,应该有到该计算机的网络流量日志)
您的问题不是由软件故障引起的,而是由摆弄数据库的人引起的。如果您将出错的地方称为“错误”,那么您的错误很容易重现:当某人对数据库进行了愚蠢的事情时,事情总是会出错。还有一些方法可以避免这种“错误”,方法是不允许手动或使用未经测试的软件修改数据库,并严格控制谁可以修改数据库。
如果仅将数据库中的错误称为“错误”,那么您就没有不可复制的错误,根本就没有错误。您可能有一个错误报告,但也有证据表明该问题不是由错误引起的。因此,您可以关闭错误报告,而不是“不可复制”,而可以关闭“损坏的数据库”之类的信息。有错误报告的情况并不罕见,调查表明没有错误,但是用户使用了错误的软件,用户的期望是错误的,等等。
在那种情况下,您仍然知道存在不想重复的问题,因此您将采取与第一种情况相同的操作。