小说:白话幂等性设计

栏目: 数据库 · 发布时间: 5年前

内容简介:你的关注意义重大!-更多文章-

点击上方 方志朋 ”, 选择“置顶或者星标”

你的关注意义重大!

(以下故事纯属虚构,如有雷同纯属巧合!)

一月的深圳,一如既往的炎热!

某天,烟哥正一边喝着 芝芝芒芒 ,一边愉快的装13!

突然,小刘满脸愁容的找到了我,对我说:"烟哥,自从我们的单体应用拆成微服务架构后,不知为啥,老是出现数据不一致的问题!已经都快被客户骂死了,人家客户明明只点了一次,我们这边却有了两条数据!"

其实烟哥在装13的时候,被人打扰,这是大忌!大忌!然而,看在小刘是个妹纸的份上,我就不计较了!没错,我就是这么没原则的人!其实我本来可以直接告诉人家怎么解决的,然而无耻的烟哥,为了多和妹纸说会话,决定多啰嗦一会!

只见烟哥嘴角嘿嘿一笑,问到:"你知道 为什么拆成微服务架构后,会出现数据不一致问题么? "

接下来的情形,无法用言语形容,各位看官请看下面这张图

小说:白话幂等性设计

烟哥解释到:"因为在传统应用中,调用接口,只有两种状态 成功失败 。但是呢,在微服务的架构下,还有第三种情况,那就是 超时 !小刘啊,你们的服务,调用另一个服务,如果超时了,你们是怎么处理的呢?"

小刘说:"重试啊!调用超时了,重试一下呗!"

这时,烟哥的表情突然变成了这样

小说:白话幂等性设计

烟哥回答到:"对的!小刘真聪明!然而, 重试只是一种方法! 还有一种就是,调用方在超时后,去查询一次被调用方。如果能查到数据,就代表调用过了,不继续执行,如果查不到数据,走失败流程!因为你们在调用超时的情况下,进行重试调用,就给系统带来了不一致问题了!因此我们必须给调用接口提供 幂等性 保证,防止重复调用出现不一致的情形!"

这个时候,小刘表情变成了这样

小说:白话幂等性设计

"哦,小刘,你懂?来来来,说说 什么是接口幂等性? "

说时迟,那时快,只见小刘挥舞着她的小手,说道:“接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。”

这种时候,烟哥痛心疾首,

小说:白话幂等性设计

只见烟哥眉毛微微一皱,开始装13的解释道:“如果按这么解释,比如一个查询接口。假设 SQL 是下面的这样的

select * from table;

这个时候,有一个线程,一直往这个 table 插入数据,那你每次调用查询接口的返回值肯定不一样啊!你能说查询操作不是幂等性操作?

应该要这么理解, 幂等性强调的是外界通过接口对系统内部的影响, 外界怎么看系统和幂等性没有关系,只要一次或多次调用对某一个资源应该具有同样的副作用就行。注意了,是对资源造成的副作用必须是一样的,但是返回值允许不同!

说到这里,小刘一脸懵逼的看着我。。。

烟哥说道:“就用,增、删、改、查来举例一下吧!”

(1)查询操作

查询操作并不会产生或变更新的数据,因此查询是天然具备幂等性。

(2)删除操作

这里分为 物理删除逻辑删除

  • 物理删除:删除只会进行一次,无论执行几次 delete 操作,造成的效果是一样的!是幂等性操作

  • 逻辑删除:这类删除,是用 update 修改字段而已,这种操作无论 update 几次,造成的效果是一样的!是幂等性操作

(3)增加操作

这里要看这张表是否带唯一索引。

  • 带唯一索引Insert:此时如果重复插入操作,是会插入失败的!该操作是幂等性操作

  • 不带唯一索引Insert: 这种情况是非幂等性操作。

(4)修改操作

要看修改了啥

  • 计算式Update:这类操作是指 UPDATE table SET number=number-1 WHERE id=1 ,这类SQL的操作,是非幂等性操作!

  • 非计算式Update:这类操作是指 UPDATE table SET number=3 WHERE id=1 ,这类SQL操作,这种修改是属于幂等性的操作!

小刘:"烟哥,你可以先说说网上说的什么 on DUPLICATE KEY UPDATE 是什么东西么,就像下面这个SQL这样!"

