Linux のシステム時計の時刻あわせ



2004年 7月 3日

松本徳真 < matsu@netfort.gr.jp >


概要

常時接続に限らず、ネットワークに接続されたコンピュータが勝手な時を 刻んでいたのでは、色々な問題が発生します。
本セミナーでは、Linux のシステム時計を個人ユーザーが可能な範囲でま ともにする事を考えます。

1) UNIX time, 協定世界時について、glibc での実装に付いて簡単に解説。
2) ntp 等有名な、時刻合わせ、時刻比較プログラムに付いて簡単な紹介。
3) 現在企画中の簡易時刻修正プログラムの紹介。



はじめに



協定世界時(UTC)について

協定世界時, 閏秒等の単語は聞いた事があると思いますが、これらが 何物か把握している人は少ないようです。コンピュータのシステム時計 に付いて考える前に協定世界時に付いて、簡単に解説してみたいと思います。

時を計る物差しは、この世に無数に存在します。皆がそれぞれ勝手な時計を 使っていると、混乱してしまいます。食事の待ち合わせ時間の指定で、 「俺様の腹のすいた時」と指定されても困ってしまいます。
そこで、皆で使う共通の時刻システムとして決められたのが、 協定世界時(UTC)です。


日本標準時

協定世界時で 06:00:00 頃と言えば日本ではお昼過ぎです。日常生活の便利の ためには、12:00:00 が、お昼であって欲しいものです。そこで、世界各地で 地方時と言うものが運用されています。東西に長い国では、複数の地方時が ある場合もあります。日本では、日本標準時(JST)が使用されています。 日本標準時は協定世界時に対してちょうど 9時間進んでいます。協定世界時で 2004年6月10日 0時0分0秒は、日本標準時では 2004年6月10日 9時0分0秒に なります。協定世界時と地方時の変換は、何時間進んでいるか遅れているか がわかれば機械的に簡単に計算できます(但し、夏時間が存在する、非文明国は 除く)。



真太陽時



恒星時, 平均太陽時

恒星時 恒星の観測から得られる。ある恒星が子午線を通過してから、 次に子午線を通過するまでの時間を一日とする。地球の自転をを 直接時刻に反映する。
真太陽時 地球表面から見た太陽の動きを基準にした時刻系。地球の軌道が楕円形である、 地軸が約23.4度傾いている等の事情で、季節によって一日の長さが異なる。
平均
太陽時
太陽時の季節変動分を平均化したもの。恒星時から計算で得ることができる。



国際原子時(TAI)

まず 1秒の長さを定義して、一定の速度で時が進んで行く時刻システム
技術の進歩とともにますます精密な時刻システムになって行く。
国際原子時は、世界各地の原子時計を比較しながら運営されている。

133Cs 原子の基底状態の2つの超微細準位の間の遷移に対応する 放射の 9 192 631 770 周期の継続時間。

セミナーではここに、原子時計の写真を貼っていました。
原子時計や、周波数標準器等の写真を見たい方は、

http://jjy.nict.go.jp/
独立行政法人 情報通信研究機構 日本標準時グループ

http://www2.nict.go.jp/dk/c251/index.html
独立行政法人 情報通信研究機構 原子周波数標準グループ

をさまよって下さい。



協定世界時(UTC)



TAI, UT1, UTC, leapsecond


数ヵ月経過

さらに数ヵ月経過

さらに、さらに数ヵ月経過



UNIX での実装

time_t time( time_t *time);
int gettimeofday( struct timeval *tv, struct timezone *tz );
等のシステムコールで、ある起点(1970/01/01 00:00:00 GMT) からの 経過時間を秒、またはマイクロ秒単位で得ることができる。
localtime(), localtime_r(),
gmtime(), gmtime_r()

等の libc に含まれる関数を使って、年、月、日、時、分、秒に 変換することができる。



古代の UNIX では、

unix time と呼ばれる time() の戻り値を、 年、月、日、時、分、秒に変換する際、1日を 86400( = 24時間*60分*60秒)秒 と決め打ちしていたが、かといって、TAI でも、UT1, UT2 とも 言えない不思議な時刻システムであった。
昔は、正確な時刻を取得する安価な手段がなかったので、そんなに 気にすることもなかったということか。
ただ、現在では、高速なネットワークで多くのコンピュータが接続される 中で、時刻同期の重要性は高まっているが、あいまいな基準では困るよね?



glibc, FreeBSD では、

glibc 2.1 以降では、従来の unix time 的な使用法ができる一方、 設定により、UTC に対応することもできる。 FreeBSDの libc でも、かなり早い時期から対応している。 他のUNIXシステムはわかりません。必要な人は各自で調べてね。







UTC対応の考え方

time() 関数の戻り値を、1970/1/1 00:00:10 TAI からの 経過秒数と定義する。
あるいは、1972/1/1 00:00:00 UTC の値を 63072000( =2*365*24*60*60 ) と 定義する。
time() 関数の戻り値から、年月日時分秒に変換するには、 閏秒(leapsecond)実施 のデータが必要。タイムゾーンが Asia/Tokyo に設定されている場合、
/usr/share/zoneinfo/Asia/Tokyo
に閏秒実施データが含まれていれば、UTC 対応のシステムとなり、含まれていな ければ、従来同様のシステムになる。



