34

我不确定为什么媒体普遍说 Google 的 TrueTime API 难以复制(Wired、Slashdot 等)。

我可以理解要获得谷歌正在实现的低错误间隔是一件多么困难的事情,但我不明白 API 本身有多困难。

例如,我制作了一个 hacked together 版本。这是间隔。

    typedef struct TT_interval {
            struct timeval earliest;
            struct timeval latest;
    } TT_interval;

这是现在的功能。

    int TT_now(TT_interval* interval)
    {
        struct ntptimeval tv;
        struct timeval delta;

        struct timeval* earliest_p = &(interval->earliest);
        struct timeval* latest_p = &(interval->latest);
        struct timeval* now_p = &(tv.time);
        struct timeval* delta_p = δ

        timerclear(&delta);
        timerclear(&interval->earliest);
        timerclear(&interval->latest);

        if(ntp_gettime(&tv) == 0) {
            tv.maxerror = tv.maxerror > 0 ? tv.maxerror : -(tv.maxerror);

            delta.tv_sec = delta.tv_sec + (tv.maxerror / 1000);
            delta.tv_usec = delta.tv_usec + ((tv.maxerror % 1000) * 1000);

            if(delta.tv_usec > 1000000) {
                delta.tv_usec -= 1000000;
                delta.tv_sec++;
            }

            timeradd(now_p, delta_p, latest_p);
            timersub(now_p, delta_p, earliest_p);
        } else {
            printf("error on ntp_gettime. %s\n", strerror(errno));
            return ERROR;
        }

        return SUCCESS;
    }

最后,这里是 before 和 after 函数(它们是 now 函数的包装器,可以使用一些 DRY 重构)。

    int TT_before(TT_interval* interval, bool* success)
    {
        struct timeval* latest_p;
        struct timeval* earliest_p;
        TT_interval now;

        if(TT_now(&now) != SUCCESS) {
            return ERROR;
        }

        latest_p = &(interval->latest);
        earliest_p = &(now.earliest);

        if(timercmp(latest_p, earliest_p, <) != 0) {
            *success = true;
            return SUCCESS;
        } else {
            *success = false;
            return SUCCESS;
        }

        return ERROR;
    }

   int TT_after(TT_interval* interval, bool* success)
    {
        struct timeval* latest_p;
        struct timeval* earliest_p;
        TT_interval now;

        if(TT_now(&now) != SUCCESS) {
            return ERROR;
        }

        earliest_p = &(interval->latest);
        latest_p = &(now.earliest);

        if(timercmp(latest_p, earliest_p, <) != 0) {
            *success = true;
            return SUCCESS;
        } else {
            *success = false;
            return SUCCESS;
        }

        return ERROR;
    }

我似乎得到了大约 5,000us 到 350,000us 的间隔错误(使用公共 NTPd)。这与谷歌的数字相去甚远,但你需要从某个地方开始。

除了性能不佳之外,这种设计是否存在重大缺陷会阻止像 Spanner 这样的东西被构建在上面?

4

1 回答 1

57

实现 TrueTime API 的挑战在于您必须提供的保证。也就是说,绝对时间绝不能超出系统中任何服务器上的 TrueTime 时间间隔。如果发生这种情况,那么事件的绝对顺序就会丢失,就像 Spanner 的大多数保证一样。

Spanner 论文通过多种方式实现了这一点(第 3 节):

  1. 多个时间服务器,具有不同的来源(GPS、原子钟),包括来自其他数据中心的时间服务器。
  2. Marzullo 的算法用于检测骗子并将各种可信时间源复用到本地机器时钟的更新中。
  3. 假设跨度服务器的时钟漂移为 200us/s,应用于时钟同步之间。
  4. 从系统中踢出显示测量的本地时钟漂移 > 阈值的机器(阈值 << 200us/s 是必要的)。

现在,您可以使用更简单的方法来实现这一点 - NTP 和假设的 10 分钟错误间隔将很容易做到。但正如问题中所述,这对性能有影响。读写事务 (4.2.1) 必须等待提交,预期等待时间为 2*errorAverage - 在此示例中为 20 分钟。类似地,“现在”时间的只读事务(4.2.2) - 而不是过去的时间 - 必须等待安全时间足够长;在本例中至少 10 分钟。因此,要拥有一个高性能的系统,您需要尽可能减少错误间隔,同时又不会失去您的保证,这就是复杂性出现的地方。

我不确定 ntp_adjtime 在您的系统中是如何被调用的——它可能已经使用多个不受信任和不相关的时间源进行设置,在这种情况下,您已经完成了大部分工作。如果您还可以确保 maxerror 值保证比系统可能的时钟漂移更快,那么您应该很高兴。Spanner 的大部分性能,无需您自己的个人原子钟 :)。

于 2013-08-28T15:21:35.327 回答