1.问题背景
最简单的:DB事务。如创建订单时,同时往订单表、订单商品表插数据,这些Insert须在同一事务执行。
Order服务调用Pay服务,刚好网络超时,然后Order服务开始重试机制,于是Pay服务对同一支付请求,就接收到了两次,而且因为轮询负载均衡算法,落在了不同业务节点!所以一个分布式系统接口,须保证幂等性。
2.如何避免重复下单?
前端页面也可直接防止用户重复提交表单,但网络错误会导致重传,很多RPC框架、网关都有自动重试机制,所以重复请求在前端侧无法完全避免!问题最后还是如何保证服务接口的幂等性。
2.1 如何判断请求是重复的?
所以保证幂等性要做到:
2.1.1 每个请求须有唯一标识
比如订单支付请求,得包含订单id,一个订单id最多只能成功支付一次。
2.1.2 每次处理完请求后,须有记录标识该请求已被处理
在MySQL中记录一个状态字段。如支付之前记录一条这个订单的支付流水。
2.1.3 每次接收请求时,判断之前是否处理过
若有一个订单已支付,就肯定已有一条支付流水。若重复发送这个请求,则此时先插入支付流水,发现orderId已存在,唯一约束生效,报错重复Key。就不会再重复扣款。
在往DB插记录时,一般不提供主键,而由DB在插入时自动生成。这样重复的请求就会导致插入重复的数据。MySQL的主键自带唯一性约束,若在一条INSERT语句提供主键,且该主键值在表中已存在,则该条INSERT会执行失败。因此可利用DB的“主键唯一约束”,在插数据时带上主键,以此实现创建订单接口的幂等性。
给Order服务添加一个“orderId生成”的接口,无参,返回值就是一个【全局唯一】订单号。在用户进入创建订单页面时,前端页面先调用该orderId生成接口得到一个订单号,在用户提交订单时,在创建订单的请求中携带该订单号。
该订单号其实就是订单表的主键,于是,重复请求中带的都是同一订单号。订单服务在订单表中插入数据的时候,执行的这些重复INSERT语句中的主键,也都是同一个订单号。而DB唯一约束保证,只有一次INSERT执行成功。
实际要结合业务,如使用redis,用orderId作为唯一K。只有成功插入这个支付流水,才可执行扣款。

