vector clock向量时钟算法简介

本文通过实例介绍向量时钟的基本原理及应用,探讨其在分布式系统中解决数据一致性问题的方法,并提出结合时间戳解决冲突的策略。

原文链接:http://blog.chinaunix.net/uid-27105712-id-5612512.html

一、使用背景

先说一下需要用到向量时钟的场景。我们在写数据时候,经常希望数据不要存储在单点。如db1db2都可以同时提供写服务,并且都存有全量数据。而client不管是写哪一个db都不用担心数据写乱问题。但是现实场景中往往会碰到并行同时修改。导致db1db2数据不一致。于是乎就有人想出一些解决策略。向量时钟算是其中一种。简单易懂。但是并没有彻底解决冲突问题,现实分布式存储补充了很多额外技巧。


这里反向叙述方式, 介绍向量时钟。先举实际例子让读者有个感性认识,然后再说算法规则。

二、举个例子

向量时钟实际是一组版本号(版本号=逻辑时钟),假设数据需要存放3份,需要3db存储(用ABC表示),那么向量维度就是3,每个db有一个版本号,从0开始,这样就形成了一个向量版本 [A:0, B:0, C:0];
Step 1: 初始状态下,所有机器都是 [A:0, B:0, C:0]

      DB_A——> [A:0, B:0, C:0]

      DB_B——> [A:0, B:0, C:0]

      DB_C——> [A:0, B:0, C:0]

Step 2:  假设现在应用是一个商场,现在录入一个肾6的价格 iphone6 price 5888; 客户端随机选择一个db机器写入。现假设选择了A,数据大概是这样 :
{key=iphone_price; value=5888; vclk=[A:1,B:0,C:0]}


Step 3:  接下来A会把数据同步给BC;于是最终同步结果如下

      DB_A——> {key=iphone_price; value=5888; vclk=[ A:1,B:0,C:0]}

      DB_B——> {key=iphone_price; value=6888; vclk=[ A:1, B:0,C:0]}

      DB_C——> {key=iphone_price; value=5888; vclk=[ A:1,B:0,C:0]}


Step 4:过了分钟,价格出现波动,升值到6888;于是某个业务员更新价格。这时候系统随机选择了B做为写入存储,于是结果看起来是这样:

      DB_A——> {key=iphone_price; value=5888; vclk=[A:1,B:0,C:0]}

      DB_B——> {key=iphone_price; value=6888; vclk=[A:1,B:1,C:0]}

      DB_C——> {key=iphone_price; value=5888; vclk=[A:1,B:0,C:0]}


Step 5:于是B就把更新同步给其他几个存储

      DB_A——> {key=iphone_price; value=6888; vclk=[A:1, B:1,C:0]}

      DB_B——> {key=iphone_price; value=6888; vclk=[A:1,B:1,C:0]}

      DB_C——> {key=iphone_price; value=6888; vclk=[A:1, B:1,C:0]}


到目前为止都是正常同步,下面开始演示一下不正常的情况。


Step 6:价格再次发生波动,变成4000,这次选择C写入:

      DB_A——> {key=iphone_price; value=6888; vclk=[A:1, B:1,C:0]}

      DB_B——> {key=iphone_price; value=6888; vclk=[A:1,B:1,C:0]}

      DB_C——> {key=iphone_price; value=4000; vclk=[A:1, B:1,C:1]}


Step 7:  C把更新同步给AB,因为某些问题,只同步到A,结果如下:

      DB_A——> {key=iphone_price; value=4000; vclk=[A:1, B:1, C:1]}

      DB_B——> {key=iphone_price; value=6888; vclk=[A:1,B:1,C:0]}

      DB_C——> {key=iphone_price; value=4000; vclk=[A:1, B:1,C:1]}


Step 8:价格再次波动,变成6000元,系统选择B写入

      DB_A——> {key=iphone_price; value=6888; vclk=[A:1, B:1, C:1]}

      DB_B——> {key=iphone_price; value=6000; vclk=[A:1,B:2, C:0]}

      DB_C——> {key=iphone_price; value=4000; vclk=[A:1, B:1,C:1]}


Step 9: 当B同步更新给AC时候就出现问题了,A自己的向量时钟是 [A:1, B:1, C:1], 而收到更新消息携带过来的向量时钟是 [A:1,B:2, C:0], B:2 比 B:1新,但是C:0却比C1旧。这时候发生不一致冲突。不一致问题如何解决?向量时钟策略并没有给出解决版本,留给用户自己去解决,只是告诉你目前数据存在冲突


三、规则介绍

版本号变更规则其实就2条,比较简单

1、   每次修改数据,本节点的版本号 加1,例如上述 step 8中 向B写入,于是从B:1 变成 B:2, 其他节点的版本号不发生变更。

2、   每次同步数据(这里需要注意,同步和修改是不一样的写操作哦), 会有三种情况:

a: 本节点的向量版本都要比消息携带过来的向量版本低(小于或等于) 如本节点为 [A:1, B:2,C:3]}, 消息携带过来为  [A:1, B:2,C:4] 或  [A:2, B:3,C:4]等。 这时候合并规则取每个分量的最大值。

