反省:不必追求100%的系统精确性

    去年我看了一部很烂的电影:《变形金刚3》。这部电影真的很烂很烂,但其中有一类镜头引发了我的思考:机器人的一条腿被打断后,它仍然用身体的其他部件进行战斗,虽然动作严重变形,但并没有放弃战斗。

    我当时就想,断了一条腿,相当于分布式架构中当了一个子系统;这种异常不是业务异常,而是技术异常,应声明为RuntimeException,在它抛出后不但要中止当前腿的动作,而且要中止接下来的其他手足的动作; 否则,可能导致系统的行为进入一个不可知的状态,轻则“动作严重变形”,重则一脚踏空、高空坠落,造成灾难性的后果。

    很显然,我那时的想法是不切实际的。作为战斗者,变形金刚的高可用性远远比它的“精确性”来得重要。对应到互联网的开发中,就是“网站看上去很健康”比“每笔交易无误”来得重要。当然,对敏感的系统比如支付系统、动车调度系统,还是后者更重要;但对普通的电子商务,“动作变形”比“拒绝服务”要友好的多。

  这里不妨总结一下严格追求精确性的常见的实践:

   

    1.技术异常统统定义成或包装成RuntimeException,并且不捕捉,让用户看到类似于“暂时无法为您提供服务”的提示

    2.数据库里严格使用事务,以避免单边数据

    3.数据库里使用各种约束,如外键、check constraint,以保证数据的完整性

  

    替代的“宽大处理”方案是:

  

    1. UI层调用业务层、或者一个系统调用另一个系统时,可以考虑捕捉RuntimeException,遇到RuntimeException时使用一个“最合适”的值作为调用的结果,并继续执行当前的流程。 例如,获取商品的折扣失败时,就认定优惠为0,以原价把商品卖给消费者。不过,最好要有配套的动作:

       a.给系统配备实时监控功能,当发生这种事时,运维人员能马上收到通知,解决问题

       b.发生这种事时,应记录日志,供未来审计和业务修正。

    2. 事务最好还是要有的。但如果某些场景下实现事务很难,比如分布式事务,那就让它去吧

    3. 不干净的数据输入最好能通过校验来阻拦掉。如果校验不够充分,数据通过了应用要进入数据库,而且中止当前SQL运行会导致后续SQL都无法执行,那就可以考虑让DBMS容忍这种错误,使用一个“最佳”的数据插入进去。MySql就可以做这种事情。

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.