安全开发与发布的基本准则
遵循一套用于安全开发和发布的准则,为开发活动编织一张质量安全网,尽可能降低出问题的概率。
影响面评估准则
确保代码安全的第一准则是:代码的影响面评估。在核心流程里的一行代码的影响面,胜于在非核心流程里的百行代码的影响面。
新手工程师,往往容易见树不见林,着眼于眼前的功能,而未察觉对现有或全局的负面影响。
- 在核心流程或通用方法里加代码时,要谨慎。哪怕是一行,都可能会出问题。
- 尽量避免修改原有方法的签名。使用重载方法或拷贝方法来解决。如果原有方法只有一个调用方,可以这么做,但要回归影响的功能;如果有两个调用方,谨慎这么做;如果有三个调用方,避免这么做【因为回归量可能很大,超出所能预料】。
- 实现眼前的功能时,要同时关注会被影响的功能。
- 修改的方法有很多调用方时,要考虑兼容,评估每个被影响到的方法及风险。
- 新增而不修改原有代码,通常不会出问题。努力做到开闭原则:“对修改关闭,对扩展开放”。
- 新增配置而不修改原有配置,通常不会出问题。但是“老配置+新应用”会导致问题。
- 当用新做法替换原有做法时,尤其要回归所有影响到的点。
- 对可能产生风险的代码敏感。
- 勿存侥幸心理;勿对代码过于自信。
健壮性准则
很多线上问题出在代码的不健壮性上。即使引发的是小问题,未导致故障,但修复时也要重新测试和发布,耗时耗力。
- 在核心流程里解析不可靠的数据(尤其是 JSON 数据)时,加 try-catch 。
- 在整体流程中流经的确定很可能会抛出异常的代码,如果不期望影响整体的执行完成,加 try-catch 。
- 在整体流程中流经的不确定是否有场景会导致抛出异常的代码,加 try-catch。
- 避免链式地获取嵌套对象的属性,很容易导致 NPE 。
- 对 API 返回结果判空。
- 对不太确定是否为空的对象或容器判空。
- 考虑对原有情况的兼容。
不可变准则
修改入参,使用全局变量,往往使得程序行为更难推测,错误潜藏非常隐秘,出问题后排查也会非常耗时。
- 避免修改方法入参(对象或容器)。
- 使用 stream.filter 替代删除列表中的元素。
- 当需要修改入参来实现时,总是考虑通过返回对象来替代。
- 提供 merge 操作优化修改入参。
- 避免使用全局变量。
快速失败准则
快速失败是避免产生大量脏数据的法宝之一。
- 如果一项功能需要多个前置条件同时具备才能正确运行,错误运行会导致不可确定的结果时,在任一条件不具备时,及时抛出异常终止。
重大重构准则
- 尽可能新增接口/链路而非修改原来的。
- 使用策略模式分离新链路和旧链路。
- 增加开关,能够快速切回原来的服务。
- 确保可快速回滚【应用及配置】。
- 通过逐步分流来切入新流量,冷却老流量。
- 用次要的影响面小的业务进行线上试点。
并发安全准则
- 单例组件类尽可能只引用不含有实例成员的单例组件。
- 组件类避免含有可变的实例成员;这种设计容易潜藏难以觉察的并发风险。
- 如果组件类含有可变的实例成员,则要么确保不在并发环境使用,要么添加组件的原型声明。
- 生产环境里使用全局配置良好的线程池,而不是简陋配置的线程池。
- 避免在方法里动态创建线程池。除非这是一个小流量应用,且方法调用很少。
大流量准则
- 应对流量大的长耗时任务,限制指定时间段的处理数量。
- 应对流量大的工具需要加限速能力;限速可动态调整。
- 降级非核心服务和数据,可配置。
- 数据存储冗余或优化,减少为了取少量次要数据而导致的外部服务调用。
- 实时性要求不高的场景,采用延时队列或非实时接口来处理。
关键日志准则
- 核心链路和关键数据必须打日志;方便排查问题。
- 已预估的出错或致命问题的打错误日志;发布时要尤其关注此类日志。
- 不影响系统运行的错误打警告日志;避免干扰发布是否OK的判断。
提前预知准则
- 对于预发上报出的任何问题保持敏感。因为那可能是老天爷在提醒你。
- 对于返回大量数据的查询服务类,可以使用对比引擎来比较线上和预发的返回结果。
严格测试准则
- 单测全部通过;不可绕开原有单测。
- 无论改动大小,均要自测。
- QA 和预发测试,自测通过。
- 已有测试用例全部通过。
安全发布准则
- 一个项目涉及多个应用和配置时【应用+配置 > 3 时】,一定要制定发布文档,指明配置与应用的发布顺序,以及不遵循该发布顺序时会导致的风险。
- 发布文档的细节必须非常具体明确,每一个操作和命令都毫无歧义。即使换另一个人来发布,只要按步骤执行,就不会出问题。
- 发布 4 个以上应用时,应找团队其他小伙伴协助,减少因发布压力过大可能导致的误操作或长耗时。
- 发布多个应用时,在代码实现考虑兼容,确保部分可以提前发布或者并行发布。
- 发布时要专注,不允许被打断;发布后一小时内应持续观察,尽量不要离开。
- 节前非重要紧急问题避免发布;与产品同学协商好,改日发布。
- 由于配置切换导致线上容易产生大量脏数据,或者需要修复很多数据时,最好凌晨发布。 尽量一次性解决,而不要累积起来多次解决【捞数据和修复数据的成本有时很大】。
- 涉及很多配置和 DDL 的大项目发布,最好凌晨发布。有充足的时间测试回归。
- 开发与发布前,确保 QA 和预发、线上的配置是一致的。配置不一致,可能会导致 QA 和预发的测试OK,但是到线上就会出问题。
- 使用灰度发布或蓝绿发布;白名单验证;分流发布;分批发布;