想到这个题目是因为最近咱们组呈现了一个重大的线上问题,某小哥在进行线上操作的时候传错了一个参数。这种问题在程序员这行很常见,所谓常在河边走,哪有不湿鞋。
工作这么多年我本人犯过错,也看到过身边的删库跑路案例,更有甚者因为泄露敏感信息而锒铛入狱。这里分享一些本人所见的实在案例,以及如何在编程上、工作习惯上防止犯错。
案例分享
信息泄露
大疆前员工泄露公司源代码,被罚 20 万、获刑半年,这个安全事故齐全是因为员工的安全意识有余造成的。
这类问题十分多,不信你能够在 Github 上用 password、private key 之类的关键词搜寻,很多人会有意识把这些敏感信息推送到 Github 上,而公司又没法齐全禁止 Github,只能不断加强平安培训和监控。
从这个案例来看公司的损失十分十分大,单人力老本这块就难以估计,我也因为这个事变参加到了平安建设中,前面在这里畛域工作了两三年左右。真是一人挖坑,有数人救火。
退款接口
我在做领取、物流相干的零碎时,已经因为一个诡异的接口造成了间接上的金钱损失。
咱们的领取是通过第三方领取零碎做的对接,比方用户通过领取零碎向咱们预领取了 100 美金,等他收货后第三方把钱给咱们。第三方领取有个退款接口,假如他不想要货了于是发动退单,咱们的零碎就会调用第三方的领取接口去退款。
因为接口有时候调用失败或者返回不及时,我在写代码的时候默认既然对方预领取了 100 美金,屡次发动退款接口天然也没问题,所以我有一些重试的机制来确保退款胜利。过了一段时间后发现账目上有点差异,起初通过排查是因为反复调用了退款接口,这个接口如果两次调用就会退给客户退 200 美金!
最初咱们只能发邮件给一些客户,说多退了钱,麻烦能退回来么,有的客户很善意就间接返回了钱。我记得有个客户回复说:我认为这是上帝给我的赏赐,对不起我曾经花完了。
额,我就是那个可怜的上帝好么。
并发问题
我前公司所在的部门已经有个发货零碎,当多过程跑起来的时候,有个并发问题没解决好,最终导致用户收到多份雷同的货物。
当程序员经验不足的时候这种谬误就很容易呈现。代码中哪些局部是能够重入的,哪些局部须要加锁,都须要认真思考。然而在业务疾速倒退,疾速堆代码的时候,咱们可能不肯定有足够的工夫把所有细节都思考分明。
配置谬误
我之前呈现过的一个最大的谬误是因为配置谬误。这件事我始终都记得,因为印象切实是粗浅,当初对正则表达式都有所恐怖。
那天我正筹备上班回家,我配置了一些平安上的防护规定。而后我的 Leader 说拦挡的页面不够难看,咱们要不对立个拦挡页面。我想了一下感觉很简略,就筹备在咱们本人定制的网关 (Kong) 上配置一条全局规定,我想通过正则表达式把所有拦挡页面 redirect 到订制的谬误页面。
我通过后盾 Admin 页面,在一个全局插件上写下了一条正则表达式,提交失效。而后立马就收到了报警,大量零碎同时报警!因为有公司很多域名的申请都通过这个网关,而我配置的正则表达式嵌入到 Lua 代码中后有语法错误,导致所有零碎的路由解决时都报错。
最要命的是咱们的 Admin 页面也会通过这个网关,所以 Admin 页面也没法拜访了,意味着我无奈通过页面去回滚配置!我过后曾经手心发汗,如热锅上的蚂蚁了。强制本人慌张下来,马上批改插件的代码,连忙让运维一起迅速地服务器上网关更新。
整个过程大略破费了 20 分钟,这期间整个公司预计有一半的零碎都是不能拜访的,包含那些官网、商城等。
经验总结
犯错并不可怕,只有是集体就可能会犯错。呈现谬误往往也不止是集体的问题,也意味着团队有问题,比方对代码品质要求不够,零碎设计不够容错,权限划分不够好,平安机制不健全,没有 代码 Review 等等。 谬误是集体和团队最好的学习、进步的机会,而且咱们曾经交了学费 。
然而随着咱们成长,最好防止集体犯一些低级的谬误,特地是安全类的问题。写程序、做零碎设计的时候就做好进攻,把犯错的概率升高到最小。
进攻编程
面包落地的时候,永远是抹黄油的一面着地。
下面配置的问题,我在做网关的时候其实意识到了潜在危险,Admin 路由也通过本人管制那出问题不就嗝屁了吗?过后我自我安慰只有不对这个路由开有问题的全局插件就能够了,所以没有及时处理这个危险,最终导致本人掉入坑里。
当零碎中存在潜在问题时,工夫一拉长呈现的概率就大了。因而咱们编程的时候总要无意识想最坏的状况是什么,哪些是危险操作,比方写数据如果没写入胜利会怎么,如果并发运行了会怎么,如果文件谬误会怎么,这就是进攻式编程。
做零碎设计时,要思考敏感的业务逻辑如何测试,如何在零碎层面躲避谬误。对于敏感的资源肯定要再从统计的角度进行复查。像我那个退款的问题就是对潜在的风险意识不够,想当然地对接口进行了谬误的假如,而对方这个接口不是幂等的。起初咱们在零碎中加了很多查看,确保及时代码有问题也能尽早发现问题。
如果系统对正确性要求高,必须加大量单元测试和集成测试,并且每修复一个 Bug 都引入对应的测试,因为随着代码的一直演进,没人能保障新加的代码不会毁坏掉原来的代码。测试能最大水平自动化地帮咱们发现一些潜在问题。
我工作的第一家公司是做 EDA 相干软件的,因为 EDA 软件不像互联网这样的零碎,crash 了就是产生在客户的机器上,很多时候都没法 debug,因而公司对代码品质要求极高,他们在自动化测试这块就做得十分棒,测试覆盖率简直 100%,还有很多 fuzzy testing。
代码上的问题没法完全避免,那如何缩小危险?微软有个实际就是大量使用 killswitch,实质上就是开关,每个新加的性能和代码,倡议都是加上相似这样一个嵌套:
if(!killswitch-active(uuid))
{// your new code ...}
else {// old code ...}
这样的益处在于如果新的代码呈现了问题,能够迅速把对应的 killswitch 关上,这样老的代码就持续跑了,也就是不必发新版本就能疾速回滚。不得不说这个方法尽管有点土和笨,然而十分有用,因为这也救过我,而且让人发代码压力不至于那么大。害处也很显著,当 killswitch 多了之后代码就很难读,所以要去定期清理那些老的开关。
工作经验丰富一些了之后 (掉入坑里足够屡次),天然会对容易呈现问题的局部有风险意识,这须要一直积攒和总结。
工作习惯
平安是第一位的,咱们在工作中对敏感信息、公司资产要有肯定的安全意识。齐全依照公司的平安准则来工作,否则提桶跑路可能是小事,被查究法律责任就麻烦了。
任何线上操作都是危险的,如非必要不要进行手动的线上操作。操作的时候尽量慢,而后想分明如果错了如何复原。比方删货色尽量软删除,把要删的货色挪动目录或者设置状态。
如果一个动作是有危险的,应该思考如何把这动作自动化,如果是必须有人给输出,那须要肯定的流程来进行 Review 和批准。
微软还有个好实际就是所有的线上命令,如果是写入型的命令默认不能运行,须要手动地运行命令晋升权限。
运维方面,如果有条件和工夫尽量往 Infrastructure as Code 方向上靠,缩小人工进行操作。
_
写到最初,感觉写得不够零碎和全面,这个题目范畴太大,开发、运维、标准、平安等很多方面都波及到,而且有很多细节问题。
一句话倡议是: 放弃对工作的敬畏之心,特地是你的代码和工作会影响到很多用户时,即便一个小的谬误也会造成大量损失 。
先这样吧👻。