前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无处不在的幂等性

无处不在的幂等性

作者头像
明月AI
发布2021-10-28 14:17:24
5540
发布2021-10-28 14:17:24
举报
文章被收录于专栏:野生AI架构师

0. 引子


最近接手一个项目,基于Airflow实现ETL的功能。问题是这个ETL经常出问题,然后就是修数据,虽然有Airflow的优势,但是还是相当的烦人。我们项目都是基于Docker进行部署的,原来的启动方式是这样的:

代码语言:javascript
复制
# 启动一个后台容器
sudo docker run -dti --restart always --name airflow -p 10101:8080 \
    -v /root/services/airflow:/airflow \
    -v /data/logs/airflow:/airflow/logs \
    -e C_FORCE_ROOT=True \
    registry.cn-hangzhou.aliyuncs.com/ibbd/airflow \
    bash /service.sh
    
# 然后通过docker exec来分别启动Airflow的调度器和worker
# 大概脚本如下:
sudo docker exec -tid airflow bash start-scheduler.sh
sudo docker exec -tid airflow bash start-worker.sh

问题是scheduler进程或者worker进程经常自己就挂掉了,很可能是因为客户的服务器配置资源不足导致的。开始处理这个问题就是写监控脚本,监控进程,但是问题依然是没有完全避免,有时监控脚本也因为莫名的原因没有启动成功。

前些天把启动方式修改成了如下的方式:

代码语言:javascript
复制
# 启动调度器
sudo docker run -dti --restart always --name airflow-scheduler \
    -v /root/services/airflow:/airflow \
    -v /data/logs/airflow:/airflow/logs \
    -e C_FORCE_ROOT=True \
    registry.cn-hangzhou.aliyuncs.com/ibbd/airflow \
    airflow scheduler
    
# 启动worker
sudo docker run -dti --restart always --name airflow-worker \
    -v /root/services/airflow:/airflow \
    -v /data/logs/airflow:/airflow/logs \
    -e C_FORCE_ROOT=True \
    registry.cn-hangzhou.aliyuncs.com/ibbd/airflow \
    airflow worker

# 启动webserver(需要的时候才启动即可)
# sudo docker run -dti --restart always --name airflow-webserver -p 10101:8080 \
sudo docker run -ti --rm --name airflow-webserver -p 10101:8080 \
    -v /root/services/airflow:/airflow \
    -v /data/logs/airflow:/airflow/logs \
    -e C_FORCE_ROOT=True \
    registry.cn-hangzhou.aliyuncs.com/ibbd/airflow \
    airflow webserver -p 8080

非常干净利落地解决了问题,利用docker的restart always就能自动实现我们所需要的功能。而且还有个非常好的好处:

随时可以干掉某个容器进行重启!

这是个非常好的特性,不正是类似我们经常所追求的幂等性吗?

1. 关于幂等性


维基百科上,关于幂等性的介绍有:

在数学里,幂等有两种主要的定义。

  1. 在某二元运算下,幂等元素是指被自己重复运算(或对于函数是为复合)的结果等于它自己的元素。例如,乘法下唯一两个幂等实数为0和1。
  2. 某一元运算为幂等的时,其作用在任一元素两次后会和其作用一次的结果相同。例如,高斯符号便是幂等的。

https://zh.wikipedia.org/wiki/%E5%86%AA%E7%AD%89

在IT工程领域,因为组件或者模块不可避免的不可靠性(编程领域有一个至理名言就是:所有可能会发生的,最终一定会发生),所以幂等性就变得非常重要,在设计工程中往往是需要重点考虑的。例如上面引子提到的容器启动也是一个例子,无论执行多少次启动脚本,结果都是一样的,而不会产生额外的副作用。

2. 幂等性的应用


幂等性在IT工程设计领域几乎无处不在,如果在设计和实现上保持了幂等性,那么你的系统的健壮性往往是很好的,维护也简单。除了上面提到的容器启动设计,常见的还有:

2.1 接口设计

接口设计是我们经常碰到的工作,但是我们对于接口的假设往往是,因为各种各样的原因,我们的接口出现异常的情况是不可避免的,因此我们设计的重点并不是完全杜绝接口出问题,而是接口出问题之后,我们能否再执行一次该接口,直到成功。

