web-dev-qa-db-ja.com

GoogleのTrueTimeAPIを複製するのが難しいのはなぜですか?

GoogleのTrueTimeAPI(Wired、Slashdotなど)を複製するのが難しいとマスコミが一般的に言っている理由はわかりません。

Googleが達成している低いエラー間隔を取得するのがいかに難しいかは理解できますが、API自体がどのように非常に難しいかはわかりません。

たとえば、私はハッキングされたバージョンをまとめました。これが間隔です。

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

これがnow関数です。

    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のようなものを上に構築することを妨げる大きな欠陥がありますか?

32
Jon Bringhurst

TrueTime APIを実装する際の課題は、提供する必要のある Guarantees にあります。つまり、絶対時間は決してシステム内のサーバーのTrueTime間隔の外にある必要はありません。これが発生する可能性がある場合、Spannerのほとんどの保証と同様に、イベントの絶対的な順序が失われます。

Spanner paper は、手段の組み合わせによってこれを実現します(セクション3):

  1. 他のデータセンターのタイムサーバーを含む、異なるソース(GPS、原子時計)を備えた複数のタイムサーバー。
  2. 嘘つきを検出し、さまざまな信頼できる時間ソースをローカルマシンクロックの更新に多重化するマルズーロのアルゴリズム。
  3. クロック同期の間に適用される、スパンサーバーでの200us/sの想定クロックドリフト。
  4. 測定されたローカルクロックドリフト>しきい値(必要に応じてしきい値<< 200us/s)を示すシステムのキックマシン。

これで、 can は、より簡単な手段でこれを達成できます-NTPそして10分の想定エラー間隔で簡単に実行できます。しかし、質問で述べたように、これにはパフォーマンスへの影響があります。読み取り/書き込みトランザクション(4.2.1)はコミットを待機する必要があり、予想待機時間は2 * errorAverage-この例では20分です。同様に、読み取り専用トランザクション(4.2.2)は「現在」(過去の時間ではなく)は、セーフタイムが十分に進むのを待つ必要があります。この例では少なくとも10分です。したがって、高性能システムを使用するには、エラー間隔を可能な限り最小限に抑える必要があります。なし保証を失うと、複雑さが生じます。

システムでntp_adjtimeがどのように呼び出されているかはわかりません。信頼できない、相関のない複数のタイムソースを使用してすでに設定されている可能性があります。その場合、ほとんどの場合、すでにそこにいます。 maxerror値がシステムの可能なクロックドリフトよりも速く進行することが保証されていることも確認できる場合は、問題がないはずです。あなた自身の個人的な原子時計なしで、Spannerのパフォーマンスのほとんど:)。

48
Eric Burnett