异常体系与项目实践
Posted 知了一笑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异常体系与项目实践相关的知识,希望对你有一定的参考价值。
程序式阴影:为什么不报错?
一、简介
在程序开发的过程中,异常处理从来都是一个复杂的维度,无论是新手还是经验老到的选手,在编码时都会面对各种异常情况;
程序中的异常可以反映系统的缺陷和待优化的点,并且是无法完全避免的,如何处理异常和降低异常出现的频率,是系统质量的基础保障;
随着分布式架构的流行,各种复杂的请求链路给异常处理带来了巨大的麻烦,需要全面的监控来定位原因,才能快速的优化和解决;
二、异常体系
不论是JDK基础,还是各类组件,在源码中都涉及大量的异常封装,从而精确的反映出描述信息,先来看看Java中的异常体系基础;
Throwable:是所有错误「Error」和异常「Exception」的超类,
Error:通常是底层的不可恢复的类,此类错误一般都比较严重,JVM将终止其运行的线程;
Exception:程序自身可以捕获并且可以预处理的异常,例如捕获处理或者抛出;
针对「编译器」来说,异常又分为「检查」异常和「非检查」异常;
检查异常:即编译时异常,在编译时期就会被编译器查验到的异常,这类异常要么捕获处理要么抛出,否则就会报编译错误;
非检查异常:即运行时异常,在编译时期不会被编译器查验到的异常,这类异常只有在程序运行的时候,才会有可能被抛出;
三、异常用法
1、使用细节
Java异常处理关键字,分别是:「try」可能抛异常的代码块,「catch」捕获异常、「finally」必须执行的代码块、「throw」方法内抛指定异常、「throws」方法声明抛多个异常;
public class UseExe01
public static void main(String[] args)
try
strStm ();
ioStm();
catch (NullPointerException e)
System.out.println("空指针异常:"+e.getMessage());
e.printStackTrace();
catch (IOException e)
System.out.println("IO流异常:"+e.getMessage());
e.printStackTrace();
catch (Exception e)
System.out.println("异常:"+e.getMessage());
e.printStackTrace();
finally
System.out.println("execute...finally");
public static void ioStm () throws FileNotFoundException
new FileInputStream(new File("file_path"));
public static String strStm () throws NullPointerException
Object object = new Object() ;
return object.getClass().getName() ;
案例分析
细节分析
- 如果「try」代码块中没有抛出异常,执行完会跳到「finally」代码块;
- 如果「try」代码块中抛出异常,则执行「catch」代码块,无论是否捕获异常,最终都要执行「finally」代码块;
- 可以存在多个「catch」代码块,但是最多只匹配一个异常;
- 捕获异常与抛出异常的类型可以匹配,或者捕获异常的类型是抛出异常的父类;
- 在异常捕获时,同一个继承体系内,先捕获子类异常,再捕获父类异常;
2、返回值问题
在异常处理逻辑中,有一个非常经典的问题,就是「return」返回值,如果在「try.catch.finally」代码块中都存在「return」关键字,则要分情况讨论;
2.1 值类型
public class UseExe02
// 返回【2】
public static int getInt1 ()
try
int i = 1 / 0;
catch (ArithmeticException e)
e.printStackTrace();
return 1;
finally
System.out.println("execute...finally");
return 2;
// 返回【1】
public static int getInt2 ()
int a = 1;
try
int i = 1/0;
return a;
catch (ArithmeticException e)
e.printStackTrace();
return a;
finally
++a;
System.out.println("execute...finally");
// 返回【3】
public static int getInt3 ()
int a = 1;
try
int i = 1/0;
a++;
return a ;
catch (ArithmeticException e)
a++;
e.printStackTrace();
finally
a++;
System.out.println("execute...finally");
return a ;
逻辑分析
2.2 引用类型
public class UseExe03
// 返回【张三】
public static String getStr1 ()
String var ;
try
var = new String("张三");
return var ;
catch (ArithmeticException e)
e.printStackTrace();
finally
var = new String("李四");
System.out.println("execute...finally:"+var);
return var ;
// 返回【李四】
public static String getStr2 ()
String var ;
try
int i = 1/0;
var = new String("张三");
return var;
catch (ArithmeticException e)
e.printStackTrace();
var = new String("李四");
return var;
finally
var = new String("王五");
System.out.println("execute...finally:"+var);
// 返回【王五】
public static String getStr3 ()
String var ;
try
int i = 1/0;
var = new String("张三");
return var ;
catch (ArithmeticException e)
var = new String("李四");
e.printStackTrace();
finally
var = new String("王五");
System.out.println("execute...finally:"+var);
return var ;
逻辑分析
2.3 结论说明
- 如果只有「try」代码块中有「return」关键字,逻辑执行正常则得到「try」处的返回值;
- 如果只有「try.catch」代码块中有「return」关键字,「try」代码块异常,「catch」代码块执行正常,则得到「catch」处的返回值;
- 如果「finally」代码块中有「return」关键字,当该代码块执行正常时会得到此处的返回值;
值得说明的一点是,从异常的设计原理来来说,并不推荐在「finally」代码块中使用「return」关键字,可能会导致程序提前结束,这也是常见的开发规范;
四、项目实践
1、异常定义
对于复杂的分布式工程来说,系统发生问题时,十分依赖异常信息的捕获,从而快速定位原因和解决;
项目在处理异常时,需要考虑两个核心维度:「1」捕获和解决异常信息,「2」传递异常信息到应用端,从而引导用户的动作;
在系统中,通常依赖很多自定义的异常,比如常见:系统异常,业务异常,第三方异常;基本都是「运行时」异常;
系统异常:比如超时请求或者服务级别异常,导致流程无法执行,需要研发人员介入处理;
业务异常:基于响应的提示信息,用户可以自行解决的问题,比如常见的参数校验,授权问题等;
第三方异常:可以是内部不同系统的交互,也可以是第三方的交互,可能会涉及到各种响应状态,通过内部的封装进行统一管理,并且要保留第三方的响应;
2、异常封装
基于运行时异常「RuntimeException」类,分别定义「系统」、「业务」、「第三方」三类异常;
自定义异常基础类,注意此处省略很多构造方法,作为「RuntimeException」的子类,具体参考其源码的构造方法即可;
public class BaseExe extends RuntimeException
private String code ;
public BaseExe (String code,String msg)
super(msg);
this.code = code ;
public BaseExe(String message, Throwable cause)
super(message, cause);
// 省略其他构造方法
系统异常类,并提供常用的系统异常信息枚举类;
public enum SysExeCode
SYSTEM_EXE("S00000", "系统异常");
public class SysException extends BaseExe
public SysException(String code, String msg)
super(code, msg);
public SysException(SysExeCode sysExeCode)
super(sysExeCode.getCode(), sysExeCode.getMsg());
业务异常类,并提供常用的业务异常信息枚举类;
public enum BizExeCode
BIZ_EXE("B00000", "业务异常");
public class BizException extends BaseExe
public BizException(String code, String msg)
super(code, msg);
public BizException(BizExeCode bizExeCode)
super(bizExeCode.getCode(), bizExeCode.getMsg());
第三方异常类,并提供常用的第三方异常信息枚举类;
public enum ThirdExeCode
THIRD_EXE("T00000", "第三方异常");
public class ThirdException extends BaseExe
// 第三方交互异常响应信息
private String thirdCode ;
private String thirdMsg ;
public ThirdException(String code, String msg)
super(code, msg);
public ThirdException(String code, String msg,String thirdCode,String thirdMsg)
super(code, msg);
this.thirdCode = thirdCode ;
this.thirdMsg = thirdMsg ;
public ThirdException(ThirdExeCode thirdExeCode,String thirdCode,String thirdMsg)
super(thirdExeCode.getCode(), thirdExeCode.getMsg());
this.thirdCode = thirdCode ;
this.thirdMsg = thirdMsg ;
从开发规范来说,不允许在代码中随意添加异常描述信息,必须都维护在相应的枚举类中,不同的异常类型,要在合适的场景下抛出,尽量由最上层统一捕获并处理,再转换为统一的响应结果;
3、异常处理
3.1 响应方式
在微服务项目中,通常采用RestControllerAdvice
和ExceptionHandler
注解,实现全局异常的捕获和处理;
@RestControllerAdvice
public class ExeHandler
/**
* 默认异常
*/
@ExceptionHandler(value = Exception.class)
public void defaultException(Exception e)
// 统一返回
/**
* 系统异常
*/
@ExceptionHandler(value = SysException.class)
public void sysException(SysException e)
// 统一返回
/**
* 业务异常
*/
@ExceptionHandler(value = BizException.class)
public void bizException(BizException e)
// 统一返回
/**
* 第三方异常
*/
@ExceptionHandler(value = ThirdException.class)
public void thirdException(ThirdException e)
// 统一返回
3.2 记录方式
通常在一些核心的业务流程中,会通过注解的方式记录日志,于研发而言,最关心的还是异常日志,以此为逻辑优化的关键依据;
比较常用的技术手段是自定义注解+切面编程来实现,细节参考开源仓库中《集成日志,复杂业务下的自定义实现》篇幅内容;
@Component
@Aspect
public class LogAop
/**
* 日志切入点
*/
@Pointcut("@annotation(com.defined.log.annotation.DefinedLog)")
public void logPointCut()
/**
* 环绕切入
*/
@Around("logPointCut()")
public Object around (ProceedingJoinPoint proceedingJoinPoint)
try
// 执行方法
result = proceedingJoinPoint.proceed();
catch (SysException e)
// 系统异常
catch (BizException e)
// 业务异常
catch (ThirdException e)
// 第三方异常
catch (Exception e)
// 默认异常
finally
// 信息处理
return result ;
4、异常通知
抛开业务异常不说,对于「系统」和「第三方」异常,通常都会第一时间触达到研发,从而快速定位原因和处理;
一般会根据异常的级别,将进行不同维度的消息触达,比如某微,某钉,邮件,短信等;
从技术的实现上来看,常规也是采用切面编程的方式,细节参考开源仓库中《基于AOP切面,实现系统告警功能》篇幅内容;关于消息中心的搭建设计,同样可以参考开源仓库中《聊聊消息中心的设计与实现逻辑》篇幅内容;
5、系统故障
从系统架构的层面来分析,大部分组件都提供了必要的监控能力,而这种监控手段的核心价值在于快速发现故障,并且提供一定的分析能力;
比如分布式系统中,复杂的请求的链路,对于故障的定位和排查难度都是极大的,需要将各种组件的监控信息进行统筹分析;
系统层面监控
请求链路分析
日志记录能力
可以从关键的日志记录作为问题切入点,再基于系统层面的监控能力缩小问题范围,分析请求链路的异常原因,最后通过完整的日志分析细节,从而提升问题解决的效率;
关于这些技术的应用,在开源仓库中都有详细案例,此处不再赘述;
五、参考源码
编程文档:
https://gitee.com/cicadasmile/butte-java-note
应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent
赵毅:基于大数据平台构建数据仓库的研究与实践|恒银论坛
作者赵毅系恒丰银行科技开发部副总经理。
摘要
恒丰银行通过大数据平台构建数据仓库的项目实践,逐渐建立起全行数据综合服务体系,即报表和查询体系、基于专业引擎的数据计算访问体系、数据分析服务体系、数据挖掘体系,最终形成了数据应用价值到最终用户的合理传导机制。本文曾发表于《中国金融电脑》2017年第5期,部分内容有所更新。
恒丰银行原传统数据仓库是建立在IOE(IBM、ORACLE、EMC)传统架构体系上,已接入数据源系统有30多个,配套建立监管数据集市、数据分析集市、风险数据集市三个主要数据集市,负责十几个管理应用和监管系统的数据需求,下游建有银行管理类系统如综合经营分析系统(管理驾驶舱)、自定义查询平台等,并为各分行提供数据下发服务。
随着恒丰银行各类业务快速发展以及与外部机构跨界合作的展开,历史数据越来越多,半结构化数据、非结构数据也越来越多,数据的统一存储和处理面临硬件成本和访问压力等问题,原有的技术架构体系越来越不适应业务发展要求,无法满足金融科技环境下银行对大数据的应用创新需求。
本文根据恒丰银行在大数据平台建设上的经验提供解决上述问题的实践案例,案例中在技术架构上大数据技术可以解决已有数据仓库的性能瓶颈问题;在业务层面,大数据平台体系的数据仓库能够利用数据创造更多的业务价值,为银行经营决策者制定方案提供更合理的数据参考。
一、大数据对银行数据管理的挑战
在日益激烈的国际、国内行业竞争环境下,商业银行努力优化服务结构、迅速响应市场变化、精细化管理决策,以求在新环境下抓住新机遇。在这一背景下,商业银行逐渐寻求技术突破,通过科技驱动业务变革、提升业务价值,走在行业前列。但应看到,在互联网、大数据技术日新月异的今天,商业银行面临着诸多挑战。
首先,商业银行面临着全量、多维、更新迭代迅速的数据冲击,对数据的采集、存储、应用、分析、管控、扩容均提出了新的挑战。虽然数据仓库系统在商业银行已发展十余年,但由于单节点处理能力较弱,以Scale-up纵向扩容方法提升硬件能力的方式成本高昂,性能提升有限,已无法满足业务快速发展的需要。
其次,随着商业银行业务日益多样化、复杂化,业务系统越来越多,数据孤岛效应凸显,数据系统分开建设,数据架构设计中的职责划分不合理,系统之间存在重复加工、统计口径不一致、大量数据冗余的现象,系统之间无法形成协同效应。
最后,由于商业银行业务场景的变化,业务部门对于实时决策的要求越来越强烈。例如,实时精准营销、实时风险预警,都要求数据仓库有高并发、低延迟、非结构化的数据处理能力。而传统数据仓库由于技术架构上的天然局限难以满足此类场景的数据探索需求。
二、恒丰银行大数据平台建设实践
恒丰银行处于业务发展的新阶段,新业务模式的创新对数据信息服务的总体能力提出了新的要求,需要一个低成本可线性扩展的统一数据处理平台,解决企业多个数据应用形成数据孤岛,导致数据资源难以共享、数据标准不一、存在大量冗余数据的问题。但现有的主流数据库技术因为系统架构陈旧已经不能满足业务发展需要,开源大数据技术在商业银行企业级应用场景下还有诸多不完善的地方。
2015年,恒丰银行在开源软件、国产大数据平台的基础上,自主设计开发建设企业级大数据应用平台,利用全新的大数据平台技术全面重构了企业数据仓库应用,满足海量结构化与非结构化数据的低成本加工存储、快速统计分析、业务模型探索、实时分析与决策等需求。结合大数据技术服务能力,升级改造原有的渠道、授信管理、审计、客户管理等系统,在客户服务、风险管理、内部管控、流程优化、营销管理等多个业务领域提升恒丰银行的运营效率和市场竞争力。
(一)数据仓库技术平台选型
基于银行当前应用数据能力的要求,新一代企业级数据仓库应具备如下技术能力:
1.支撑海量数据存储和低延迟联机查询。将企业主要数据汇聚到一个平台上,支持大并发的低延迟联机查询,这也是一般企业应用大数据能力的初步目标。
2.支持统计分析应用。包括即席业务统计报表、多维业务数据分析、客户群体细分等应用,一般可替代传统数据仓库的主体功能。
3.数据探索与业务预测。支持业务分析团队的数据探索和业务建模实验,实现诸如业务趋势预测、客户行为预测等高阶应用。
4.决策支持能力。通过应用决策树、规则推理引擎、运筹优化技术,实现客户定价、风险预警等领域特定业务问题的机器自动化流程管理和简单人机交互方式的辅助业务决策支持应用。
5.自主学习能力。通过引入深度学习网络、知识图谱、遗传演化等智能技术构建相对复杂的机器智能学习体系,能从海量数据中提炼高价值信息,构建自主训练与反馈、可不断从最新数据中调整演化的智能业务模型体系。
以Hadoop/Spark为代表的大规模数据处理技术为超越传统数据库的处理局限性提供了先进的并行计算和资源调度框架。在经过充分评测后恒丰银行最终确定采用Hadoop/Spark架构作为新一代企业大数据平台的基础设施组件。
该平台具备高模块化和松耦合架构,针对不同的应用领域通过组件之间的灵活组合与高效协作来提供定制化的大数据平台支撑;此外,平台已全面支持SQL、PL/SQL标准数据库语言及Oracle、DB2、MySQL、SQLServer等多种银行传统应用数据库,结合自身数据挖掘与机器学习组件,能够构建起强大的数据分析生态系统。
(二)大数据平台层次化架构设计
基于大数据平台构建的新一代数据仓库的整体架构(如图1所示包括如下层级结构),完成对数据源存储、加工、应用、输出、数据管理等各层面的重构。
1.源系统结构化数据:源系统按大数据平台的供数规范要求提供表数据文本和标志文件。
2.文件交换区FSA:文件的交换中枢,含源系统结构化数据和半结构化、非结构化数据(主要是外部数据)。
3.源数据缓存区ODM:结构化数据接入,在线数据平台的源数据历史层HDM、基础数据模型层的数据来源。
4.源数据历史层HDM:源数据缓存区数据接入。
5.基础数据模型层FDM:源数据按数据仓库模型加工后存储,源数据缓存区数据接入,公共数据模型层CDM的主要数据来源。仅大数据平台各数据层数据存储和内部流转用。
6.公共数据模型层CDM:聚焦客户营销和风险管理的银行信息资产加工和存储,源数据缓存区、基础数据模型层数据接入,数据服务接口的主要数据来源。
7.数据服务接口DSI:在线数据平台的对外数据服务接口,源数据历史层、公共数据模型层数据接入,BI应用集市的唯一数据来源。
8.历史数据服务接口:历史数据平台的对外数据服务接口,源数据历史层、公共数据模型层数据接入,各类查询应用的唯一数据来源。
9.综合监管集市:试点应用银监标准化EAST所在的综合监管集市,数据服务接口的数据接入,综合监管应用的唯一数据来源。
10.数据分析集市:BI统计分析类应用所在的数据集市,公共数据汇总层ADM的加工和存储,数据服务接口的数据接入。
11.统一调度平台:大数据平台ETL过程的统一作业调度监控,包括:调度、监控、日志、处理四部分内容。
(三)原关键数据仓库应用迁移
新一代数据仓库逻辑架构主要包括在线数据平台与历史数据平台两部分。在线数据平台将对原有数据仓库的体系进行重构,向业务人员提供更多更全的业务数据及更加高效便捷的模型数据。历史数据平台实现对历史数据的永久存储,并能够提供给用户历史数据查询的数据服务接口。
应用迁移的主要目标是建设在线数据平台、历史数据平台,设计公共数据模型,并实现银监标准化系统(EAST)的数据切换。整体设计思路分为数据移植、在线数据平台、历史数据平台、银监标准化(EAST)四个部分。
1.梳理数据移植流程
(1)利用Sqoop技术连接原数据仓库抽取数据到hdfs文件系统;
(2)将原数据仓库的数据抽取到hdfs文件系统后,在大数据平台中构建映射在这些数据文件上的外表,其表结构与原数据仓库表结构一致;
(3)在构建外表后,数据平台已可以查询到原数据仓库的数据,为构建数据平台的HDM层源数据备份,还需将这部分的数据进行还原操作。
数据移植流程如图2所示。
2.建立在线数据平台
在线数据平台集中了源数据缓冲层、源数据历史层、基础数据模型层和公共数据模型层。源数据缓冲层作为外部业务系统数据接入层,单日缓存业务系统每日数据,供历史明细层程序处理已存入基础数据平台。源数据历史层是对业务系统源数据进行初步清理后,粗放在数据平台中,保留历史原貌。基础数据模型层保留了原数据仓库部分基础数据模型,以支持公共数据模型及其他应用数据需求,保存模型历史数据。公共数据模型层为数据仓库的主体数据体,是支撑数据汇总、数据分析的多纬度数据集市。
3.建立历史数据平台
历史数据平台是在线数据平台的数据备份,实现每日数据同步。历史数据平台源数据备份结构与在线数据平台一致,保存永久数据。历史数据平台公共数据模型备份结构与在线数据平台一致,永久保存数据。并依托公共数据模型的历史,构建历史数据查询服务模型接口。
4.重构银监标准化(EAST)应用
银监标准化EAST系统改造内容主要是数据连接改造(JDBC-hadoop)和参数配置调整,不包括系统功能和流程。由于EAST系统数据结构为Oracle表,存储过程为Oracle存储过程,需根据大数据平台的特性对表结构进行重构,支持大数据平台的存储过程格式,并进行数据移植。
(四)注重公共模型开发
恒丰银行当前数据仓库存在应用离散、冗余数据加工、资源紧张等问题。所以,公共数据模型的建设需要统一需求管控,建立更大的项目资源池,减少重复开发,规划应用方向;统一计算口径,减少数据冗余和数据复制,减少重复数据加工。同时,能够满足不同应用场景的共性需求,稳妥推进新技术应用。公共数据模型层建设原则如图3所示。
在主题模型领域,根据主题+业务方式进行数据存储,以具体业务为依据提练主题要素,涵盖客户、事件、产品、作业、财务绩效、资产管理、市场与公共元信息(如费率、利率与汇率)。依据可重用性、安全性、高可用性、可管理性、可扩展性、高性能的设计原则,采取总体规划、分层实现的方式。以底层软硬件与数据相结合,需求与问题驱动,建设良好公共数据模型层,便于数据更直观完善的展现,为业务和决策人员的分析决策提供良好的支持。公共数据模型层的整体规划如图4所示。
构建公共模型层,数据来源主要包括行内数据、同业数据和外部数据三大部分。
1.行内数据:行内的业务系统、管理系统数据包括核心、企贷、个贷、国结等数十个源系统数据。九大类数据整合为公共数据模型七大主题,根据相应主题+业务划分对源数据进行重新整合分类归总。
2.同业数据:同业数据包括监管当局和其他银行披露的各项业务指标——规模数据、盈利数据、风险数据。
3.外部数据:从外部采购或抓取的数据,如征信、舆情、宏观数据。
(五)开发专业数据集市与数据应用
恒丰银行详细规划了各管理分析领域的业务应用场景,形成了营销主题、风险主题、客户主题、资讯主题、运营主题、绩效主题等专业共享数据集市,为具体管理分析域的业务应用提供了基础明细层、共享加工层、结果数据存储和对外服务接口。
在数据应用方面,大数据平台项目一期已经陆续构建了信贷工厂、报表平台、精准营销、全面风险预警、客户关系管理CRM、财富管理系统、大数据资讯平台、反欺诈、信用卡交易监测、数据可视化、客户生命周期管理、运营风险监测等40多个上层应用。在二期项目规划中,还包括决策管理引擎、用户画像与营销推送、实时风险监控等数据应用,充分发挥大数据平台在海量数据计算、非结构化数据处理、实时流数据处理、内存计算与列式存储等领域的能力与优势。
通过大数据平台的业务建模能力,为全行数据价值发现提供了领域技术基础;通过数据探索、机器学习模型与算法,为业务部门从行内外海量数据中寻找价值突破口提供实践依据。
三、大数据平台建设取得的成效
目前,基于大数据平台的数据仓库已全面上线,并支撑全行统一数据管理与数据服务。通过本次项目的技术实践和应用系统的逐步落地,恒丰银行实现了成本管理与业务管控的双效提升。
在经济效益层面,经初步估计,企业数据应用的总体硬件投入成本将降为原来的1/5~1/10,数据库软件授权许可费更是只有原来的1/20;同时由于各应用建构在同一个数据平台,每个应用减少了大量的共性数据加工和数据共享代码开发,软件开发成本也得到了降低,预计每年为恒丰银行节约上千万元的软硬件投入和系统运维成本。
在生产效率层面,原有传统数据仓库的大数据量跑批处理往往需要4~5小时,新一代大数据平台的分布式计算能力,结合内存处理技术,处理同样数据量级的工作仅需数十分钟,大大提升了营销、风控、运营等业务流程的响应能力。
考虑到系统实现的新技术能力以及业务分析团队获得更高时效性的数据资源和更快的数据分析和建模能力,能创造的隐性业务价值也是非常可观的。
大数据平台逐渐成为全行数据管控的枢纽和压舱石。恒丰银行通过大数据平台构建数据仓库的项目实践,逐渐建立全行数据综合服务体系,即报表和查询体系、基于专业引擎的数据计算访问体系、数据分析服务体系、数据挖掘体系,最终形成了数据应用价值到最终用户的合理传导机制。
以上是关于异常体系与项目实践的主要内容,如果未能解决你的问题,请参考以下文章