====== 交易监控中间件_设计 ======
===== 库表设计 =====
==== la_trans_monitor交易监控表 ====
^ 字段 ^ 类型 ^ 是否可空 ^ 约束 ^ 默认值 ^ 备注 ^
| id | int(11) | 否 | 主键自增 | | 主键ID |
| sys_date | Char(8) | 否 | | | 系统日期 |
| sys_time | Char(6) | 否 | | | 系统时间 |
| method_type | varchar(10) | 否 | | | 方法类型,PO:提供对外服务方法,IN:内部服务方法,IO:调用外部方法,SQL:内部sql |
| outer_system | varchar(20) | | | | 外部系统代码 |
| method_route | varchar(200) | 否 | | | 方法路径 |
| method_name | varchar(100) | 否 | | | 方法名称 |
| request | longtext | | | | 入参 |
| response | longtext | | | | 出参 |
| is_exception | int(1) | 否 | | 0 | 是否异常发生,0:没发生异常,1:发生异常 |
| begin_time | timestamp(3) | 否 | | | 开始时间 |
| end_time | timestamp(3) | 否 | | | 结束时间 |
| used_time | bigint | 否 | | | 耗时(毫秒) |
| ip | varchar(50) | | | | 机器ip |
| resv1 | varchar(100) | | | | 备注字段1 |
| resv2 | varchar(100) | | | | 备注字段2 |
| resv3 | varchar(100) | | | | 备注字段3 |
| is_delete | int(1) | 否 | | | 是否删除,0:未删除,1:已删除 |
| created_at | timestamp | 否 | | | 创建时间 |
| updated_at | timestamp | 否 | | | 修改时间 |
===== 切面设计 =====
execution(* com.shhxzq.fin.lifeapp..*.*(..)) 监控 @Service @Controller
around方法前后操作
===== 注解设计 =====
注解@LogMethodTime
{
isMonitor: 是否监控 [true/false]
monitorMethodType: 监控方法类型枚举 [PO/ IN/ IO/ SQL]
outerSystem: 外部系统代码 [be/spw/beidou/cts…]
methodName: 方法名称 [查询是否显示信用卡管理菜单]
resv1: 备注字段1
resv2: 备注字段2
resv3: 备注字段3
}
比如:
@LogMethodTime(isMonitor = true, monitorMethodType =
MonitorMethodTypeEnum.PROVIDE_OUT, methodName = "查询是否显示信用卡管理菜单",
resv1="{request[0].custNo}", resv2="{response}", resv3="NOTHING_HERE!")
public boolean queryShowCreditMenu(QueryShowCreditMenuRequest request) {
...
}
获取[类.方法()]路径,入参,出参,请求时间,结束时间,消耗时间,是否异常发生,本地IP,备注字段1,2,3
===== 备注字段表达式设计 =====
注意:在切面中通过反射解析获取值
(1).普通字符串:直接保存字符串内容
(2).支持表达式:引入commons-jexl3实现类似el/velocity表达式获取对象属性
- 监控方法[获取请求]表达式:{request}
- {request} : 取第一个request参数
- {request[0]} : 取第一个request参数
- {request[1]} : 取第二个request参数
- {request.custNo} : 取第一个request参数的属性
- {request.createdAt.time} : 取第一个request参数的属性的属性
- {request[0].custNo} : 取第一个request参数的属性
- {request[0].createdAt.time} : 取第一个request参数的属性的属性
- {request[1].createdAt.time} : 取第二个request参数的属性的属性
- 监控方法[获取返回]表达式:{response}
- {response} : 取第一个request参数
- {response.custNo} : 取第一个request参数的属性
- {response.createdAt.time} : 取第一个request参数的属性的属性
- 表达式新增分隔符{|}支持,让一个备注字段可以存多个信息"|"拼接
比如:{request[0].custNo}{|}普通字符串{|}{response.userCardDto.bankNo}
===== 备注字段手动设置设计 =====
注意:通过在ThreadLocal中设置值,在切面中获取
- 新增手动设置备注字段方法,不在注解中使用表达式反射(相对提高性能)(但是这种方式有代码侵入到业务中)
- 手动设置备注字段优先级高于(覆盖)注解中的设置(普通字符串/支持表达式)
比如:TransMonitorUtils.setResv1(this.getClass().getName(),
"queryShowCreditMenu", new Object[]{request}, "我的老娘亲!");
===== mq异步推送交易监控信息 =====
异步操作,mq推送交易监控信息,不拖慢主流程
{{:分享:技术:交易监控:sj_1.png?800|}}
===== mq异步消费 =====
insert到库中:la_trans_monitor交易监控表
===== 数据库中数据 =====
{{:分享:技术:交易监控:sj_2.png?800|}}
{{:分享:技术:交易监控:sj_3.png?800|}}
{{:分享:技术:交易监控:sj_4.png?800|}}
===== 查询明细SQL =====
SELECT * FROM la_trans_monitor WHERE 对应条件
===== 统计SQL =====
统计:并发数,平均耗时,TPS
TPS=并发数/平均耗时(s)
######查询结果######
select
#*
#并发数,平均耗时,TPS
count(1), avg(used_time), count(1)*1000.0/avg(used_time)
from la_trans_monitor
######条件######
where 1=1
#and method_type='PO'
#and method_type='IO' and outer_system='be'
#and method_route='com.shhxzq.fin.lifeapp.biz.impl.credit.LaCreditServiceImpl.getUserCardById'
and is_exception=0
#and begin_time between '2017-06-14 11:15:00.000' and '2017-06-15 11:30:00.000'
#and end_time between '2017-06-14 11:15:00.000' and '2017-06-15 11:30:00.000'
#and used_time > 1000
;
===== 实时监控界面 =====
CMS中实现折线图,SQL参考上面统计SQL,可能要实时去计算[每分钟/每10分钟/每小时/每天]的统计数据
如果实时监控查询统计SQL比较慢,后面考虑使用缓存或者异步或者定时去算
====== 附件 ======
{{:分享:技术:交易监控:生活应用交易监控设计.docx|}}