关于版本戳(version stamp)
版本戳产生的动机
在分布式环境下,一份数据会存在多份拷贝。在对数据进行更新时,就可能会存在多个副本中的数据不一致的现象,这包含以下两种情形:
1. 某些节点中的数据已经更新,有些节点中的数据没有被更新。
2. 两个节点都已经更新,但是他们更新的内容出现了不一致。
这样就会产生一个问题,如果一个用户同时读取这两个节点中的数据,就会发现所读取出来的数据是不相同的。所以,用户需要决定所读出来的数据哪个是新的哪个是旧的,由此取出新的数据。为此,引入版本戳来标识数据的新旧版本。
版本戳的产生方法
1. 计数器,由一个主节点来产生计数器的值,分发给所有的从节点。如果在从节点中对数据进行了更新,就把计数器的值加1. 由主节点来产生计数器的值的主要原因在于,保证所有的从节点拥有相同的版本升级方法(计数器值大的版本一定要比计数值小的版本新)。
2. timestamp,这种方法的主要困难在于,所有的节点需要保持一致的时间。如果一个节点的时间不同步,就会导致全局的错误。同时,时间戳的精度问题也是需要考虑的,如果在一个更新非常频繁(一毫秒内可能进行多次更新)的场合中,就必须控制时间戳的精度更大。
3. GUID,产生一个全局唯一的ID,比如说根据日期,硬件信息等产生一个全局唯一的ID。这种方法的主要问题在于,GUID 比较大,同时,无法通过直接比较来判断版本的新旧。
4. 根据内容产生一个hashcode。这种方法的问题与GUID的问题是类似的。
如何使用版本戳
引入一个条件更新的概念,一般的操作是先读取一个数据,再对数据进行写入操作。如果这两个操作不是事务性的原子操作的话,那么就可能存在时间窗口,在写入数据之前这个数据已经发生了变化,而不是之前所读取的数据了。
所以,可能使用条件更新的方法,在写入之前判断当前的数据是否已经发生修改,而这个判断的依据就是版本戳。
主要困难
产生一个所有节点都共享的版本顺序变化规则。
在主从模式下,可以通过主节点产生版本戳进行分发。
1. 但是,在对等模型中,就不存在主节点的概念了。所以引入的是“版本戳数组 ”,为每个节点都产生一个数组中的元素。比如,如果有三个节点,blue, green, red,那么每个节点在局部进行数据修改的时候,就相应地改变这个节点上的版本。接着把这个数据修改的信息通知到其他所有的节点,方法是,两个节点之间交换“版本戳数组”。比如:一个节点A的数组是:[blue:1 , green:2, red:3], 另一个节点B的数组是:[blue:2, green:2, red:3],就可以知道节点B中的数据是更新的。
2. 使用版本戳数组,还可以发现写入冲突。比如:一个节点A的数组是:[blue :1 , green:2, red:3], 另一个节点B的数组是:[blue :2, green:1, red:3]. 也就是说,这个新的数据已经在green 节点中进行了更新,同时又在blue中进行了更新,因此就产生了冲突。但是版本戳数组无法对这种冲突进行解决。