幂等是什么及Ansible幂等实现源码解析

2021-02-23 16:39:45 浏览数 (1)

运维就要无所不能,无所不会

  • 一、幂等概念
  • 二、幂等使用场景
  • 三、幂等实现方案
    • 3.1 db去重表
    • 3.2 MVCC(多版本并发控制)
    • 3.3 状态机约束
  • 四、Ansible 幂等实现源码剖析

幂等是什么及Ansible幂等实现源码解析

大家好,我是史丹利「Stanley」,昨天被老板「粉丝」批评说近段时间文章太软。。。今天我们硬一把,来聊聊幂等。先上图

Ansible-Copy-1st

Ansible-Copy-2st

Notice: 第一次执行结果和第二次一致,所以第二次执行命令时并没有实质变更,即不对目标对象做变更。

一、幂等概念

幂等(idempotence)一词原为数学上的概念,用一个最直观的数学式子表达为:

f(f(x)) = f(x)

对应到软件开发领域,即为同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的,实际上就是接口的可重复调用(包括时间和空间上两个维度)。

不是要求返回值完全相同,而且是指后续多余的调用对系统的数据一致性不造成破坏

  • 写操作

如果第一次写入是成功的,后续的写入应该抛出异常或者空操作,或者执行了写入但是未对数据造成变化。

作业:数据库如何保证写操作幂等?

  • 读操作

读取类操作,需要保证其实现上是真正的读取,不能在读操作中夹带写操作。如HTTP get method

好的如:秒杀按钮只能点击一次,之后会变成灰色无法点击。如微信红包

差的如:某东秒杀按钮可重复点击,每次返回“茅台已被抢完”...

二、幂等使用场景

  • 应用场景类
    • 某东抢茅台
    • 某信抢红包
  • 技术场景类
    • ansible执行命令,如符合幂等刚不会重复执行
    • curl -X GET HTTPURL

三、幂等实现方案

方式不一,具体和业务场景有关联性。

3.1 db去重表

订单支付信息录入至去重表,每次支付请求先录入订单信息再执行支付行为。

如插入成功,且支付,如插入失败。则抛异常

图1-1:支付场景时序图

3.2 MVCC(多版本并发控制)

数据库并发请求场景下,根据唯一字段判断最新状态,唯一字段可以是版本号、JS生成的唯一码、表唯一索引等。如果唯一字段不存在,则无法获取数据或执行增、删、改等变更操作

代码语言:javascript复制
update table_name set deposit = deposit-#{payment}, version = version   1 where orderId = #{orderId} and version = #{version}

3.3 状态机约束

通过程序代码逻辑等技术手段实现,在代码段是增设状态判断,如果状态机已处于下一个状态,这时候不能往回跳转到上一个状态,通过状态机的跳转约束,可以做到有线状态机的跳转约束,比如基于状态机实现的乐观锁:

代码语言:javascript复制
update table set status=next_status where id=#{id} and status=#{status}

当前状态第一次被修改后,状态被修改为下一种状态,同一记录针对当前状态的其他修改会失败,程序跑出异常,这常见于并发场景的修改。

如下 Ansible 即通过该方式实现。

四、Ansible 幂等实现源码剖析

以文首 copy 模块为例。

代码语言:javascript复制
# 文件所在位置
ansible/modules/files/copy.py

ansible-copy模块逻辑

  • 幂等核心源码如下「请留意注释」
代码语言:javascript复制
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 的幂等通过各模块或插件, AdHocPlaybook 只实现了命令分发执行和结果收集展示

参考: 幂等实现[1]


~ over ~ 你学废了吗?

参考资料

[1]

幂等实现: https://segmentfault.com/a/1190000015884659

0 人点赞