运维就要无所不能,无所不会
大家好,我是史丹利「Stanley」,昨天被老板「粉丝」批评说近段时间文章太软。。。今天我们硬一把,来聊聊幂等。先上图
Ansible-Copy-1st
Ansible-Copy-2st
Notice: 第一次执行结果和第二次一致,所以第二次执行命令时并没有实质变更,即不对目标对象做变更。
幂等(idempotence)一词原为数学上的概念,用一个最直观的数学式子表达为:
f(f(x)) = f(x)
对应到软件开发领域,即为同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的,实际上就是接口的可重复调用
(包括时间和空间上两个维度)。
不是要求返回值完全相同,而且是指后续多余的调用对系统的数据一致性不造成破坏。
如果第一次写入是成功的,后续的写入应该抛出异常或者空操作,或者执行了写入但是未对数据造成变化。
作业:数据库如何保证写操作幂等?
读取类操作,需要保证其实现上是真正的读取,不能在读操作中夹带写操作。如HTTP get method
好的如:秒杀按钮只能点击一次,之后会变成灰色无法点击。如微信红包
差的如:某东秒杀按钮可重复点击,每次返回“茅台已被抢完”...
方式不一,具体和业务场景有关联性。
订单支付信息录入至去重表,每次支付请求先录入订单信息再执行支付行为。
如插入成功,且支付,如插入失败。则抛异常
图1-1:支付场景时序图
数据库并发请求场景下,根据唯一字段判断最新状态,唯一字段可以是版本号、JS生成的唯一码、表唯一索引等。如果唯一字段不存在,则无法获取数据或执行增、删、改等变更操作
update table_name set deposit = deposit-#{payment}, version = version + 1 where orderId = #{orderId} and version = #{version}
通过程序代码逻辑等技术手段实现,在代码段是增设状态判断,如果状态机已处于下一个状态,这时候不能往回跳转到上一个状态,通过状态机的跳转约束,可以做到有线状态机的跳转约束,比如基于状态机实现的乐观锁:
update table set status=next_status where id=#{id} and status=#{status}
当前状态第一次被修改后,状态被修改为下一种状态,同一记录针对当前状态的其他修改会失败,程序跑出异常,这常见于并发场景的修改。
如下 Ansible
即通过该方式实现。
以文首 copy
模块为例。
# 文件所在位置
ansible/modules/files/copy.py
ansible-copy模块逻辑
def main():
...
# 调用sha1先做md5校验
checksum_src = module.sha1(src)
checksum_dest = None
# Backwards compat only. This will be None in FIPS mode
try:
md5sum_src = module.md5(src)
except ValueError:
md5sum_src = None
# 设置状态机 changed
changed = False
...
if checksum_src != checksum_dest or os.path.islink(b_dest):
# 开始文件copy
....
# 成功copy
changed = True
else:
# 如果文件已经存在,且md5一样,则不执行操作。
changed = False
Notice: Ansible 的幂等通过各模块或插件,
AdHoc
和Playbook
只实现了命令分发执行和结果收集展示参考: 幂等实现[1]
~ over ~ 你学废了吗?
[1]
幂等实现: https://segmentfault.com/a/1190000015884659