b:   本节点的向量版本都要比比消息携带过来的向量版本高,这时候可以认为本地数据比同步过来的数据要新,直接丢弃要同步的版本。

c:   出现冲突,如上述step 9中,有的分量版本大,有的分量版本小,无法判断出来到底谁是最新版本。就要进行冲突仲裁。


四、冲突解决

其实没有一个比较好的解决冲突的版本:就笔者目前所了解,加上时间戳算是一个策略。具体方法是再加一个维度信息:数据更新的时间戳(timestamp)。[A:1, B:2,C:4ts:123434354] ,如果发生冲突,再比较一下两个数据的ts,大的数值说明比较后更新,选择它作为最终数据。并对向量时钟进行订正。


五、其他问题

1、向量时钟的维数和存放数据备份数目相等,如果备份数目太多。会导致向量太长。不过目前好像不会存在这个问题,一般备份数目=3就足够。即使再多几份,也不会太长。
2、 冲突纠错时,矫正方有很多:有的放在后台服务端矫正,有的交给客户端来矫正,譬如客户端仲裁后,写回服务端。纠错时机也有很多,有点在读数据是发现数据不一致进行纠正,有的是同步时候发现不一致纠正。实际实现大家自己选择。

<think>好的,用户想了解操作系统的Clock时钟页面置换算法的工作原理及实现。首先,我需要回顾一下自己掌握的相关知识,并确保准确无误。根据之前的引用内容,CLOCK算法是LRU的近似实现,通过循环链表和使用位来管理页面。接下来,我需要详细解释其工作原理和实现步骤,同时保持结构清晰。 首先,应该从基本概念入手,解释CLOCK算法的设计目标,即低开销地模拟LRU。然后描述其数据结构,比如循环链表和页表项中的使用位。接着分步骤说明算法的工作流程,包括指针移动、检查使用位、替换页面的条件等。可能还需要比较CLOCK与其他算法如FIFO、LRU的区别,突出其优势。 在实现部分,可能需要用伪代码或流程图来展示,但用户提到需要中文回答,所以用文字描述更合适。同时,用户要求行内数学表达式用$...$,独立公式用$$...$$,但这个问题可能涉及较少的数学公式,更多是流程和逻辑。不过如果有涉及计算的部分,比如页面访问概率,可能需要用数学表达式。 另外,用户要求生成相关问题,我需要根据内容提出几个相关的问题,比如与其他算法的比较、改进型CLOCK、性能分析等。还要注意引用标识的正确添加,确保引用来源对应之前的参考内容。 需要检查是否有遗漏的关键点,比如改进型CLOCK算法是否要提及?根据引用[2],用户提到了改进型,但问题主要关于基础CLOCK,所以可能简要提到改进型作为扩展,但详细说明留在相关问题中。 最后,确保语言简洁明了,结构清晰,分点阐述,符合用户对回答结构的要求。可能还需要注意术语的准确性,如“使用位”是否也称为“访问位”,是否需要统一术语。根据引用内容,使用“使用位”更合适。</think>### 操作系统 Clock 页面置换算法原理及实现 #### 一、算法原理 Clock 算法(时钟置换算法)是一种通过**循环检测页面使用状态**的近似 LRU 算法。其核心思想是通过一个“时钟指针”遍历内存中的页面,结合**使用位(accessed bit)**判断页面是否最近被访问,以此决定替换哪一页[^1]。 ##### 关键数据结构 - **循环链表**:内存中的页面按顺序排列成环形结构。 - **页表项属性**: - **使用位(accessed bit)**:标识页面是否被访问过(1 为已访问,0 为未访问)。 - **存在位(present bit)**:标识页面是否在内存中。 ##### 工作流程 1. **初始化**:时钟指针指向链表头部。 2. **页面访问**: - 若页面在内存中,将其使用位置 1。 - 若页面不在内存中(缺页),触发页面置换流程。 3. **置换流程**: - **步骤 1**:检查当前指针指向页面的使用位。 - **步骤 2**:若使用位为 0,直接替换该页面,指针前移一位。 - **步骤 3**:若使用位为 1,将其置 0,指针前移一位,重复此过程直到找到使用位为 0 的页面。 这一过程可类比时钟指针循环扫描页面,故得名“时钟算法”。 #### 二、算法实现 以下为简化伪代码描述: ```text 初始化循环链表和指针 while 发生缺页中断时: current_page = 指针当前指向的页面 while True: if current_page.使用位 == 0: 替换 current_page 指针移动到下一位置 break else: current_page.使用位 = 0 指针移动到下一位置 ``` #### 三、算法特性 1. **开销低**:仅需维护使用位和指针移动,无需精确记录访问时间(如 LRU)。 2. **近似 LRU**:通过周期性清除使用位,模拟“最近未被使用”特性。 3. **时间复杂度**:最坏情况下需遍历整个链表,但实际平均性能接近 $O(1)$[^2]。 #### 四、改进型 Clock 算法 在标准算法基础上引入**修改位(dirty bit)**,优先替换未修改的页面(减少磁盘写入次数)。其规则为: 1. 第一轮扫描:寻找 $(使用位=0, 修改位=0)$ 的页面。 2. 第二轮扫描:寻找 $(使用位=0, 修改位=1)$ 的页面。 3. 若未找到,重复上述过程。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值