UTC対応システムの問題点

不定期に実施される閏秒の実施が決まれば、新しい閏秒実施データを取得し、
/usr/share/zoneinfo
以下を再構築する必要がある。
入手先
ftp://elsie.nci.nih.gov/pub/
自動化するのはそう難しくないので大した問題ではない。

UTC に対応していないアプリケーションが結構ありそう。



UTC 未対応アプリケーション例

cron は、もともと指定時間は分までしか指定できないので、 気にしないというのもひとつの手。あるいは cronexec を使え。
http://www.netfort.gr.jp/~tosihisa/cronexec/

時刻合わせの雄, ntp が、まじめに対応しない。DJB作 clockspeed を使うか?でも Pentium または互換CPU (TSCレジスタを持つもの) に限られる。





ちょっと休憩

なにか質問ありますか?











時刻合わせの実際

時刻合わせの要素
時刻 時刻をあわせる。
周波数 時計のすすみ具合を調整する。


毎日時報を聞きながら腕時計をあわせる
→ ”時刻”をあわせる。

いつも遅れがちな時計を、時計屋さんで直してもらった
→ ”周波数”をあわせる



基準時刻の取得方法

GPS
長波JJY
テレフォンJJY
ネットワーク経由









ネットワーク経由の遅延対策



ネットワーク経由の基準時刻取得プロトコル

ntp 123/udp ネットワーク遅延対策あり
サーバ: ntpd
クライアント: ntpd, ntpdate, clockspeed, その他いっぱい
daytime
13/udp,tcp
time
37/udp,tcp
ネットワーク遅延対策なし
サーバ: inetd 内蔵
クライアント: netdate
ICMP TIMESTAMP ネットワーク遅延対策あり
サーバ: TCP/IP プロトコルスタック
クライアント: clockdiff



裏技その1

#!/bin/sh
host=$1
datestr=`wget -S --spider $host 2>&1\
|grep " Date: "` || exit
echo "${datestr##* Date: }"







裏技その2

#!/bin/sh
tmstr=`wget -q -O - \
http://www2.crl.go.jp/cgi-bin/JST.cgi \
|grep Standard`
tmstr=${tmstr#*\"}
tmstr=${tmstr%\"*}
echo $tmstr





裏技は使うな!!

http://www2.crl.go.jp/cgi-bin/JST.cgi
をブラウザで表示すると、

「日本標準時表示のページ」は URL が変更になりました。
トップページからたどり直してください。

と表示されます。

この cgi を利用して時刻合わせをするプログラム が配布されたため、想定外のアクセスがあり、URL 変更を余儀なくされ たそうです。
にくいことに、このページのコメントに、時刻データが含まれていて、 例の時刻合わせプログラムが動作し続けるように工夫がされています。
組織によっては DDoS 攻撃だ、不正アクセスだと騒ぎだしかねないこと を考えると、なかなか大人の対応だと思います。







公開 NTP サーバ

ntp1.jst.mfeed.ad.jp
ntp2.jst.mfeed.ad.jp
ntp3.jst.mfeed.ad.jp

ntp プロトコルで時刻合わせを行うことが可能なら、これらの サーバを使うと良いでしょう。現在は、試験公開中ですが、 本運用になるまで、停止されることはなさそうです。







ntpd

ntpd パッケージに含まれる ntpdate を cron 等で定期的に実行すると、 時刻合わせができる。
ntpd を実行すれば、周波数同期も行う。
ntpd は、ntp サーバとしても機能する。アクセス制御が 出来るとは言え、用途によってはちょっと不安。
周波数同期は ソフトウェア PLL によるかなり高度なもの。
時刻同期のみと、周波数同期も行った場合の時刻のずれの模式図。


PLL の概念







clockspeed

時刻と、周波数の調整を行う。
ntpd がソフトウェア PLL によって、適宜周波数を調整するのに対して、 長時間の時刻ずれの測定により、周波数を決定する。
始めから UTC に対応した設計がなされている。
頻繁に基準時刻を取得できない環境で有利になる。
t = p * TSC +offset
で、p と offset を決定し、適宜システム時刻に反映する。
settimeofday(), ではなく、adjtime() を使用しているので、 時刻が逆戻りしたりする事はない。
Pentium および 互換 CPU の持つ TSC レジスタに依存。



現在企画(実験)中

Linux には、移植性に難はあるが、adjtimex() というシステムコールが 存在する(たぶん ntpd 由来)。
clockspeed のように、長時間の時刻ずれの測定結果から、システム時計 の周波数を決定し、adjtimex() で、システム時計の周波数を変更する。
ntpd, clockspeed の様な daemon でなく、時々ユーザが、手動、cron 経由、 あるいは、ネットワーク接続スクリプトから実行する。













おしまい

質問をどうぞ。