出題の概要と適用場面
あるLinuxサービスが、リクエストの開始時に CLOCK_REALTIME を読み取り、「現在時刻 - 開始時刻」によって2秒のタイムアウトを適用しています。同じタイムソースが監査レコードのタイムスタンプ記録、現地時間で毎日09:00のジョブのスケジューリング、および複数サービスからのイベントの順序付けにも使われています。NTPの時刻補正や手動でのクロック変更の後、ウォールクロック時間(実時間)が前後にジャンプすることがあります。その結果、一部のリクエストが即座に期限切れになる一方で、他のリクエストは2秒をはるかに超えて待機し続けます。
ローカルの経過時間とタイムアウト、マシンがサスペンドしている間も期限を消費すべきリース、人間のカレンダーに基づくスケジュール、永続的な監査時刻、そしてマシン間の因果関係に基づく順序付けのそれぞれに適したクロックまたは順序制御メカニズムを選択してください。プロセスの再起動、シリアライズ、クロックスキュー、および検証計画についても扱ってください。
2秒のタイムアウト、サスペンド時の動作、スケジュールは面接上の前提条件です。Linuxの主要なクロックは CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_BOOTTIME であり、言語のランタイムがこれらをラップしている場合があります。特定のアプリケーションフレームワークではなく、オペレーティングシステムの時刻セマンティクスと信頼性の推論が中核スキルであるため、カテゴリは general です。
2026年に更新されたシステム設計面接のリソースでは、ウォールクロック、モノトニッククロック、クロック補正、スキューによる障害を一つの実践トピックとして扱っています。POSIX.1-2024の根拠資料、Linuxのmanページ、Goのドキュメントは、個別に検証可能なAPIの境界を提示しています。これらの情報源は現在の妥当性と長期的な対策価値を示すものであり、特定企業の出題内容や面接頻度を示すものではありません。
面接官が評価しているポイント
第一に、候補者が「その時刻の値は何の問いに答えるためのものか」を問えるかどうかです。ウォールクロック時間は「現時点で常用時またはUTCのどの瞬間か」に答え、監査、証明書の有効性、カレンダースケジュールに適しています。モノトニック時間は「このランタイム内でどれだけの時間が経過したか」に答え、所要時間、バックオフ、タイムアウトに適しています。API名やナノ秒単位の精度はセマンティクスの代わりにはなりません。
第二に、候補者が「モノトニック=完全に均一、グローバルに一貫、あるいは常に進み続ける」という意味ではないことを理解しているかどうかです。Linuxの CLOCK_MONOTONIC は、システム時刻の設定による不連続なジャンプの影響を受けず、逆戻りもしませんが、段階的なNTP調整(スルーイング)によって進む速度が変化し、システムサスペンド中の時間は除外されます。連続して読み取った場合に同じ値が返されることすらあります。
第三に、候補者が CLOCK_MONOTONIC、CLOCK_BOOTTIME、CLOCK_MONOTONIC_RAW、およびCPU時間を区別できるかどうかです。BOOTTIMEはモノトニックであり、サスペンド時間を含みます。MONOTONIC_RAWは段階的なNTP調整を回避するため低レベルのクロック測定には有用ですが、アプリケーションのタイムアウトにおけるデフォルトの選択肢ではありません。プロセスおよびスレッドのCPUクロックは、待機時間ではなくCPU上で実際に実行された時間をカウントします。
第四に、候補者がローカルのモノトニックな読み取り値を、あたかも普遍的なタイムスタンプであるかのように永続化したり送信したりすることを避けられるかどうかです。その原点にはカレンダー上の意味がなく、再起動をまたいだ永続的なタイムラインにはなりません。物理的なタイムスタンプ単体ではマシン間の順序を証明できません。要件に応じて、ビジネス上のシーケンス、データベースのコミット位置、コンセンサスログ、ランポートクロック、またはハイブリッド論理クロック(HLC)が正確性を担保する必要があります。
最後に、候補者が実際のクロック障害を注入してテストできるかどうかです。単に2秒間待つテストを1回行うだけでは、ウォールクロックのステップ、スルーイング、サスペンド、再起動、リモートとのスキューのいずれも検証できません。
回答前に確認すべき質問
- 2秒とは、アクティブな実行時間ですか、それとも実際の経過時間ですか? プロセスが正常に動作している間のリクエストタイムアウトには
CLOCK_MONOTONICを使用します。1分間のサスペンド後に期限切れになっている必要があるローカルリースにはCLOCK_BOOTTIMEを検討すべきです。 - デッドラインはプロセスの再起動をまたいで有効である必要がありますか? インメモリのモノトニックなデッドラインは単一の実行インスタンスに属します。信頼できるウォールクロックの有効期限またはビジネス状態を永続化し、起動後に上限付きのローカルバジェットを設定します。
- 「毎日09:00」はどのタイムゾーンで定義され、夏時間(DST)のギャップや重複(フォールド)では何が起こりますか? カレンダージョブにはIANAタイムゾーンと、存在しないまたは重複する現地時間に対するポリシーが必要です。モノトニック時間ではこのルールを表現できません。
- 監査レコードは何を証明する必要がありますか? 検索やコンプライアンスには人間が読めるUTC時刻が役立ちますが、時刻の一致、クロックの巻き戻し、複数ホスト間のスキューに対処するためには、安定したID、コミットシーケンス、または因果関係フィールドも必要です。
- サービス間の順序付けの目的は、表示、重複排除、因果関係、それとも厳密な全順序ですか? 表示のみであればスキューを許容できる場合があります。台帳や複製ステートマシンでは通常、「タイムスタンプが大きい方が勝ち」ではなく、コミット権限やコンセンサスログが必要です。
- 対象プラットフォームはサスペンドやVMマイグレーションをどのように処理しますか? Linuxがクロックセマンティクスを定義していますが、実際の言語ランタイム、ホスト、仮想化レイヤー、解像度についてはバージョン固有の検証が必要です。
- 時刻同期はクロックをステップ(即時変更)させますか、それともスルー(徐々に調整)させますか? ウォールクロックのステップは所要時間の減算処理を直接破綻させます。スルーイングの場合、モノトニック時間は減少しない状態を保ちますが、生のハードウェアカウンタに対する進み方がわずかに変化します。
30秒の回答フレームワーク
「私は『その時刻が何を答えるべきか』に基づいてクロックを選択します。監査タイムスタンプや毎日09:00のスケジュールには、永続的なウォールクロック時間が必要です。単一プロセス内の2秒の所要時間やタイムアウトにはモノトニッククロックを使用し、ウォールクロックのステップによって早期または遅延してタイムアウトが発生しないようにします。サスペンド中もリースを消費させる必要がある場合、Linuxでは CLOCK_BOOTTIME を使用します。モノトニックな値をシリアライズしたり、再起動やマシンをまたいで比較したりすることはしません。サービス間のウォールクロック時間は観測用であり、ビジネスバージョン、コミットログ、または論理クロックが正確性を担保します。ウォールクロックの前後のステップを注入し、スルーイング、サスペンド、再起動、ホスト間のスキューについて、ユースケースごとの不変条件に照らしてテストします。」
ステップごとの詳細解説
ステップ 1: 1つの時間値を5つの要件に分解する
システム全体に1つのタイムソースを割り当てるのではなく、決定表を作成します。
| 要件 | 推奨される基準 | 主な理由 |
|---|---|---|
| ローカルの所要時間、リトライバックオフ、2秒のタイムアウト | CLOCK_MONOTONIC | 不連続なウォールクロック変更の影響を受けないため |
| サスペンド時間を消費するローカルリース | CLOCK_BOOTTIME | モノトニックでありサスペンドを含むため |
| UTCの監査時刻、証明書の有効性 | CLOCK_REALTIME | Unixエポックの意味を持ち、永続的で交換可能なため |
| 現地時間で毎日09:00 | ウォールクロック + IANAゾーン + DSTポリシー | 人間のカレンダーで定義されるため |
| ホスト間の正しい順序 | ビジネスバージョン、コミットログ、または論理クロック | 物理的なスキューがあるため、タイムスタンプ単体では因果関係を証明できない |
| プロファイラでのCPUコスト | プロセスまたはスレッドのCPUクロック | CPU上で実際に実行された時間をカウントするため |
1つのレコードが2つの時間ディメンションを持つこともあります。たとえば、リクエストログは検索用にUTCの observed_at を保存し、プロセスはモノトニックな開始読み取り値から duration_ms を計算します。これらのフィールドは異なる問いに答えるものであり、互いに代替できるものではありません。
ステップ 2: ウォールクロック時間が所要時間の減算を破綻させる理由を説明する
コードが elapsed = realtime_now - realtime_start を評価するとします。リクエストの開始後にウォールクロック時間が90秒進むと、次のチェックで誤ってタイムアウトと判定されます。逆に90秒巻き戻ると、elapsed が負の値になり、ウォールクロック時間が追いつくまでリクエストが待たされる可能性があります。また、NTPはクロックの進み速度を変更して段階的に時刻を補正することもあります。ウォールクロック時間は外部の常用時に合わせる必要があるため、アプリケーションは連続した読み取り値が厳密に増加することを前提にできません。
開始時と現在の読み取り値は同じモノトニッククロックから取得するか、そのクロックに明示的に基づいたタイマー/デッドラインAPIを使用してください。realtimeの読み取り値からmonotonicの読み取り値を引き算してはいけません。それぞれの原点が異なります。「raw」の方が正確そうに聞こえるという理由だけで MONOTONIC_RAW を選ばないでください。アプリケーションのタイムアウトでは通常、秒の長さが実際の秒数に合わせて規律(調整)されている非減少クロックが適しており、これこそが通常のPOSIX/Linuxモノトニッククロックが提供するものです。
ステップ 3: サスペンドがバジェットを消費するかどうかを判断する
Linuxの CLOCK_MONOTONIC は、システムがサスペンドしている間、時間の積算を停止します。ラップトップが1分間スリープした場合、30秒のローカルMONOTONICタイマーはレジューム後もまだ残り時間を持っています。これは実行可能時間で定義された処理には適していますが、マシンがスリープしている間に期限切れになるべきセッションやセキュリティリースには適していません。
CLOCK_BOOTTIME はサスペンド時間を含み、後者のルールに適合します。サスペンドされたマシンを起こして処理を実行するには、適切なアラーム機能と権限が別途必要であり、BOOTTIMEを選択しただけで自動的に復帰するわけではありません。再起動をまたぐリースの場合、新しいブートでは古い原点のポータブルな継続性が提供されないため、BOOTTIMEの数値だけを永続化することは依然としてできません。
ステップ 4: カレンダーのデッドラインと永続化を個別に処理する
「毎日09:00」はカレンダールールです。これにはウォールクロック時間、名前付きタイムゾーン、DSTポリシーが必要です。ルール変更により、ある日付の09:00が異なるUTCオフセットにマッピングされる場合があり、一部の現地時間は重複したり存在しなかったりします。起動時に1回だけモノトニックな期間に変換して再計算しないのではなく、カレンダー式とタイムゾーンを保持してください。ある回のイベントがトリガーされた後、その実行タイムアウトの制御にはモノトニック時間を使用できます。
監査データには、正規化されたUTC時刻、業務上必要な場合は元のタイムゾーンまたはオフセット、レコードID、および信頼できるコミット順序を保存する必要があります。ウォールクロック時間は人間が読める形式ですが、一意でも厳密に増加するものでもありません。NTPの巻き戻し中に同一またはより小さいタイムスタンプが発生しても、主キー、カーソル、残高更新順序を破損させてはなりません。
ステップ 5: プロセス間およびマシン間の伝播を制限する
絶対的なモノトニック値は、定義されたランタイム環境内でのみ意味を持ちます。Goの公式ドキュメントでは、シリアライズ時にモノトニックな読み取り値を明示的に除去することが記載されています。あるプロトコルが別のホストに monotonic_deadline=8374921 を送信して直接比較させることはできません。そのホストは異なる原点、ブートサイクル、またはAPI規約を持っている可能性があるためです。
RPCでは、上限付きの残りバジェットまたはUTCデッドラインを伝播させることができますが、トレードオフを明確にする必要があります。各ホップはローカルのモノトニッククロックでバジェットを消費し、転送、キューイング、スキューのためのマージンを残します。リスクの高いリースでは、クライアントの時刻単体を信頼することはできません。書き込みが引き続き有効であるかどうかは、サーバーの権限、リースエポック、フェンシングトークンによって決定されます。
イベントの順序付けも、同じ要件優先のアプローチに従います。ログUIはウォールクロック時間を表示し、スキューの疑いがある箇所にフラグを立てることができます。因果関係にはトレースの親情報、メッセージシーケンス、または論理クロックを使用できます。厳密なステートマシン順序には、データベースのコミット位置またはコンセンサスログを使用します。すべてのイベントを created_at でソートすることは観測順序を提供するだけであり、実際の前後関係の証明にはなりません。
ステップ 6: テストをクロックの不変条件として実装する
テスト環境で注入可能なクロックやプラットフォームのタイム名前空間/仮想クロックを使用して、以下を検証します。
- 500ミリ秒後にウォールクロック時間を90秒進める。モノトニックな2秒のタイムアウトが即座に発火してはならない。
- ウォールクロック時間を90秒巻き戻す。経過時間が約2秒後にタイムアウトが正しく発火し、UTCログはID衝突なしで巻き戻り時刻を記録できる。
- 段階的な補正(スルーイング)をシミュレートし、負の所要時間が発生しないことを確認し、許容される測定誤差を記録する。
- リース期間より長くサスペンドする。MONOTONICタスクは定義されたバジェットを保持し、BOOTTIMEリースは期限切れになる。
- プロセスを再起動する。古いモノトニックな値は復元されず、永続化された有効期限の状態はその規約に従って再確立される。
- 2つのテストノードに逆方向のクロックオフセットを設定する。ステートマシンは、ウォールクロックの大きさではなく、バージョンまたはログ位置によってイベントを適用し続ける。
- DSTのギャップと重複をシミュレートし、毎日09:00の明示的なポリシーを検証する。
最低限、負の所要時間の発生回数、タイムアウト誤差、早期/遅延期限切れ、クロックのステップ/スルーイベント、ホストオフセット、DSTによる重複実行、タイムスタンプの衝突によって拒否された書き込みを監視します。90秒のオフセットは障害注入用の値であり、本番環境のスキューを表すものではありません。
質の高い模範解答
「この実装は、1つの CLOCK_REALTIME の値に3つの異なる意味を持たせてしまっています。ウォールクロック時間は手動変更や同期を受け入れる必要があります。時刻が進むステップが発生すると now - start が突然2秒を超え、巻き戻りが発生すると差分が小さくなるか負になります。私なら、単一のモノトニック時間ドメイン内でリクエストの所要時間とバックオフを計算し、好ましくはそのクロックにバインドされたデッドラインAPIを使用します。
次に、他の要件を分離します。監査レコードにはUTCウォールクロック時間と安定したレコードIDを保持します。毎日09:00のジョブにはIANAゾーンと明示的なDSTポリシーを保持します。ローカルリースがサスペンド中も期限切れになる必要がある場合はLinuxの CLOCK_BOOTTIME が適しており、実行可能時間のみをカウントする場合は CLOCK_MONOTONIC が適しています。CPU時間も MONOTONIC_RAW も、一般的なリクエストタイムアウトの直接の代替にはなりません。
モノトニックな値をデータベースに保存したり、別のホストに送信したり、再起動をまたいで復元したりはしません。サービス間のログには観測用としてウォールクロック時間を含めることができますが、ビジネス上の順序はバージョン、メッセージシーケンス、コミットログ、または論理クロックが担います。各RPCホップはローカルのモノトニッククロックで上限付きバジェットを消費し、セキュリティリースではサーバーの権限とフェンシングも併用します。
最後に、90秒進むステップ、90秒の巻き戻し、段階的な補正を注入し、サスペンド、プロセスの再起動、逆方向にスキューした2つのノード、およびDST境界をテストします。合格基準は、負の所要時間が発生しないこと、ウォールクロックのステップによってリクエストが即座にまたは90秒遅れてタイムアウトしないこと、約束されたサスペンド動作が維持されること、そして物理的なスキューによってマシン間の状態順序が変化しないことです。」
よくある間違い
- すべてのタイムスタンプをモノトニッククロックに変更する → モノトニック値には交換可能なカレンダーの意味がなく、毎日09:00を表現できない → 所要時間、カレンダー、監査、順序付けごとに個別に選択する。
- タイムアウトのために
CLOCK_REALTIMEの減算を使い続ける → 進むステップで早期に期限切れになり、巻き戻りで遅延する → 開始時刻、デッドライン、現在時刻を1つのモノトニックドメインで計算する。 - モノトニック時間はNTPの影響を全く受けないと主張する → LinuxのMONOTONICは不連続なステップを回避するが段階的な周波数調整は受け入れる → 『決して巻き戻らない』と『完全に均一』を区別する。
CLOCK_MONOTONICがサスペンドを含むと思い込む → Linuxではサスペンド時間が除外される → サスペンドのセマンティクスを先に定義し、サスペンド時間をカウントする必要がある場合はBOOTTIMEを使用する。CLOCK_MONOTONIC_RAWをアップグレード版のデフォルトとして扱う → クロックの規律をバイパスすると実際の秒数の測定精度が悪化する可能性がある → アプリケーションのタイムアウトには通常のモノトニック時間を使用し、低レベル測定にはrawを検討する。- モノトニックなデッドラインを別のホストにシリアライズして送信する → 受信側にはポータブルな共通原点が存在しない → 定義されたバジェットまたはUTCデッドラインを伝播させ、ローカルで変換し、スキューリスクを制限する。
created_atをマシン間のビジネス順序として使用する → スキューや巻き戻しによってイベントの順序が逆転する可能性がある → 正確性の担保をバージョン、コミット位置、コンセンサスログ、論理クロックに委ねる。- 1回の手動クロック変更しかテストしない → スルーイング、サスペンド、再起動、DSTがカバーされないままになる → クロック注入マトリクスを使用し、独立した不変条件を検証する。
フォローアップ質問と回答
NTPの段階的な補正(スルーイング)によって、2秒の CLOCK_MONOTONIC の間隔は不正確になりますか?
クロックの進み速度がわずかに調整される可能性はありますが、ウォールクロックのステップのような不連続な巻き戻しは発生しません。通常のタイムアウトでは、秒の長さが実際の秒数に近接するようシステムによって調整された非減少クロックが求められるため、この調整は適切です。クロック同期コード、ハードウェアベンチマーク、または周波数分析を行う場合は、CLOCK_MONOTONIC_RAW を検討し、サスペンドやドリフトを個別に処理します。
リースが再起動をまたいで維持され、かつマシンが1分間オフラインになっている間も期限を消費する必要があります。何を変更すべきですか?
絶対的なローカルのMONOTONIC値やBOOTTIME値を永続化してはいけません。サーバーがウォールクロックの有効期限時刻、リースエポック、フェンシングトークンを保持し、クライアントは再接続後にその権限者と再検証を行います。1回のプロセス実行中であれば、付与された残りバジェットをローカルのBOOTTIMEデッドラインに変換できます。仮に古いプロセスが自身のリースが有効であると誤認したとしても、ストレージレイヤーが古いフェンシングトークンを拒絶します。
両方のサービスがNTPを使用している場合、ミリ秒単位のタイムスタンプでイベントの順序を決定できますか?
いいえ。時刻同期は不確実性を狭めますが、2つの物理的な読み取り値の間の因果関係を証明するものではなく、ネットワーク遅延によって観測順序が変わることもあります。ログ表示用であれば、両方の値を保持して不確実性を明示します。古い状態が新しい状態を上書きするのを防ぐには、エンティティごとのバージョン、メッセージシーケンス、データベースのコミット位置、または論理クロックを使用してください。グローバルな厳密順序には、コンセンサスまたは単一シーケンサーのパスが必要です。
リクエストのレイテンシをプロセスのCPU時間で測定してはいけない理由は何ですか?
リクエストはネットワーク、ディスク、ロック、またはコネクションプールで待機することがあります。これらの待機はCPUをほとんど消費しないにもかかわらず、ユーザーの体感レイテンシに影響します。CPU時間は計算コストを測定するものであり、経過時間クロックはエンドツーエンドのレイテンシとタイムアウトを測定するものです。両方を記録することは可能ですが、答えている問いが異なります。
夏時間の移行時、毎日09:00のジョブはどのように動作すべきですか?
まずプロダクトとしてのルールを定義します。存在しない現地時間の場合はスキップするか次の有効な時刻に移動します。重複する時間の場合は、1回のみ実行するか各オフセットで1回ずつ実行します。現在のUTCオフセットのみを保存するのではなく、IANAゾーンと重複排除キーを保存してください。次のカレンダー発生日時が決まれば、ローカルの待機および実行タイムアウトには引き続きモノトニック時間を使用できます。