要求是支付一个订单,须插入一条支付流水,order_id建立一个唯一键。你在支付一个订单前,先插入一条支付流水,order_id就已经传过去了。就能写一个标识到Redis中,set order_id payed,当重复请求过来时,先查Redis的order_id对应的value,若为payed说明已支付,就别再重复支付!
然后再重复支付订单时,写尝试插入一条支付流水,DB会报唯一键冲突,整个事务回滚。保存一个是否处理过的标识也可以,服务的不同实例可以一起操作Redis。
若因重复订单导致插入 t_order 失败,则Order服务不要把该错误返给前端页面。否则,就可能出现用户点击创建订单按钮后,页面提示创建订单失败,而实际上订单创建成功了。
正确做法:这种case,订单服务直接返回订单创建成功。
3.解决ABA
3.1 什么是ABA
如订单支付后,seller要发货,发货完成后要填个快递单号。假设seller填个666,刚填完,发现填错了,赶紧再修改成888。对订单服务,这就是2个更新订单的请求。系统异常时666请求到了,单号更成666,接着888请求到了,单号又更新成888,但是666更新成功的响应丢了,调用方没收到成功响应,自动重试,再次发起666请求,单号又被更新成666了,这数据显然就错了!
3.2 解决方案
订单主表增加version列。每次查询订单时,版本号要随着订单数据返回给页面。页面在更新数据的请求中,把这个版本号作为更新请求的参数,带回给订单更新接口。
订单服务在更新数据的时候,需要比较订单的版本号是否和消息中的一致:
orders tracking_number version version version
在这条SQL的WHERE条件中,version值需要页面在更新的时候通过请求传进来。
通过该版本号,就能保证,从我打开这条订单记录开始,一直到我更新这条订单记录成功,期间没有其他人修改过该订单数据。若有,则DB中的version就会改变,那我的更新操作就会执行失败。我就只能重新查询新版本的订单数据,再尝试更新。
有了这个版本号,前文的ABA即有两个case:
无论哪种情况,DB中的数据与页面上给用户的反馈都是一致的。这就实现了幂等更新且避免ABA。
4.总结
两种幂等的实现方法,就可以保证,无论请求是不是重复,订单表中的数据都是正确的。
实现订单幂等的方法,完全可以套用在其他需要实现幂等的服务中,只需要这个服务操作的数据保存在数据库中,并且有一张带有主键的数据表即可。
2*6平方的黑皮铜线光缆多少钱一米?
国标线约10元自然、左右
最大的化壮公司接到客户抱怨买来的肥皂盒里面是空的,为了预防生产线再次发生这样的事情你会怎么样处理?
不好理解。 就按化妆品公司来理解。 既然出现这种情况影响不小。 我认为大厂生产线一班不直接对外出售,所以需要综合调查;既包装,出库,运输,流通,销售,看在哪个环节出的问题,查处后按制度及时处理。 杜绝同样的情况在度发生。
电磁炉买什么牌子比较好用?购买的时候注意什么?
美的SN216D电磁炉质量好坏,取决于高频大功率晶体管和陶瓷微晶玻璃面板的质量优劣。 选购时,务必购买高速、高电压、大电流的单只大功率晶体管的电磁炉,因其质量好、性能优、可靠性高、不易损坏。 首先看面板是否平整,有无凹凸或倾斜,选择平滑无损的;再看面板的颜色,黑色的德国塞兰微晶玻璃板和表面光滑纯白色的日本nec陶瓷面板都是好面板,一般名厂和大厂采用;国产的a级和b级板虽也呈白色,但b级板的边沿粗糙,没有a级的光滑;c级板容易发黄变色,厂家往往印有图案。 尽量选购进口面板或国产a级面板的产品。 然后察看底部的散热风扇,选择风扇对角线尺寸大的产品。 最好是采用磁悬浮、液压或纳米陶瓷风扇,如能拆开的话,用手按压风扇扇叶,能够按下去2mm左右的是磁悬浮,反之则不是。 询问导购看能否确认散热风扇的类型和品牌,如用avc等国际大厂的,说明厂家很舍得投入成本。 散热效率的高低会影响内部元器件的使用寿命,而好的散热风扇会减少正常运作时的噪音。 再看电源插头,应选购三脚电源插头的产品。 然后进入产品测试。 产品测试分五步:一、听听声音接通电源开机,除了正常的散热风扇的声音,应听不到其它杂音及电流声。 二、测试按键逐个测试所有按键功能是否能正常操作,淘汰按键失灵的产品。 三、测试安全性无锅保护在工作状态下移开锅具,观察电磁炉是否能自动报警,通常在2分钟左右会自动切断电源。 空锅保护空锅加热时间稍长,电磁炉应当会自动发出报警并停止加热。 有些电磁炉没有此项功能。 不当加热保护试试在炉面放置铁汤勺等小件物品然后开机,通常锅具面积少于65%时不能正常加热。 有的电磁炉没有此项功能。 四、测试锅具适应性通电加热过程中,重复多次取锅、放锅的动作,看看恢复加热的时间是否正常,通常取锅后放回1-3秒就会恢复加热,如果恢复时间大于5秒,说明这款机器对锅具的适应性不好。 五、测试温控检查电磁炉是否有100℃温区设计,用配套的锅具烧水,看水开后设定在100℃挡位是否还能维持沸腾状态。 温度设计不准会导致烧机隐患,因为内部的很多保护功能是基于温度监测的。 在烧水过程中,可把锅向边缘移1/4或1/3,保持1-2分钟左右,应能继续加热,说明电磁炉加热功能正常。 在选择时,尽量选温度调节挡多的,在100℃至270℃间如能按10或20逐级递升的,使用会更方便。 目前,投放市场的电磁炉功率均在1000-2400W之间,并分成若干档。 功率越大加热速度则越快,但耗电也越多,售价随之越贵,因此选购时应根据用餐人数以及使用情况而定。 一般来说,3人以下家庭选1300W为宜;4-5人选1600W-1900W左右为宜;6-7人选1800W-2100W为宜;8人以上选2100W以上电磁炉。 要选择技术力量雄厚、信誉度高的品牌,产品要通过CCEE中国电工产品安全认证及ISO9001国际质量认证。 399元
发表评论