zoukankan      html  css  js  c++  java
  • 时间戳

    时间戳的原理和意义 

    两个问题的解决 

    带宽和查询压力 

     每个 client 都会拉取一系列列表数据,典型的如好友列表、群列表、阻止列表、分组列表

    等等。这些列表数据与用户的体验密切相关,属于非常重要的数据。为了保证数据的正确拉

    取,client 最开始采取的做法是,每次登陆拉取这些列表。 

     后来我们发现用户的列表很少发生改变,于是希望 client 能够通过某种方式捕捉数据改变

    的事件,从而触发拉取动作。这么处理所带来的好处是,client 与 server 之间的流量被减少

    了,同时 server 面临的压力会被减轻。 

     我们采取的做法是为每个列表数据分配用于标识版本的时间戳。Client 在拉取列表数据之

    前,先拉取时间戳与本地时间戳进行对比,如果 server 的数据有更新,client 才会发起拉取

    操作。 

     为什么时间戳需要存放在 server 端呢?考虑如下情况: 

    机器A

    机器B Server 版本1

    版本2 Step 1

    Step 2

    Step 1 用户从机器A迁移至机器B Step 2 用户从机器B迁移至机器A 

    State 1 用户在机器 A 使用 client,然后拥有数据版本 1 作为本地存储 

    State 2 用户在机器 B 使用 client,然后操作了列表数据,拥有数据版本 2 作为本地存储 

    State 3 用户回到机器 A 使用 client,本地存储的数据版本实际上已经很低了,需要与 server

    做一次同步 

     综上所述,server 端需要为每个用户存储时间戳数据,它实际上是由多个时间戳所组成,

    每个时间戳代表着一类数据。 

     通常情况下,列表型的数据拥有自己的时间戳。此外,我们按照变化频率,把用户的属性

    数据(如签名档、头像等),分为了不同的时间戳。这里分类的依据是: 

    1. 基本不变或很少变化的数据合用一个时间戳 

    2. 变化频率较高的数据合用一个时间戳 

     对于情况 1,可以预料时间戳的版本基本不会发生变化,所以它的确可以起到节省流量的

    作用。对于情况 2,则对流量的节约作用很有限。 

    时序问题 

     对于两台服务器而言,例如 chat-dbcache: Chat dbcache R-f

    W-f

    cache

    drop

    in R-b

    W-b 数据版本发生更新

    时间 时间 

    1. R-f(read-forward)表示发出读请求 

    2. W-f(write-forward)表示发出写请求 

    3. R-b(read-backward)表示读请求处理完毕返回 

    4. W-b(write-backward)表示写请求处理完毕返回 

     由上图可知,读请求携带了一份旧数据返回给请求方(这里是 chat)。当请求方含有 cache

    时,由于没有对 cache 做额外的保护,旧数据会进入 cache。这时除了等待 cache 超时,没

    有什么好的办法把旧数据从 cache 中清除掉。 

     这个问题的本质是,对于请求方,当 write 操作返回成功之后,携带旧数据返回的 read

    操作可能入 cache,导致逻辑出现异常。这个问题的解决方案依赖于 bitmap+时间戳。首先

    介绍 bitmap,它在应用程序启动时初始化为 0: 

    Chat dbcache R-f

    W-f

    cache drop

    Can’t in R-b

    W-b 数据版本发生更新

    时间 时间

    Bitmap <- 0

    Bitmap <- 1

    client R-f2 Bitmap <- 0 1. R-f 之前,把 bitmap 置为 0 

    2. W-b 之后,把 bitmap 置为 1,然后清空 cache 

    3. 把数据加载至 cache 之前,需要检查 bitmap。如果为 0,则可以入 cache;否则不入 cache 

    第 1 点的意思是: 

    性质 1 只有 r-f 才能使 bitmap 变为 0 

    第 2 点的意思是: 

    性质 2 只有 w-b 才能使 bitmap 变为 1 

    第 3 点的意思是: 

    性质 3 只有 bitmap 为 0 时,数据才能入 cache 

    Bitmap 的引入保证了: 

    定理 1 数据入 cache 的充分必要条件是: 

    1. 没有 w-b 或者 

    2. w-b 之后有 r-f2 发出 

     充分性: 

    由性质 3,数据入 cache 可以推断 r-b 时 bitmap 为 0。由性质 2,应用程序收到 r-b 的上一

    个操作,肯定不是 w-b(因为如果是 w-b,则 bitmap 会变为 1)。 

    1) 如果 r-b 的上一个操作是 r-f,则说明没有 w-b。 

    2) 如果 r-b 的上一个操作是 r-fx,由性质 1,是否存在 w-b 不会对 bitmap 的值造成影响,

    因为即使 w-b 存在,它也一定是在 r-fx 之前被应用程序接收,那么 r-fx 发出的时候,

    一定会把 bitmap 置为 0 

    必要性: 

    1) 没有 w-b。由性质 2,bitmap 不会变为 1。则只要有 r-f 被发起,可以肯定 r-b 时 bitmap

    为 0,数据入 cache 

    2) W-b 之后有 r-f2 发出,则由性质 1,bitmap 在 r-f2 发出之后会变为 1,于是 r-b 时 bitmap

    为 0,数据入 cache 

    综上所述,命题成立。【证毕】 

     假设服务方保证: 

    性质 4 w-b 之后处理的所有 r-fx,都拥有最新版本的数据 

    那么 w-b 之后发起的 r-f2 所得到的数据一定是一份新数据。 

    Bitmap 的意义在于写操作之后,应用程序可以获得一次读数据的机会,进而获得一份新

    数据,但是 bitmap 并不能保证这份新数据,可以进入 cache 中。考虑如下情况: Chat dbcache R-f

    W-f

    cache drop

    in R-b

    W-b 数据版本发生更新

    时间 时间

    Bitmap <- 0

    Bitmap <- 1 client R-f2 Bitmap <- 0 R-b2

     

    由图可知,r-f2 的确得到了一份新数据,并在 r-b2 携带返回。然而由于 r-b 先返回,且进

    入了 cache,如果 cache 的进入是“先入为主”,那么 r-b2 无法进入 cache。 

     为了解决这个问题,再次引入时间戳的概念。假设 r-bx 携带的数据都具有一个时间戳作

    为版本的标识,那么我们可以依赖这个时间戳限制 cache 的使用,即: 

    定理 2 “高版本的 r-bx 可以进入 cache” 是 cache 中的数据不会长时间错误的充分条件。其

    中“长时间错误”的意思是,如果 cache 不超时,则数据会永远存在于 cache 中。 

     根据 bitmap 的时序图,因为高版本 r-bx 可以进入 cache,所以即使低版本 r-bx 进入 cache,

    也会被新数据淘汰。因此 cache 中的数据不会长时间错误。 

    时间戳的混乱 

    对比上述两种时间戳。为简单起见,我称它们为 A 型和 B 型时间戳。 

    A 型时间戳:解决 client-server 的流量/查询压力问题 

    B 型时间戳:配合 bitmap 解决时序问题 

     这两类时间戳的差异在于,是否关心数据内容。 

     A 型时间戳严格的表示数据的版本。对于 client 而言,为了保证功能正常,不同版本的数

    据必须对应不同版本的时间戳(否则无法获得新数据);对于 server 而言,为了保证性能,

    相同版本的数据不允许有不同版本的时间戳(否则 client 会拉取数据,从而破坏提高性能的

    初衷)。 

     B 型时间戳不需要关注它所代表的数据版本。由时序问题的背景,我们可以推断出 B 型时

    间戳只是为了解决如下问题: 

     假设有三个时间点,分别做了三件事情:r-f / w-b / r-f2,其中 

     r-f 早于 w-b 早于 r-f2 

     如何标记 r-b2 比 r-b 的数据版本新。 

     一个解决办法是,令 r-bx 的时间戳等于 r-fx 的时间戳。对于每次 r-fx,都增加 B 型时间戳的值。这么做的缺点是相同版本的数据,会在 cache 中不停的被切换;然而优点是,应用程

    序可以自己分配 B 型时间戳,不需要借助服务方的支持。 

     初看起来觉得这个做法值得推敲。但是这个解决方法可以满足定理 2,所以它是正确的: 

    1) 在没有 wb 操作的前提下,允许读操作的时序翻转。比如 r-f 和 r-f2 的时序发生了翻

    转,由于没有 wb 操作,cache 的数据一定是正确的 

    2) 存在 wb 操作的前提下,因为 r-f2 在 w-b 之后发出,那么由性质 4 可知,r-f2 一定可

    以获得一份新数据,这就表示它的数据版本一定大于或等于 r-f 的数据版本,因此可

    以使用 r-b2 替换 r-b 

  • 相关阅读:
    学习进度笔记
    学习进度笔记
    学习进度笔记
    《一级架构师》阅读笔记
    学习进度笔记
    学习进度笔记
    学习进度笔记
    mysql
    error: 'wblog/' does not have a commit checked out
    有用的网页
  • 原文地址:https://www.cnblogs.com/zxm1002/p/4741279.html
Copyright © 2011-2022 走看看