在学生管理系统里,其中会有学生信息采集的功能。程序结构不外乎下面的分层实现方式。
开发出来这个功能,我觉得大家都易如反掌了。
当然易如反掌。
OK,我要说的是数据校验,以最简单的非空校验(例如:学生姓名不可为空)来说:
首先,前端页面的表单要校验,为空则不允许提交,非空则调用后端api接口来post数据。
其次,后端程序的controller里要校验,为空则直接返回错误提示,非空则调用StudentService类。
再次,StudentService类要校验,为空则直接返回错误提示,非空则在其他校验通过后,进行数据的持久化。
上面的“再次”,在单体应用内不做校验也可————而一旦是在RPC调用的情况下,是必须要做的。
那么,聪明的你,有没有,或者曾经有没有,忽视上面的几处校验呢?
你也许会说 No, of course not. ————肯定会做校验呀。
你也许还会说 But why?————为什么要这么多处校验呢?一个地儿校验住不就完了吗?
First,为什么前端要校验?
–> 前端页面校验不通过时,则直接在页面提示给用户了,好处:①响应快,因为无须调用后端api,也减少了网络通信;②用户体验会好一些。
Second,前端已经校验了,为什么后端还要校验?
–> 正常情况下是不需要后端再校验了。非正常情况下呢?例如,前端没拦住,再例如,请求不是前端发过来的…
Third,为什么service类还要校验?
–> 上面说了,如果是单体应用,你不校验也行。而如果是局域网RPC服务之间调用的话,你还真要加上这个校验。也是为了防止非正常情况的。
在实际企业应用开发中,因为非正常情况的概率性事件存在,所以,我们需要“重复地”来做这些校验。类似的需要多处“重复”做的校验包括:数据合法性校验、数据重复校验、幂等校验(幂等控制)、数据唯一性校验(数据防重控制)。
你也许会继续追问:哪有那么多非正常情况呀????
你可以不“重复”做这些校验,而simply依靠请求链路里的only一个节点的校验来cover。那么,你这种“半裸奔”的系统没出现问题,只能说明你比较幸运。一直没出现问题,说明你一直比较幸运。
最近我们系统碰巧又出现了这样的事故。一个中台dubbo服务提供了数据的新增接口,供下游业务线调用。系统运行了大半年也没出现问题,而最近却翻车了。一个业务线在特定的分支逻辑里缺乏有效的防重控制,致使在业务高峰期不停地重复刷这个接口(传递同样的数据),而这个dubbo接口里没有做业务防重。瞬时的高频调用,不仅让dubbo服务出现故障,还造成了大量的重复数据。随之而来的是运营的催促,客户的投诉,我们在处理重复数据时,耗费了大量的人力和时间成本。这一张多米诺骨牌,让我们付出了惨痛的代价。
我是因为遇到了这么一个事故才写这个blog吗?
不是!许多大的事故往往就是类似小疏忽导致的。我遇到的这样的事故简直太多了。
你没有遇到这样的事故吗?
我不信!So,一番碎碎念,愿小伙伴们别再为这样的疏忽而翻车。