前言
此篇文章将会介绍一个在实际应用中的解决方案
这些方案是这些项目或者系统在当时的情况下做出的最优解,我会详细介绍我们是面临怎样的问题并且怎样解决这些问题,或许它不是最优或者是最合理的方式,但是这篇文章或许能为您带来一些灵感。
此外,我发布的文章一定是在项目中使用过的解决方案,是经过时间验证的,我们可以通过分析这些案例,来为我们下一次的方案提供正面或者反面教材。
如果您有更好的已经实际使用过的方案愿意提供给我们,我们很高兴为您的方案给与酬劳。
一、场景(未重新设计之前)
1. 系统功能说明
这个系统只是众多业务系统中的一个,并且处于所有数据流的末端,严格上来说他是一个报表系统,在我接手时,它已经开发完成。
2 系统架构说明
spring cloud + nacos + redis +mysql
我们大致上使用了以上工具构成了项目框架主题
3.业务说明
我们需要新建一次考试,分配考场和考号,之后需要导入学生的成绩数据,通过算法计算后生成学生的行为分析模型,通过这些行为模型,系统会提供给学生或者老师能够使用的统计报表
4.业务流程
5.面临的问题详情
1.数据业务流程完全写死在代码中,并没有流程可视化或者可操作的流程控制,导致后面接手的人员几乎无法理解业务。
2.报表数据需要经过10张表的洗礼才能够使用,其中牵扯的状态不下十个,导致表之间的关系难以理解,并且排查数据生成的过程中出现的问题难度很大。
3.在报表统计中常常需要关联很多张表查询才能得到全部范围的数据或者部分数据,这让查询变得缓慢。
4.牵扯众多的前置业务系统,通常该系统需要等待前置系统的业务数据生成,之后才能去获取数据进行出来,系统之间的频繁交换数据,导致了数据常常出现缺失或者其他异常情况,这让这个系统十分的不稳定
5.业务接口的查询源头混乱,难以统一维护。
5.详情
数据库设计:
这是重新设计之前的数据库结构
二、解决方案分析
业务层面:
报表系统应该专注于他的报表业务,在生成报表数据的流程中,我们有很多步骤都嵌套了其他系统的数据,但是反观一想,这些数据都是作为必须的前置条件,他们之间的联系相当紧密,但他们实质上能够分离出来作为生成报表数据的第一步。
数据库层面:
既然我们在业务上让所有前置条件业务在概念上都归为一步,那为什么不能将下一步,也就是报表数据单独成立一张表,这张表中只存储已生成的未出现错误的报告呢?
三、方案实施归纳
1.我们决定把创建考试到算法计算这个流程化零为整,他们都是同一个工作,数据生成或者清洗
2.新建一张真正的报表表储存静态数据。
四、方案实施详情
1.数据库设计
我们只留下了四张表2.业务流程
我们发现之前的业务并不需要储存那么多的数据,只需要在核心算法计算前把数据给到算法便会得到结果
3.核心说明
1.rep_detail表是一张非关系型的结构,他储存的数据是每一次考试每一科目每个人的每道题的答题情况,在统计报表时,只需要切换字段和数据范围,就能得到业务接口想要的报表数据,他根本不需要与其他表进行连表查询,所有的查询入口都应该是eval_exam,在此处,我们甚至不需要去关心eval_exam_subject,因为我们的rep_detail中拥有eval_exam_subject中的一切。
rep_detail表字段
2.既然现在我们无需担心业务接口获取数据的方式,那我们剩下的就是维护好核心算法计算前的数据准备工作,准备好所需的数据并对他们进行清洗是一个复杂并且带有挑战的业务。
3.在数据准备过程中几乎没有流程来控制业务,只有上一步的成功与否,更加利于排查错误。
五、重新设计后遇到的问题
1.主要问题
1.red_detail中常常一次考试便会生成几十万条数据,数据库由此变得缓慢。
2.red_detail字段的多样性,让业务sql变得复杂和难以理解。
2.如何解决问题
1.更换mysql数据库引擎为MyISAM,此时我们的静态表rep_detail不再需要事务来保证它的安全,因为它的数据经过预清洗保证了数据的有效性,从而让新增数据变得更快。
2.增加mysql索引,让复杂的查询sql变得更快。此表中只有一个索引
3.我们在代码中的web层增加了redis,让接口除第一次查询之外均能保证响应速度(由于索引原因,第一次查询最糟糕的接口最长等待时间为10s)。
4.我们的新设计和结构让数据脱离了业务,也让业务能够离开数据,当接口变得难以维护时或者其他系统进行了大幅度的改动,这个接口的重写工作为因为我们的设计变得轻松,新接手的人员只需要理解rep_detail的字段意思和接口业务,就能够直接重写接口,而不需要担心其中会有某些没注意到的业务细节或者与其他系统的关系。