我们已经不用AOP做操作日志了! | 原力计划

来源 | JAVA葵花宝典
责编 | 王晓曼、Carol
 头图 | CSDN下载自东方IC

前言


用户在操作我们系统的过程中,针对一些重要的业务数据进行增删改查的时候,我们希望记录一下用户的操作行为,以便发生问题时能及时的找到依据,这种日志就是业务系统的操作日志。

本篇我们来探讨下常见操作日志的实现方案和可行性!

常见的操作日志类型

  • 用户登录日志

  • 重要数据查询日志 (但电商可能不重要的数据也做埋点,比如在淘宝上你搜索什么商品,即使不买,一段时间内首页也会给你推荐类似的东西)

  • 重要数据变更日志 (如密码变更,权限变更,数据修改等)

  • 数据删除日志

  • ......

总结来说,就是重要的增删改查根据业务的需要来做操作日志的埋点。

实现方案对比


1、基于AOP(切面)传统的实现方案

  • 优点:实现思路简单;

  • 缺点:增加数据库的负担,强依赖前端的传参,不方便拓展,不支持批量操作,不支持多表关联;

2、基于数据库Binlog

  • 优点:解除了数据新旧变化的耦合,支持批量操作,方便多表关联拓展,不依赖开发语言;

  • 缺点:数据库表设计需要统一的约定;

方案实现细节


1、基于AOP切面+注解的传统方案

传统的做法就是切面+注解的方式,这种对代码的侵入性不强,通常记录ip、业务模块、操作账号、操作场景、操作来源等等,一般在注解+拦截器里这些值都拿得到,如下图所示:

这种常见的我们在通用方法都可以处理,但是在数据变更方面,一直没有较好的实现方式,比如数据在变更前是多少,变更后是多少。

以我们以前实现的一套方案来说,基于数据变更的记录方式不仅要和需求方约定好模板(上百个字段的不可能都做展示和记录),也要和前端做一些约定,比如在修改之前的值是多少,修改后的值是多少,如下代码客观请看:

    @Valid@NotNull(message = "新值不能为空")@UpdateNewDataOperationLogprivate T newData;@Valid@NotNull(message = "旧值不能为空")@UpdateOldDataOperationLogprivate T oldData;
存在的问题:
  • 旧值如果不多查询一次数据库则需要依赖前端把旧值封装到oldData对象中,很有可能已经不是修改前的值;

  • 无法处理批量的List数据;

  • 不支持多表操作;

再以一个场景为例,再删除之前需要记录删除前的值,是不是还得再查一次~

@PostMapping("/delete")
@ApiOperation(value = "删除用户信息", notes = "删除用户信息")
@DeleteOperationLog(system = SystemNameNewEnum.SYS_JMS_LMDM, module = ModuleNameNewEnum.LMDM_AUTH, table = LogBaseTableNameEnum.TABLE_USER, methodName = "detail")
2、基于数据库Binlog 方案

系统架构图如下:


「主要分为3块:」

  • 业务应用:生成每次操作的traceid,并更新到操作的业务表中,发送1条业务消息,包含当前操作的操作人相关的信息;

  • 日志收集应用:对业务日志和转换后的binlog日志做整合,提供对外的日志查询搜索API;

  • 日志处理应用:利用canal采集和解析业务库的binlog日志并投递到kafka中(实现方案可以参考《如何基于Canal和 Kafka,实现 MySQL 的Binlog 近实时同步?》),解析后的记录中记录了当前操作的操作类型,如属于删除、修改、新增,和新旧值的记录,格式如下:

{"data":[{"id":"122158992930664499","bill_type":"1","create_time":"2020-04-2609:15:13","update_time":"2020-04-2613:45:46","version":"2","trace_id":"exclude-f04ff706673d4e98a757396efb711173"}],
"database":"yl_spmibill_8",
"es":1587879945200,
"id":17161259,
"isDdl":false,
"mysqlType":{"id":"bigint(20)",
"bill_type":"tinyint(2)",
"create_time":"timestamp",
"update_time":"timestamp",
"version":"int(11)",
"trace_id":"varchar(50)"},
"old":[{"update_time":"2020-04-2613:45:45",
"version":"1",
"trace_id":"exclude-36aef98585db4e7a98f9694c8ef28b8c"}],
"pkNames":["id"],"sql":"",
"sqlType":{"id":-5,"bill_type":-6,"create_time":93,"update_time":93,"version":4,"trace_id":12},
"table":"xxx_transfer_bill_117",
"ts":1587879945698,"type":"UPDATE"}
处理完Binlon日志转换后的操作日志:
  {"id":"120716921250250776","relevanceInfo":"XX0000097413282,","remark":"签收财务网点编码由【】改为【380000】,签收网点名称由【】改为【泉州南安网点】,签收网点code由【】改为【2534104】,运单状态code由【204】改为【205】,签收财务网点名称由【】改为【福建代理区】,签收网点id由【0】改为【461】,签收标识,1是,0否由【0】改为【1】,签收时间由【null】改为【2020-04-24 21:09:47】,签收财务网点id由【0】改为【400】,","traceId":"120716921250250775"}

