目录
背景
为了保证数据质量,防止重复数据对业务数据进行污染。所以我们一般在写数据时,需要做防重校验。例如新增接口时,为了保证接口的幂等。
示例:
目前需要保证同一个姓名+手机号+性别,不重复。路由key 是姓名。
发展历程:
单表唯一索引
这不是很简单么,对这几个字段加上唯一索引不就OK了么。
几天后,测试同学突然来反馈说发现了重复数据。不可能呀,唯一索引都加上了咋还会重呢。不可能。
经过半小时的查看,突然发现重复数据为以下情况。
居然还有这种情况。。。
新增业务锁表
既然合并在一起会失效,那么单独出来存储,总不会错了吧。所以单独新增锁表(路由key=uuid)。如下:
几天之后,测试同学又来反馈问题了,这个数据还是有重复呀。(这个测试可真厉害)
通过排查发现出现了以下数据
这是咋回事呀。明明第一次张三同学就写入了两个手机号呀,怎么锁表里面只有一条数据呢。马上查看了日志。发现由于业务表(姓名)、锁表(UUID)。这两个表同时保存数据的时候,无法保证事务。所以凉凉。
难度要上分布式事务么,不科学呀,分布式事务那么重,要是给加上,不是又得再进行几轮性能优化吗。应该咋整呢?
重整旗鼓
梳理下思路,目前我们主要做防重,防重的方案有
1、数据库唯一索引(行不通)
2、每次写之前先查一次数据是否存在(并发情况下,没法控制数据写入)
第一条路,目前是卡住了,能不能走走第二条路呢?第二种情况主要是并发的情况下会有问题,能不能把并发这个问题给解决了呢。
解决并发的两条路:
1、将数据库的隔离级别调整为序列化(所有请求单线程处理,性能影响极大)
2、加入分布式锁,对某些固定资源进行加锁处理。防止并发造成问题。
第二条路看似是可行的,可是加锁容易,那什么时候释放锁呢。普通情况都是业务逻辑操作完就释放锁了。但是目前业务数据和锁数据可没法保证事务呀。
插图
必须得等到锁数据完全写成功之后,才能释放锁,那么怎么知道锁数据完全写入成功了呢?
既然同步没法搞定,能不能想想别的招呢?这时,最终一致性突然跳出来了。
最终一致性:这个概念是在学习分布式事务时学到的。既然不能用2PC,3PC这种重的流程。那么咱们可以采用异步重试机制呀。