3. [WIP]分布式事务@原理
Last updated
Was this helpful?
Last updated
Was this helpful?
描述一下我们的基本矛盾 , 因为数据越来越大, 所以一定会将数据切成好多分片, 存放在不同的实力上. 而同样的一个分片, 也会被存好几份, 其中的某一份被称作是主分片, 剩下来的几份就是副本, 一方面这些副本用来容灾, 另一方面副本也\可以作为只读, 用来提升读的效率.
假设我们有三个服务器 [Server1(比客观时间快5ms) / Server2(比客观时间慢4ms) / Server3(比客观时间慢2ms)], 在上面发生了两个事务 $T_1$ (先发生) / $T_2$ (后发生), 那么在数据库记录下这两个事务的时间戳的时候, ${S}_2$应该大于${S}_1$. 因此, 我们只需要证明: 已知 $T_1$的提交时间早于$T_2$的开始时间, 求证 $S_1 < S_2$. 为了能满足这个性质, 要求:
$S_i$应当大于[所有参与者的] 本地开始时间, 并且需要大于协调者的 TT.Now().Latest
: Start原则
真正提交的时间必须在 $S_i$ 之后, 即真正提交时间大于记录下的时间戳: Cond Wait原则
如果使用这个规则:
$T_1$ 开始的时候:
Server1的本地时间是15ms, Server2(协调者)的本地时间是7ms, 按照Start原则$S_1$会被选择为 max(7+7, 15) = 15
$T_1$的真正执行时间要在15之后我们假设是17ms
$T_2$开始的时候:
Server2(协调者)的本地时间是12ms, Server3的本地时间是13ms, 按照Start原则$S_2$会被选择为 max(12+7, 13) = 19
$T_2$的真正执行时间要在19之后我们假设是21ms
结论:
即使很快的就把事务做完了, 但为了协调时间, 我们故意把真正的提交时间滞后了
但这样能做到事务记录时间上的有序化
如果不使用这个规则:
Server1的本地时间是15ms, Server2(协调者)的本地时间是7ms, 直接选择15ms作为T1的执行时间S1
Server2(协调者)的本地时间是12ms, Server3的本地时间是13ms, 直接选择13ms作为T2的执行时间S2
即使我们都知道Server2开始的更晚, 但记录下的时间, 却是Server2更早, mess
已知客观时间上有: $t{abs}(T_1^{commit}) < t{abs}(T_2^{start})$
由于我们进行了CondWait, 所以记录下的时间戳 $S1 < t{abs}(T_1^{commit}) $
而时间戳 $S2$ 一定大于$t{abs}(T_2^{start})$, 因为很显然只有$T_2$开始了之后, 才能提交产生$S_2$
因此 $ S1 < t{abs}(T1^{commit}) < t{abs}(T_2^{start}) < S_2 $
第三点的解释:
时间戳$S2$的选择: TrueTime区间的最大值 TT.Now().Latest, 因此我们能做到S2大于 $t{abs}(T_2^{start})$
事实上我们不仅选择了协调者本身的 TT.Now().Latest,甚至考虑到所有参与者开始时间, 请注意S2的选择虽然是提交时间, 但我们为了保证大于T2的开始时间, 因此Start原则里max的是开始时间. 所以我们一定能得到 $ t_{abs}(T_2^{commit}) \le S_2$ .
此时根据传递性, $ t{abs}(T_2^{start}) \lt t{abs}(T_2^{commit}) \le S_2$
我们在最上面的图中可以看到, 事实上我们已经把所有事务, 在协调者身上串行化(Linearized) 处理了, 这意味着如果两个事务涉及修改到同一条数据, 那么这两个事务一定得是串行的, 相对的, 如果两个事务并不涉及同一条事务, 那么他们可以并行, 因为Merge的时候并不会出问题. 另外因为我们要等两个 ε , 一个是选择的提交时间TT.Now().Latest, 另一个是TT.After($S_i$)的, 因此等待成本还是挺大的. 根据论文里的数据, 正常来说一个 ε 有90%概率会在1ms之内. 串行的吞吐量是每秒125个.
但这事实上给我们一种可能, 就是集群中的所有节点都可以参与写操作. 这是一个很不一样的设计.