库表设计

  • 所有业务系统表需要添加trace_id字段,每次操作生成一个随机字符串并保存到业务表中;

  • 日志收集应用库表设计。

CREATE TABLE `table_config` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`database_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '数据库名',`table_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ' 数据库表名',PRIMARY KEY (`id`),UNIQUE KEY `unq_data_name_table_name` (`database_name`,`table_name`) USING BTREE COMMENT '数据库名表名联合索引'
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库配置表';
CREATE TABLE `table_field_config` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`table_config_id` bigint(20) DEFAULT NULL,`field` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字段 数据库',`field_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字段 中文名称',`enum_flag` tinyint(2) DEFAULT NULL COMMENT '是否枚举字段(1:是,0:否)',`relevance_flag` tinyint(2) DEFAULT NULL COMMENT '是否是关联字段(1:是,0否)',`sort` int(11) DEFAULT NULL COMMENT '排序',PRIMARY KEY (`id`),KEY `idx_table_config_id` (`table_config_id`) USING BTREE COMMENT '表ID索引'
) ENGINE=InnoDB AUTO_INCREMENT=2431 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库字段配置表';
CREATE TABLE `table_field_value` (`id` bigint(20) NOT NULL,`field_config_id` bigint(20) DEFAULT NULL,`field_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ' 枚举',`filed_value` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '枚举名称',PRIMARY KEY (`id`),KEY `ids_field_config_id` (`field_config_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据字典配置表';

效果:

3、基于Binlog实现方案未来规划

  • 优化发送业务消息的实现,使用切面拦截减少对业务代码的侵入;

  • 目前暂时不支持对多表关联操作日志记录,需要拓展。

总结


本文以操作日志为题材讨论了操作日志的实现方案和可行性,并且都已经在功能上进行实现,其中使用AOP方案也是大部分中小企业的首选实现方案,但是在一些金融领域以及ERP相关系统,对操作日志记录明细要求极高,常见技术方案很难满足。

即使能够满足也会带来一些代码强侵入以及性能问题,所以我们又讨论了基于Binlog实现的方案,该方案虽然比对AOP来说增强了技术的复杂性,但是对于有一定技术积累的团队来说不算什么难事,并且该方案我们都实现了上线,并且解决了代码层面上的侵入,属于跨语言级别的,相信对读者还是有一定的启发。

 

推荐阅读

  • 一文带你从头认识什么是「缓存」!

  • 在 520 这天,竟然有人把 Docker讲清楚了? | 原力计划

  • 如何使用 SQL Server FILESTREAM 存储非结构化数据?这篇文章告诉你!

  • 平安科技王健宗:所有 AI 前沿技术,都可以在联邦学习中大展身手!

  • 踢翻这碗狗粮:程序员花 7 个月敲出 eBay,只因女票喜欢糖果盒!

  • 又一年5.20,用Python助力程序员脱单大攻略(视频版)

  • 斗地主吗?能学区块链那种! | 原力计划

真香,朕在看了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/517831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

会向业务“砍需求”的技术同学,该具备哪6点能力?

阿里妹导读:“会”砍需求,并不是件容易的事情,这涉及到工程师的商业头脑,要会判断技术和业务的关系。技术与业务好比“两条腿”,相互配合才能走得更远。如何具备business sense就是我们今天的课题。 论工程师的商业头…

(进阶篇)Redis6.2.0 集群 主从复制_原理剖析_02

文章目录一、主从复制流程1. 主从复制流程图2. 主从复制日志二、主从复制信息剖析2.1. 主节点信息剖析2.2. 从节点信息剖析三、关键术语3.1. 复制功能开启3.2. 全量复制场景3.3. 主从复制异步性3.4. 过期key的处理3.5. 加速复制一、主从复制流程 1. 主从复制流程图 第一条线&a…

如何抢占云栖大会C位?史上最强强强攻略来了

如何抢占云栖大会C位?史上最强强强攻略来了 原文链接 本文为云栖社区原创内容,未经允许不得转载。

寻找榜样的力量!CSDN【百万人学 AI】评选活动重磅启动

AI 业界历经算法更迭、技术方案升级,有企业攻城略池,占据更多行业山头,有企业中途折戟沉沙。AI 发展浮浮沉沉,但每一年我们都希望审视当下,一窥未来。2020 无疑是特殊的一年,而 AI 在开年的这场”战疫“中表…

重构:改善饿了么交易系统的设计思路

我在2017年5月加入饿了么的交易部门,先后负责搜索、订单、超时、赔付、条约、交付、金额计算以及评价等系统,后期开始做些整体系统升级的工作。 这篇文章成型于交易系统重构一期之后,主要是反思其过程中做决策的思路,我没有使用「…

(进阶篇)Redis6.2.0 集群 主从复制_故障解决_03

文章目录一、 主从数据一致性1. 主多从少2. 主少从多3. 知识点补充二、 数据延迟2.1. 数据延迟因素2.2. 解决方案三、 脏数据3.1. 脏数据产生的场景3.2. 解决方案四、 数据安全性4.1. 场景4.2. 解决方案五、 规避全量复制5.1. 低峰时段5.2. 主节点变更5.3. 增大复制缓冲区六、 …

以“基”取胜:青立方超融合易捷版,助力企业“极简”上云

2020年春天,以云计算、5G、人工智能为代表的“新基建”蔚然成风,不仅助力中国产业智能化、信息化进入加速推进的快车道,促使全产业链迈开高质量发展的新步伐。更是面向长远,构筑数字经济创新发展之基。可以说,没有任何…

从零开始入门 K8s| K8s 的应用编排与管理

一、资源元信息 1. Kubernetes 资源对象 我们知道,Kubernetes 的资源对象组成:主要包括了 Spec、Status 两部分。其中 Spec 部分用来描述期望的状态,Status 部分用来描述观测到的状态。 今天我们将为大家介绍 K8s 的另外一个部分&#xff0c…

创建对象内存分析

创建对象内存分析 package com.oop.demo03;public class Pet {public String name;public int age;public void shout(){System.out.println("叫了一声");}}/* //一个项目应该这存在一个main方法 public class Application {public static void main(String[] args) …

AliOS Things 维测典型案例分析 —— 内存泄漏

维测典型案例分析1 —— 内存泄漏 在系统运行的过程中,内存泄漏是较为常见但是很难复现的现象,一般的内存泄漏点都是比较隐蔽的,每次几十个字节的泄漏,往往需要压测很久才能复现问题。本节案例分析,我们从一个已经压测…

(进阶篇)Redis6.2.0 集群 哨兵模式_搭建_01

文章目录一、概念架构简述1. Redis Sentinel简述2. Redis Sentinel优点3. Redis Sentinel缺点二、redis 3节点2.1. 101节点配置2.2. 102节点配置2.3. 103节点配置三、哨兵搭建实现3.1. 101节点配置3.2. 102节点配置3.3. 103节点配置3.4. 启动哨兵3.5. sentinel 监控3.6. 哨兵验…

服务器软件大扫盲!

来源 | 沉默王二责编 | Carol头图 | CSDN下载自视觉中国先说一句哈,自从在 B 站开始刷视频后,我就觉得要学的内容实在是太多了。这篇“服务器软件大扫盲”就是我看了羊哥的一期视频后有感而发的,比如说 Web 服务器、HTTP 服务器、应用服务器这…

Flutter浪潮下的音视频研发探索

导读:本文来自 LiveVideoStack 线上分享第三季,第十期阿里巴巴闲鱼事业部无线开发专家陈炉军带来的分享内容,针对闲鱼APP在当下流行的跨平台框架Flutter的大规模实践,介绍其在音视频领域碰到的一些困难以及解决方案。 大家好&…

(进阶篇)Redis6.2.0 集群 哨兵模式_哨兵工作原理_02

文章目录1. 主从复制哨兵架构图2. 定时任务3. 主观下线4. 客观下线5. 仲裁6. 哨兵工作原理1. 主从复制哨兵架构图 2. 定时任务 Sentinel内部有3个定时任务分别是: 每1秒每个Sentinel对其他Sentienl和Redis节点执行 PING 操作(监控)每2秒每个Sentinel通过Master节点…

10年+,阿里沉淀出怎样的搜索引擎?

阿里妹导读:搜索引擎是阿里的10年沉淀,具有很高的技术/业务/商业价值。1688很多场景都借助了搜索中台的能力,基于此,以1688主搜为例介绍搜索全链路知识点,希望对你有所借鉴,有所启发。 一、整体架构 搜索…

年薪15W的程序员因为掌握这个技能,薪资翻倍!

在这个IT系统动辄就是上亿流量的时代,java作为大数据时代应用最广泛的语言,诞生了一批又一批的技术。一些独角兽公司以及腾讯、阿里、百度、网易等知名大厂对java人才的需求量连年升级,优秀程序员能轻松达到30w的水平,但写此同时&…

语雀携手Teambition,玩转项目协作与知识管理

在数字化转型的大浪潮中,大量企业都有项目协作与知识管理诉求。Teambition 是一款优秀的项目协作产品,深受众多企业的青睐。语雀则是来自阿里巴巴的一款新品,是知识管理领域里冉冉升起的新星。今年夏天,语雀携手Teambition&#x…

支付宝小程序“开闸放粮”,亿级流量扶持中小商家!

街边小店也有机会登上支付宝首页推荐位了! 9月17日消息,在支付宝开放日活动中,支付宝宣布向小程序商家开放包括主搜热搜榜、首页腰封、首页惠支付频道、首页生活服务频道、花呗频道、会员频道等六大中心化入口,商家通过引导用户扫…

idea 编译Java heap space 内存溢出

解决方案 根据自身的实际情况设置参数大小,我调整到4096就好使了

避坑!使用 Kubernetes 最易犯的 10 个错误

Kubernetes 作为大规模企业级应用容器编排的首推工具,其为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,本文作者 Marek Bartik 深入分享了 K8s 的避坑宝典,相信会对开发者们大有裨益。作者 | Marek Bartik&…