insert into table (goods_id,update_time)
values(#{goodsId},now())
on DUPLICATE KEY UPDATE
update_time=now()

烟哥:"好,你还记得我刚说的,在表有唯一索引的情况下,此时如果有重复插入操作,是会插入失败的么!"

小刘:"嗯嗯。记得!"

烟哥:"OK,这种插入失败,从严格意义上来说是分为两种情况的!"

第一种就是 报唯一键冲突异常 !例如常规的 INSERT INTO tablename(列名) VALUES(列值) 这样的语句!

第二种就是 不报异常 ,Mysql提供了三组这样防止重复插入的语句,必须要有唯一索引才能用的

  • insert ignore into :若有导致 unique key 冲突的记录,则该条记录不会被插入到数据库中.

  • replace :若插入时如发现 unique key 已存在,则替换原记录,即先删除原记录,后 insert 新记录。

  • on duplicate key update :若插入时如果发现 unique key 已存在,则执行 update 更新操作

小刘:"可是这些语句毕竟是 Mysql 的方言,换了数据库就不能用了啊!通用性太差,而且还规定一定要有唯一索引才能用!麻烦!"

此时烟哥的反应是这样的

小说:白话幂等性设计

烟哥捋了捋自己的思绪,说道:"回到我们刚才的话题,现在只有 不带唯一索引Insert计算式Update 会引起幂等性问题的,懂了嘛?"

小刘抹了抹自己的眼泪,像下面这样

小说:白话幂等性设计

烟哥淡然的解释道:"现在网上大多数文章推荐全局token的方案,就是这样的。生成一个全局性唯一的token,然后请求过来的时候,查一下token存在么,存在代表做过了,就丢弃。不存在,就执行正常业务流程,把token丢到某个存储介质里!"

小刘听了听,摇了摇头:"烟哥啊,这个方案乍听之下很完美!但是细想一下还是有一点不大好。你看啊,假设有1000个请求,重复请求一般不到10个。为了这不到10个请求的正确性,让剩下990个正常的请求都多一个查询流程,这似乎不大妥吧!"

烟哥突然惊呆了,此刻感觉如下

小说:白话幂等性设计

烟哥补充道:“嗯,是的,所以我个人还是主张在数据库的操作上解决这个问题!就插入操作来说,建议还是建一个唯一索引,来防止重复插入!”

小刘:"可是我们的数据量很小,就是不想建索引怎么办?"

烟哥说道:“那你的插入语句可以像下面这么修改

INSERT INTO table(field1, field2, fieldn) SELECT 'field1', 
'field2', 'fieldn' FROM DUAL WHERE NOT EXISTS(SELECT field
FROM table WHERE field = ?)

用这种写法,就可以防止重复插入,而且不需要建立唯一索引!SQL可以判断field字段有值,则不insert。如果无值,则会执行insert操作!这种方法其实就是使用了mysql的一个临时表的方式,但是里面使用到了子查询,效率也会有一点点影响。但是很重要的一点,这种写法在oracle里也能跑的通,通用性之强,无与伦比。如果真的达到了影响性能那个级别了,估计数据量够大,可以用上索引了。这会数据量太小,先这么写吧!”

小刘:"那针对修改场景怎么办?"

烟哥说道:“也很简单,加一个版本字段就行!比如,原来的sql为

UPDATE table SET number=number-1 WHERE id=1

,你加一个版本号字段就好啦,变成

UPDATE table SET number=number-1,_version=_version+1  
WHERE id=1 AND _version= last_version

唯一的缺点,就是执行前,需要去数据查一下当前版本是啥!当然啦,如果你的表有唯一索引,用的又是 mysql ,又能保证将来不换其他数据库。可以试试 mysqlon duplicate key update 语句,该操作插入时如果发现 unique key 已存在,则执行 update 更新操作”

烟哥补充道:"在数据库层面的改变是最方便的,所以我一直主张,改sql,改表结构来解决幂等性问题。不要引入一堆七七八八的东东,徒增系统复杂度。好啦,小刘快回去改sql吧!"

于是,小刘就愉快的回去的改sql了!!

各位看官一定发现了,本来改个SQL就能解决的问题,烟哥硬是扯了半个多小时!当然,最后的结局就是下面这样

小说:白话幂等性设计

-更多文章-

最详细的 排序 解析,理解七大排序

好文推荐,15 分钟教你搞懂 Git!

Spring Cloud Greenwich版本已发布!

分布式事务的实现原理

-关注我-

小说:白话幂等性设计

看完了,帮我点个“好看”鸭

点鸭点鸭

↓↓↓↓


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Kafka技术内幕

Kafka技术内幕

郑奇煌 / 人民邮电出版社 / 2017-11 / 119.00元

Kafka自LinkedIn开源以来就以高性能、高吞吐量、分布式的特性著称,本书以0.10版本的源码为基础,深入分析了Kafka的设计与实现,包括生产者和消费者的消息处理流程,新旧消费者不同的设计方式,存储层的实现,协调者和控制器如何确保Kafka集群的分布式和容错特性,两种同步集群工具MirrorMaker和uReplicator,流处理的两种API以及Kafka的一些高级特性等。一起来看看 《Kafka技术内幕》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具