『互联网架构』软件架构-java日志异常(18)

上次说了日志,不知道老铁遇见过没有,日志打印了一大堆,真的去找导致异常和错误的一条没有。出现这个问题的根本原因是什么?就是因为系统没有一个规范的统一的异常规范。有的老铁发现异常后,直接e.printStackTrace() 打印出来堆栈就结束了,其实这样是很危险的。如果前期对异常没有统一的处理,后期在进行统一和调整真心非常非常的困难,异常跟我们的业务逻辑耦合的非常深的。调整统一过来非常非常的难。所以在设计系统的刚开始就必须设计的完善。如果对刚开始的系统异常和业务异常没有规范化,就算后期分布式进行监控的时候也是很困难的,监控系统无法知道是系统异常还是业务异常。无法准确的通知开发人员和运维人员。报警都不知道怎么报警,例如:一个密码输出错误的可能就引发报警,这样的结果是什么?报警量特别特别的大。如果不报警,到时候真出问题了,就玩完了。是不是 进退两难,说也不是,不说也不是。

场景回顾

  • 老铁你遇到过不?

是不是总结的很经典。反正都不是我的锅,大家都是成年人了。

出现异常我们该怎么办

其实反映了问题,如果用户存在问题,只要提示明确,用户都不会反映到电话客服那里。如果还需要用户来反馈,说明系统异常设计的都不合理,我们监控系统没有做到位,用户都知道这个问题了,我们系统还不知道。监控系统需要做到的就是在用户反馈之前先知道。如果异常定义的很棒很坚挺的话,看到提示都知道问题出在哪里了!目前很多系统要定位一个问题需要花很长的时间。才能定位到哪里出的问题。现在咱们就搞明白,到底哪里发生了问题,达到一个目标,快速的响应,快速的知道,对应的问题,定位到问题的根本原因,对方传错了,有明确的指示。不应该把他带到线上,带上生产环境下,应该在上线之前就应该抹杀掉。

系统异常设计的出发点

  1. 良好的异常信息提示,开发运维人员能快速定位
  2. 响应外部调用异常时,应能明确指明是内部异常还是调用条件不满足导至。
  3. 响应用户操作异常时,能友好的提示用户。

异常分类

内部异常

响应没办法按照用户期待的结果返回。

  • 资源环境导致(系统环境异常、数据库连接超时、第三方服务响应超时)
  • 第三方服务错误响应 已经调入到第三方系统上去了,第三方的系统本身软件有bug,导致的
  • 第三方响应结果错误 按照约定返回1和0,结果返回了-1。
  • 外部传入参数非法

别人调用自身的系统,明确的告诉它参数传递错误。

  • 错误的编码逻辑 调用参数,本来传递1-10,结果你传递了11。
  • 错误的配置 上线代码链接的是测试数据库
  • 异常的业务数据(业务数据缺失) 代码传递错误,custId 和 userId写反了。

业务异常

用户操作错误导致的,比如:密码错误。

  • 用户操作错误 捕获异常。
  • 业务条件不满足 业务的时候提前规范。

系统中正确的捕获这类异常,并抛出

1.方法入参进行合法性验证

  • 对系统外部提供的接口(调用后立马验证,不要走了一段逻辑在进行验证),是必须要进行参数验证(必须)
  • 系统内部对外外层提供接口,进行验证
  • 工具类进行参数验证
  • public 方法要进行验证
  • private 方法(不建议参数验证)

2.第三方响应结果合法性验证

  • 获取第三方法结果后,根据你们的约定进行验证

3.业务处理前,对业务业务前置条件进行验证

  • 业务处理前,验证业务条件(验证佘额、验证这个帐户有没有被公安门锁定)
  • 要考虑性能成本(验证身份证号码是不是存在的)

4.业务处理后,对处理结果进行验证

  • 验证对方帐户是不是到帐了,转出帐户是不是成功扣款

5.对于可能会出现异常的代码进行 try catch 捕获

  • 尝试恢复处理
  • 直接抛出
  • 转换后抛出

系统出口统一拦截处理

统一拦截的目的是确定出去的异常是可控的,调用方能够明白异常的信息,这里出口是指系统对外统一响应逻辑,一般我们可分三类场景。 1. Web Response h5,pc页面

  • 内部异常 引导至异常提示页
  • 业务异常 返回对应提示消息至前端
  • 未知异常 尝试进行识别,如果识别不了,转换成异常编码

2. Http API接口响应

  • 内部异常

返回接口不可用消息

  • 参数错误

基于API文档中的异常列表进行响应返回。表明参数非法,需要调用方法加强参数合法性校验

  • 业务错误

基于非约定返回对应code与消息

3. RPC Service接口响应

  • 内部异常

返回服务不可用消息

  • 参数错误

基于接口文档进行响应,直接返回异常堆栈

  • 业务错误

直接返回异常堆栈

checkedException 与uncheckedException 声明原则

    1. 如果是参数非法抛出,返回结果非法(即软件BUG) uncheckedException
    1. 如果你认为调用方程序员需要有意识地采取措施,那么抛出检查型异常。
    1. 程序产品有明确的条件约束的要求,可声明检测型业务异常

统一对异常进行分类处理

  • 异常转换
  • 异常信息处理
  • 逻辑断言
  • 参数合法性验证
  • 返回结果合法性验证

异常捕获

统一对异常进行拦截处理

  • 目的:防止不明确的异常流出系统
  • RPC Service 响应拦截
  • Web Control 响应拦截
  • Http API 响应拦截

常见的错误的异常处理方式

  • 直接勿略异常
try { new String(source.getBytes("UTF-8"), "GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } 
  • 正确的处理
try { new String(source.getBytes("UTF-8"), "GBK"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("环境不支持UTF-8",e) } 
  • 业务异不提供任何信息
public class DuplicateUsernameException extends Exception { }
  • 给每个异常处理都定义一个Code,用一个统一异常替代所有业务异常
public class ServiceException extends RuntimeException { 
public ServiceException(Exception e) {   super(e); } 
public ServiceException(String message) {   super(message); } } 

错误: 1 、必须明确定义业务异常 2、 尽可能申明成checkedException 3要带上具体的业务数 正确方式:定义明确的业务异常

PS:健壮的系统异常的判断尤为重要,不要认为开发完成就完成了,其实在开发过程中,就像装修一样『前门』很光鲜,『后门』也得控制好。万一别人没从『前门』进来,要求让带个钥匙进门,结果拿个斧子进『后门』呢?

原文发布于微信公众号 - 编程坑太多(idig88)

原文发表时间:2019-02-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券