形式化验证工具TLA+:程序员视角的入门之道
简介: 女娲是飞天分布式系统中提供分布式协同的基础服务,支撑着阿里云的计算、网络、存储等几乎所有云产品。在女娲分布式协同服务中,一致性引擎是核心基础模块,支持了Paxos,Raft,EPaxos等多种一致性协议,根据业务需求支撑不同业务状态机。如何保证一致性库的正确性是一个很大挑战,我们引入了TLA+、Jepsen等工具保证一致性库的正确性。本文即从程序员视角介绍形式化验证工具TLA+。
作者 | 祥光
来源 | 阿里技术公众号
一 引言
女娲是飞天分布式系统中提供分布式协同的基础服务,支撑着阿里云的计算、网络、存储等几乎所有云产品。在女娲分布式协同服务中,一致性引擎是核心基础模块,支持了Paxos,Raft,EPaxos等多种一致性协议,根据业务需求支撑不同业务状态机。如何保证一致性库的正确性是一个很大挑战,我们引入了TLA+、Jepsen等工具保证一致性库的正确性。本文即从程序员视角介绍形式化验证工具TLA+。
从理论上证明一个程序或者算法的正确性往往是困难的,工程中一般使用测试来发现问题,但再多的测试也无法保证覆盖到了所有的行为,那些没覆盖到的行为就成为潜在的隐患,一旦在线上再暴露出来,往往会带来不可预期的结果。形式化验证正是为了解决这样的问题,它使用计算机强大的计算能力,暴力的搜索所有可能的行为,检查是否满足事先设定的属性,任何不符合预期的行为都能被发现,从根本上保证算法的正确性。
二 TLA+简介
TLA+(Temporal Logic of Actions) 是Leslie Lamport开发的一门形式化验证语言,用于程序的设计、建模、文档和验证等,特别是并发系统和分布式系统。TLA+的设计初衷是用简单的数学理论和公式精准地对系统进行描述。TLA+及其相关工具有助于消除程序中很难找到、纠错成本高的基本错误。
使用TLA+对程序进行形式化验证,首先要用TLA+对程序进行描述,这样的描述称为规范(Specification)。有了Specification以后就可以使用TLC模型检查器来运行它,运行的过程会遍历所有可能的行为,检查Specification中设定的属性,发现非预期的行为。
TLA+基于数学,使用的是数学思维,与任何编程语言都不相似。为了降低TLA+的门槛,Lamport又开发了PlusCal语言,PlusCal与编程语言类似,可以很方便的描述程序逻辑,并且借用TLA+提供的工具可以直接将PlusCal翻译成TLA+。大多数工程师会发现PlusCal是开始使用TLA+的最简单方法,但简单带来的代价就是PlusCal不具备TLA+的一些功能,有时不能像TLA+那样构造复杂的模型,因此PlusCal还不能取代TLA+。先使用PlusCal编程语言完成基本的逻辑,然后进一步基于生成的TLA+代码再修改,可以简化TLA+的开发。
三 TLA+应用
TLA+在学术界和工业界都有着广泛的应用。TLA+ Examples给出了一些使用TLA+验证过的分布式算法和并发算法。在分布式算法和并发算法的研究领域,提出一个新的算法或者改进一个现有的算法,TLA+验证基本是标配。很多分布式算法论文在非形式化的论证介绍之外, 会附带TLA+的Specification来证明自己的算法是经过形式化验证的。对TLA+比较熟悉的业内人士来说,直接看TLA+的Specification甚至比看大段的论文理解的更快,对于论文的语言描述没有看明白,或者觉得有歧义的时候,查看TLA+的Specification对照着理解,有时候是阅读论文的一把利器,甚至有时候一些算法细节只能在TLA+的Specification里看到。由于Specification是逻辑严密滴水不漏的,可以更好的作为实现的指导。
Lamport的TLA+主页上列出了一些TLA+在工业界的应用。以Amazon为例,Amazon AWS的一些系统的核心算法就使用了TLA+来做形式化验证,如表1列出了TLA+给AWS的一些系统找出的问题,其中涵盖了一些非常核心的组件,这些核心组件的问题一旦在线上暴露,造成的损失将是不可估量的。正是如此,现在分布式云服务的核心算法使用TLA+来对设计做验证已经成为行业标准了,所以作为云服务的从业者或者对此感兴趣的同学,熟悉TLA+绝对是不可或缺的加分项。
表1:TLA+给AWS的系统找出的问题
四 TLA+入门
在VS Code中安装TLA+插件就可以开始使用TLA+了。这里先以一个简单的示例入门TLA+。
考虑一个单比特位的时钟,由于只有一个比特位,只能取值0或者1,其行为只有如下两种情况:
0 -> 1 -> 0 -> 1 -> 0 -> ...
1 -> 0 -> 1 -> 0 -> 1 -> ...
我们如何用TLA+来描述这个时钟呢?为了更容易入门,先用更方便工程师入门的PlusCal来描述:
图1:单比特时钟的PlusCal描述
图1是单比特时钟的PlusCal描述,相信具有编程功底的同学都能轻易看懂。这段PlusCal代码可以直接使用TLA+提供的工具翻译成TLA+代码:
图2:单比特时钟的TLA+描述
有了上面的PlusCal的基础,理解这一段TLA+也不难,重点在于Spec的理解。Spec定义了系统的行为,如图3描述了单比特时钟的行为,Init将clock初始化为0或1,Tick让clock在0和1之间来回跳转,Stutter让clock保持不变。TLA+运行的过程其实就是在图上做遍历。
图3:单比特时钟的行为
要让这段TLA+跑起来,上述TLA+代码需保存至clock.tla文件,此外还需要编写一个如图4所示的clock.cfg文件,clock.cfg文件内容很简单,它注明要运行的Specification是哪个,要检查的Invariant是哪个。
图4:clock.cfg文件内容
有了这两个文件,就可以用TLC来运行了,运行结束后得到如图5所示的结果,图中展示了一些统计信息。
图5:运行结果
五 TLA+原理
为了理解TLA+的运行原理,弄清楚它是怎么遍历的,我们可以在运行的时候加上一些参数,让TLC输出状态图。比如我们运行图6所示的一段TLA+代码,图7是运行所需要的cfg文件。这个例子试图找出用面值为1、2和5的钱组合出19块钱的所有组合方式。
图6:money.tla
图7:money.cfg
运行结束后可以得到如图8所示的状态图,图中的顶点为状态,共20种状态,money=0为初始状态,money=19为终止状态,图中的边为动作,共4种动作:Add(1)、Add(2)、Add(5)和Terminating。
图8:状态图
TLA+的运行是完全串行的,运行的的过程即在状态图上做图的遍历,每遍历到一个状态,就检查一下当前状态是否满足事先设定的不变式,满足则继续遍历,不满足则立即报错。TLA+会尝试所有的遍历路径,不错过任何一种行为。我们知道图的遍历方式有深度优先和广度优先两种,TLA+默认广度优先遍历,也可配置成深度优先模式或者随机行为模式,深度优先模式需要给定一个最大深度。
现在我们知道了TLA+的原理实际上就是状态图的遍历并检查的过程,这样的过程看似简单,却能覆盖到算法所有的路径,不漏掉任何一种行为。实际我们经常使用TLA+检查算法的Safety和Liveness属性。
六 TLA+并发
到这里相信读者对TLA+的原理已经有了初步的了解,但细心的读者可能心中还有一个很大的疑问:TLA+运行过程是完全串行的,那么串行运行的TLA+如何模拟并发算法或者分布式算法呢?
对于串行算法来说,算法中的动作是Totally Ordered,本身就是一个串行的状态机,很容易构造状态图。但并发算法或者分布式算法中的动作是Partially Ordered,不是一个串行的状态机,如何构造出状态图呢?
如果并发算法或者分布式算法中的动作也能变成Totally Ordered,则也可以看作是一个串行的状态机,构造出状态图。
实际上Lamport大师一早就研究了这个问题,在他被引用的最多的论文《Time, Clocks and the Ordering of Events in a Distributed System》中给出了为分布式系统中的事件定序的方法。简单的说就是在保证具有Partially Ordered关系的事件的顺序的前提下,将剩下的无序的事件人为定一个顺序,可以将所有事件排一个序变为Totally Ordered,并且这种定序不会破坏因果关系。
事实上TLA+大放异彩的地方正是在并发算法和分布式算法领域,因为在这些领域算法的行为多种多样,容易疏漏,因此需要TLA+全面检查算法的所有路径,不漏掉任何一种行为。
七 总结
TLA+使用计算机强大的算力搜索算法所有可能的行为,以发现非预期的行为。随着计算机算力的提升,以及软件和硬件系统越来越复杂,TLA+将越来越受到重视,越来越成为工程师的必备技能。
最后如果读者对TLA+感兴趣,这里推荐一本TLA+的入门书籍《Practical TLA+》,比较适合入门,并且网上有免费的电子版可以直接下载。
原文链接
本文为阿里云原创内容,未经允许不得转载。
形式化验证工具TLA+:程序员视角的入门之道的更多相关文章
- 不懂前端的程序员不是好美工——UI框架metronic使用教程——程序员视角
本着不懂前端的程序员不是好美工的观点,所以作为一个仅懂一点前端的程序员,为了成为一个好美工,所以只能用些取巧的方法伪装一下. metronic一个基于bootstrap的响应式的后台管理平台的UI框架 ...
- Java程序员的Golang入门指南(上)
Java程序员的Golang入门指南 1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如 ...
- Java程序员的Golang入门指南(下)
Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...
- 为什么说每个程序员都应该刷几道LeetCode?
2015年即将过去,最近在回顾和总结过去一年的工作经历,发现自己并不能算是一名合格的程序员. Google某前员工Lucida在文章<白板编程访谈——Why,What,How>当中写道: ...
- iOS程序员的自我修养之道
新技术的了解渠道 WWDC开发者大会视频 官方文档 General -> Guides -> iOS x.x API Diffs 程序员的学习 iOS技术的学习 官当文档 Sample C ...
- 形式化验证工具(PAT)羊车门代码学习
首先介绍一下PAT工具,下图是PAT工具的图标 PAT工具全称是Process Analysis Toolkit,可以做一些简单的验证. 今天我们分析一下例子里面的Monty Hall Problem ...
- 形式化验证工具(PAT)2PC协议学习
今天我们来看看2PC协议,不知道大家对2PC协议是不是了解,我们先简单介绍一下. 两阶段提交协议(two phase commit protocol, 2PC)可以保证数据的强一致性,许多分布式关系型 ...
- 形式化验证工具(PAT)Perterson Algorithm学习
今天学习一下Perterson Algorithm. 这个算法是使用三个变量来实现并发程序的互斥性算法. 具体看一下代码: Peterson算法是一个实现互斥锁的并发程序设计算法,核心就是三个标志位是 ...
- 形式化验证工具(PAT)Reader-Writers Problem学习
经过前几次的学习,我们应该对PAT有一点点的了解了,我们加下来就直接看例子中的一个问题,这个问题比较简单. 看代码: //The classic Readers/Writers Example mod ...
- 写给程序员的机器学习入门 (八 补充) - 使用 GPU 训练模型
在之前的文章中我训练模型都是使用的 CPU,因为家中黄脸婆不允许我浪费钱买电脑.终于的,附近一个废品回收站的朋友转让给我一台破烂旧电脑,所以我现在可以体验使用 GPU 训练模型了
随机推荐
- FBEC大会 | 瑞云科技 CTO 赵志杰:元宇宙时代的基础设施——实时云渲染
FBEC未来商业生态链接大会于2023年2月24日在深圳福田大中华喜来登酒店盛大召开,本次大会由广东省游戏产业协会.深圳市互联网文化市场协会指导,陀螺科技主办. 大会以"勇毅前行·逐光而上& ...
- TP6框架--EasyAdmin学习笔记:项目初始化+环境配置
最近在研究一个基于TP6的框架EasyAdmin,这里分享下我的开发心得 首先要获取原始项目文件 这里是git地址 https://github.com/zhongshaofa/easyadmin 项 ...
- 详解SSL证书系列(6)了解HTTP及网络基础
使用HTTP协议访问Web 你知道当我们在网页浏览器(比如Chrome)的地址栏中输入URL时,Web网页是如何呈现的吗? Web页面当然不会凭空显示出来.根据Web浏览器地址栏中指定的URL,W ...
- 靶场搭建----phpstudy2018安装及注意问题
安装 官网下载: https://www.xp.cn/download.html 新人推荐2018 版本phpstudy 介绍 系统服务------开机自启 非服务模式------开机不自启 搭建好环 ...
- JAVA去掉字符串前面的0、去掉字符串后面的0
//去掉字符串前面的0 String str1 = "00123400"; String newStr1 = str1.replaceAll("^0+", &q ...
- CSS+HTML+flexible.js+rem实现屏幕缩放适配概念原理解释
首先理解几个概念: (1)屏幕尺寸:屏幕对角线的长度,一般用英寸表示,1英寸=2.54cm. (2)dp((或者叫dip):设备独立像素,也就是设备屏幕上多少个点. (3)dpi:印刷行业术语,像素密 ...
- mybatis添加maven依赖
1 <dependencies> 2 <!--导入Mybatis依赖包--> 3 <dependency> 4 <groupId>org.mybatis ...
- Spring boot中拦截器的简单使用
1.创建自定义拦截器类:首先,你需要创建一个自定义的拦截器类,该类需要实现HandlerInterceptor接口.例如,你可以创建一个名为CustomInterceptor的类. import or ...
- #轮廓线dp#HDU 1400 Mondriaan's Dream
题目传送门 分析 状压dp会TLE,考虑用轮廓线dp, 设 \(dp[i][j][S]\) 表示现在处理到 \((i,j)\) 这个位置轮廓线上状态为 \(S\) 的情况 二进制位为1表示左边或者上方 ...
- #Multi-SG#HDU 3032 Nim or not Nim?
题目 有\(n\)堆石子,每次可以从一堆中取出若干个或是将一堆分成两堆非空的石子, 取完最后一颗石子获胜,问先手是否必胜 分析 它的后继还包含了分成两堆非空石子的SG函数,找规律可以发现 \[SG[x ...