包含rust语言go通讯模型的词条( 四 )


分布式事务
要支持分布式事务,首先要解决的就是分布式系统时间的问题,也就是我们用什么来标识不同事务的顺序 。通常有几种做法:
TrueTime,TrueTime 是 Google Spanner 使用的方式,不过它需要硬件 GPS + 原子钟支持,而且 Spanner 并没有在论文里面详细说明硬件环境是如何搭建的,外面要自己实现难度比较大 。
HLC,HLC 是一种混合逻辑时钟,它使用 Physical Time 和 Logical Clock 来确定事件的先后顺序,HLC 已经在一些应用中使用,但 HLC 依赖 NTP,如果 NTP 精度误差比较大,很可能会影响 commit wait time 。
TSO,TSO 是一个全局授时器 , 它直接使用一个单点服务来分配时间 。TSO 的方式很简单,但会有单点故障问题,单点也可能会有性能问题 。
TiKV 采用了 TSO 的方式进行全局授时 , 主要是为了简单 。至于单点故障问题,我们通过 Raft 做到了自动 fallover 处理 。而对于单点性能问题 , TiKV 主要针对的是 PB 以及 PB 以下级别的中小规模集群,所以在性能上面只要能保证每秒百万级别的时间分配就可以了,而网络延迟上面,TiKV 并没有全球跨 IDC 的需求,在单 IDC 或者同城 IDC 情况下,网络速度都很快,即使是异地 IDC,也因为有专线不会有太大的延迟 。
解决了时间问题,下一个问题就是我们采用何种的分布式事务算法,最通常的就是使用 2 PC,但通常的 2 PC 算法在一些极端情况下面会有问题,所以业界要不通过 Paxos , 要不就是使用 3 PC 等算法 。在这里,TiKV 参考 Percolator , 使用了另一种增强版的 2 PC 算法 。
这里先简单介绍下 Percolator 的分布式事务算法,Percolator 使用了乐观锁,也就是会先缓存事务要修改的数据,然后在 Commit 提交的时候,对要更改的数据进行加锁处理,然后再更新 。采用乐观锁的好处在于对于很多场景能提高整个系统的并发处理能力 , 但在冲突严重的情况下反而没有悲观锁高效 。
对于要修改的一行数据,Percolator 会有三个字段与之对应,Lock,Write 和 Data:
Lock,就是要修改数据的实际 lock,在一个 Percolator 事务里面 , 有一个 primary key,还有其它 secondary keys,只有 primary key 先加锁成功,我们才会再去尝试加锁后续的 secondary keys 。
Write,保存的是数据实际提交写入的 commit timestamp,当一个事务提交成功之后,我们就会将对应的修改行的 commit timestamp 写入到 Write 上面 。
Data,保存实际行的数据 。
当事务开始的时候,我们会首先得到一个 start timestamp,然后再去获取要修改行的数据,在 Get 的时候,如果这行数据上面已经有 Lock 了,那么就可能终止当前事务,或者尝试清理 Lock 。
当我们要提交事务的时候,先得到 commit timestamp,会有两个阶段:
Prewrite:先尝试给 primary key 加锁,然后尝试给 second keys 加锁 。如果对应 key 上面已经有 Lock,或者在 start timestamp 之后,Write 上面已经有新的写入,Prewrite 就会失败 , 我们就会终止这次事务 。在加锁的时候,我们也会顺带将数据写入到 Data 上面 。
Commit:当所有涉及的数据都加锁成功之后,我们就可以提交 primay key,这时候会先判断之前加的 Lock 是否还在,如果还在 , 则删掉 Lock,将 commit timestamp 写入到 Write 。当 primary key 提交成功之后,我们就可以异步提交 second keys,我们不用在乎 primary keys 是否能提交成功,即使失败了,也有机制能保证数据被正常提交 。
go和rust哪个更有前景尽管现在go相对来说生态更成熟,但我还是觉得rust的前景更好 。
一、与Go语言相比,rust有什么优势呢?大概有以下这么两点:

推荐阅读