这就要求我们的接口应该尽可能是保持幂等性的。例如注册用户,如果每次提交都往数据库插入记录,那就乱套了,而是插入前应该判断数据是否已经存在了。

当然这是非常简单的情况,如果这个都不懂,那他可能还没入门。复杂一点的情况,例如上传文件功能接口怎么保持幂等性,几乎可能肯定很多刚入门的工程师都没考虑过这个问题,甚至有些入门多年的工程师也不考虑这个问题。

当然可能并非所有接口都能实现幂等性的,但是很显然,我们遇到的大部分都是可以幂等性的。

这在http接口设计上大家可能还是比较有感觉,但是在平时实现功能接口时可能就不太注意了,很多初入门者,为了方便,往往定义了很多全局变量,实现的函数是有副作用的,相同的输入,可能得不到相同的输出,这通常会使得维护变得糟糕。这也是这些年函数式编程咸鱼翻生的根本原因,相对于面向对象的编程,函数式编程更加容易保持幂等性,因为面向对象编程时大家很容易去修改类的属性,这样很容易导致再一次执行时就没法保持幂等性了。

2.2 Airflow的任务Task设计

Task的耗时往往是比较长的,通常比接口更不可靠,因此Task的幂等性就更加重要,也就是说,Task应该随时经受重启的考验,这样能大大降低维护的难度,出问题往往只要重启即可。

2.3 模块设计架构设计

一个系统可能很庞大,如果没有合理的模块划分,那很可能会是一个灾难。但是哪些功能应该划分到相同的模块,这就非常考验能力了,通常这也是工程师水平能力的最重要体现。不同模块之间的交互应该是具有幂等性的(并不是所有情况都能满足),不同模块之间如果乱成一团,那肯定是一个灾难的开始。

2.4 页面设计

这里只说一个经常看到的情况,就是页面跳转的设计。我发现大多数前端工程师都不会关注这个问题,可能大家觉得这只是一个小问题,不过我觉得页面URL如果不具备幂等性,那体验会变得有点糟糕。

例如我在一个网站内浏览时,可能点击了很多链接,但是当我点击到某个页面时,页面却迟迟加载不出来,这种情况是经常会发生的,这时我的操作很可能是直接刷新页面,点击浏览器的刷新按钮(这个是很合理的操作)。对于不具备幂等性的设计,这个时候,刷新可能就跑回到某个页面了,而不是我当前正在浏览的页面。当然,需要幂等性的并不是只有这个场景,例如我要将某个页面分享给其他人,或者向其他人求助等。

这个问题在现在越来越流行单页面应用之后,越来越突出了。

这个问题同样容易出现在桌面软件或者手机APP上,一个APP因为各种原因挂掉之后,比较好的体验应该是我重启之后还能回到挂掉之前的状态,但是显然大部分都不具备这样的特性,而只是简单的回到了首页。

2.5 状态设计

这又是一个更加容易被忽略的情况,但是状态设计往往是系统架构设计中关键的一环,通常弄清楚了状态的转化过程,那么你的业务系统可能就相当清晰了。例如常见的登陆状态,我见过有人将登陆的状态信息保存在服务器的文件系统中,这是非常糟糕的设计,因为依赖了一个本地的文件系统,情况要是有变化可能就很难保持幂等性。例如换服务器,或者增加了服务器。

好的实现方式应该是保持在公共的redis等缓存里,更好的方式我觉得是加密之后写到token里,请求时带上token。

在分布式应用中,幂等性会变得更加重要。有一个典型的例子,在设计数据表的主键时,可能不少人都会使用自增的ID作为主键,因为简单。但是自增ID本身是不具备幂等性的,每次插入都会有一个新的ID。而在分布式的高并发场景下,自增ID的麻烦就更大了,因为并发的代价比较大。现在也会有不少开源的全局ID生成算法,都是为了解决这一问题而生的。

3. 不能过度设计


幂等性很好,但是还是不能过度设计,有些接口或者模块可能就很难保证幂等性,过度设计只会增加系统复杂度,这是违背幂等性的初衷的。例如如果系统的并发很小,那自增主键也完全没有问题。

幂等性应该是工程设计领域都会遇到的问题,不止是在软件领域,产品模块如果都遵循幂等性,那维护成本会低很多。

写于2020-09-13

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 野生AI架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档