安価なパソコンハードウェアとGPSを組み合わせて、 ネットワーク上に高精度の時刻情報を提供するNTP Stratum-1サーバを構築する方法を紹介する。 また構築されたNTPサーバの時刻精度の評価を行い、 精度に影響する要因や対策法について述べる。
キーワード:NTP、GPS、PPS、Linux、FreeBSD
山梨大学総合情報処理センターの機種更新にあたり、 学内で初めてNTP Stratum-1サーバを運用することとなった。 NTP(Network Time Protocol)はネットワーク上のコンピュータやルータなどの機器の正確な時刻合わせに用いられるプロトコルで、 特にStratum-1サーバは精度の高い時刻信号をネットワーク以外から参照して他のNTPサーバやクライアントに高精度な時刻情報を提供する。 Stratum-1サーバを参照して時刻合わせを行うサーバはStratum-2、 Stratum-2サーバを参照して時刻合わせを行うサーバはStratum-3と順次呼ばれ、 Stratum-1サーバからの参照距離が遠くなるほど徐々に精度が低くなる。 精度低下の要因としてはネットワーク上での通信時間の揺らぎ、 サーバ自身のハードウェア特性や室温変化による内部時計の精度の揺らぎ、 サーバの負荷その他がある。
一般的なユーザの利用する端末では要求される時刻の精度はさほど高くはなく、 ファイルの日付が狂ってしまうなどの長期的な時間のずれが生じない程度で十分な場合が多い。 その様な場合は例えば1日に1回程度Stratum-3程度の精度を持つサーバと時刻合せをすれば十分で、 UNIX系であればntpdateコマンドをcronなどで実行する。 ファイアウォールや各種サーバなどでは何か問題が生じたときのログの解析の際に、 他のサーバのログと比較して追跡調査することが多いが、 その様な場合にはそれらのサーバ間で時刻のずれが生じているとログの解析が多少面倒である。 サーバ類の場合にはできればntpdateでなくntpdによって随時時刻合せをしておくことが望ましい。 ただし将来的にntpdにセキュリティホールが発見されて不正侵入の足掛かりにされてしまうという可能性を考えると、 あえてntpdは動かさずにntpdateでの時刻合せを行うのが適切な場合もある。
Stratum-1サーバが参照する時刻信号の発生源としては原子時計、電波信号、 GPS(Global Positioning System)などが有名であるが、 今回導入するシステムでは入手性と価格面を考慮してGPSを利用することにした。 GPSとしては古野電機のTS-820という機種 http://www.furuno.co.jp/product/gps/ts820/ts820.html を利用した。 TS-820は価格、入手性およびNTPサーバとしての動作実績に優れており、 古くなったPCと組み合わせることで簡単に安価で高精度のStratum-1サーバを構築することができる。
今回はStratum-1サーバを構築するにあたり、 CPUの性能によるNTPサーバの精度の違いがどの程度生じるかを調査することにした。 Stratum-1サーバとして十分な精度の時刻をネットワークに提供するために、 どの程度の性能のハードウェアが必要なのか見極めるためである。 またサーバOSとしてはLinuxとFreeBSDを採用することにし、 Stratum-1サーバとして利用する際の設定方、性能、運用しやすさなどを比較することにした。
表1: サーバ基本構成
CPU | Pentium 133MHz / PentiumIII 550MHz |
---|---|
メモリ | 128MB |
OS | Linux カーネル2.4.17 / FreeBSD 4.5 |
GPS | 古野電機 TS-820 RS-232C接続 |
NIC | 100base-TX |
GPSタイムサーバTS-820は複数の衛星と通信可能で、電源投入と同時に衛星の探索を開始する。 最低1つの衛星と通信が可能な状態になると時刻信号をRS-232Cポートを通じて出力しはじめる。 できるだけ多くの衛星と安定した通信が可能になるためには、 TS-820のアンテナは見晴らしの良い屋外に設置する必要がある。 そのため山梨大学総合情報処理センターでは5階建ての情報メディア館屋上にアンテナを設置した。 アンテナとTS-820本体を結ぶケーブルは15メートルであるため、 TS-820本体およびNTPサーバは空調管理の行き届いた場所に設置することができず、 アンテナ設置場所直下のパイプシャフト内に設置することになった。 NTPサーバの精度を確保するためには実は温度管理が非常に重要であるが、 今回は設置場所の都合からそれが困難であった。
TS-820がRS-232Cポートを通じて出力する時刻情報には2種類あり、一つは時刻情報を含む文字列で、 もう一つは文字列で表された時刻に発生される正確な時刻信号のパルスである。 これは電話による時刻案内に似ており、 まず文字列で「只今から何時何分何秒をお知らせします」と時刻情報を流したあとで、 正確な時刻に「ポーン」とパルスを発生する訳である。 これらの情報は毎秒出力されており、 特に後者の正確なパルスをPPS(Pulse Per Second)信号と呼ぶ。 仕様書によればPPS信号を利用することでTS-820では±1マイクロ秒の精度の時刻信号を提供することができる。
PPS信号が利用できない場合にはntpdは時刻情報の文字列を得るタイミングで時刻を調整するが、 PPS信号と異なり文字列は必ずしも正確なタイミングで出力されない。 運用上の経験からは数ミリ秒程度の誤差を含んでいる。 この程度の精度であればStratum-2サーバで十分に実現可能であるので、 Stratum-1サーバとして運用する価値はない。 Stratum-1サーバを構築するならばPPS信号は是非とも利用する必要がある。 PPS信号をRS-232Cポートから得るためには、 NTPサーバ側のOSカーネルがそれに対応するよう設定されていなければならない。 以下にLinuxおよびFreeBSDでのPPS信号へのカーネルの対応方法をのべる。
LinuxではPPS信号への対応は公式カーネルに含まれておらず、 カーネルでPPS信号を利用するためにはカーネルソースにパッチを当てて再コンパイルする必要がある。 PPS信号対応パッチはPPSkitとして http://www.jp.kernel.org/pub/linux/daemons/ntp/pps/ などのカーネルパッチのミラーから入手可能である。 2002年1月末の段階ではカーネル2.2系列用に2.2.19対応のPPSkit-1.1.0、 2.4系列では2.4.16対応のPPSkit-2.0.1が公開されている。 PPSkitではPPS信号の検出だけでなく、 カーネルの処理可能な最小時間単位を標準の1マイクロ秒から1ナノ秒に変更する。 これはPPS信号自体が1マイクロ秒以内の精度を持っているので、 それに対応するための自然な拡張と思われるが、 それと同時に他のパッチとの競合が発生する可能性があることを知っておく必要がある。 カーネルのレイテンシ(応答時間)を低減するためのAndrew MortonのLow Latency Patchや、 Robert LoveのPreemptive Kernel Patchなどもカーネルの時間関係の構造体を拡張するため、 PPSkitと競合する。 上記2つのパッチは開発カーネルへの取り込み中で、 将来的には安定版カーネルにも公式に採用されることが見込まれる。 その際にはPPSkitもそれに対応したものが登場するか、 PPSkit自体が公式採用されるなどの変化が見られるはずである。
PPSkitを使用する以外の選択肢としては、 TS-820開発元の古野電機が提供するLinux用のパッチがある。 ただしこのパッチはRedhat5.2用で、今となっては古いカーネル2.0.36に対するものである。 PPSkitと比べて古野電機提供のパッチの特徴としては以下の点がある。
今回構築するNTPサーバでは、
などの点から古野電機提供のパッチは使用せず、PPSkit-2.0.1を利用することにした。
今回LinuxはディストリビューションとしてDebian Woodyを利用することにした。 これは筆者の利用経験に起因するところが大であるが、 セキュリティ修正への対応の敏速さ、 システムアップグレードの容易さなどの点では、 他のディストリビューションに比べて大きな優位性があると判断されたためである。 しかしDebian Woodyはリリース間近であるとはいえ開発途中で、 PPSkit-2.0.1が対応するカーネル2.4.16は他のパッケージのバグのために、 ソースからコンパイルできないという不具合を抱えていた。 このため今回は2002年1月末で最新のカーネル2.4.17に対してPPSkit-2.0.1を適用した。 パッチはカーネルのバージョン番号の変更などの些細な修正だけで適用でき、 作成されたカーネルも全く問題なく動作した。 パッチ適用後のカーネルの設定でPPSを有効にするには最低限以下の4項目を設定する必要がある。
FreeBSDカーネルではPPS信号への対応はかなり以前から実装されている。 この点ではFreeBSDに一日の長があるといえる。 ただしインストーラで提供されるカーネルではこの機能が無効になっているため、 ユーザ自身がカーネルを再コンパイルしてこの機能を有効にしなければならない。 カーネル再構築の際には以下のオプションを有効にする。
TS-820は衛星と通信可能になってしばらくすると、 RS-232CポートからUTC時刻情報、アンテナの位置情報、衛星情報などを毎秒出力する。 電源投入後のデフォルトでは、 GGA(位置・時刻等)、ZDA(時刻等)、GSV(衛星情報等)、 およびVTG(速度・方位)形式のデータがRS-232Cポートに出力される。 シリアルポートを通信速度4800baud、データ長8bit、パリティなし、 ストップビット1bitに設定しておけば以下のような出力を毎秒確認することができる。
$GPGGA,152746,3540.6769,N,13834.4795,E,1,07,02.34,000338.3,M,0040.0,M,, $GPZDA,152746,27,01,2002,+00,00 $GPGSV,2,1,08,06,17,266,46,08,36,059,50,10,63,044,55,17,14,319,43 $GPGSV,2,2,08,23,31,304,48,24,37,158,51,26,54,259,52,27,11,040,33 $GPVTG,302.3,T,309.4,M,000.1,N,0000.1,K
またTS-820は設定によりRMC形式の時刻情報を出力させることもできる。 一方でntpdで利用するNMEAドライバはデフォルトでRMC形式のデータを想定して動作し、 設定によりGGAおよびGGL形式のデータを解釈することができる。 そのためTS-820とGPS汎用のNMEAドライバを組み合わせて使う場合には、 選択肢として以下の設定方法がある。
どの方法を使うかは利用者の判断次第である。 筆者としては、 TS-820のデフォルト設定では時刻情報を含まないデータが多く出力されているのは無駄と感じたので、 TS-820にRMC形式での出力を設定し、ntpd側での設定をデフォルトのまま運用することにした。 TS-820にZDA/GGA/GSV/VTG形式での出力をやめさせ、 RMC形式だけを出力させるにはRS-232Cポートから以下の文字列を送ってやれば良い。
$PFEC,GPint,ZDA00,GGA00,GSV00,VTG00,RMC01
設定後の出力は以下のようにシンプルになる。
$GPRMC,153044,A,3540.6762,N,13834.4781,E,000.1,272.9,270102,007.1,W*6C
この設定は停電などにより初期設定に戻ってしまうため、 NTPサーバ起動時やntpdの起動時に自動的にRMC形式での出力を有効にするよう設定しておく必要がある。 以下ではntpdのNMEAドライバを修正することでntpd起動時に設定が行われる方法を紹介する。
カーネルがPPS信号に対応したところで、 次はNTPサービスを実際に動かすntpdの導入と設定に入る。
Linuxディストリビューションで配布されるバイナリパッケージのntpdは、 PPSkit自体が公式パッチではないためか、PPS信号に対応していない。 Debianにはntpサーバで利用するために特にntp-refclockなるパッケージも存在するが、 これもPPSに対応していなかった。 (PPSkitの利用を勧める旨は記述されている。) そのためLinuxでPPS信号を利用するためにはPPSkitによるカーネルのパッチ以外にも、 ntpdをPPS対応にコンパイルし直さなければならない。 実はntpdをLinuxでPPS対応にコンパイルし直す際に必要となる追加ヘッダファイルはPPSkitに含まれており、 これらはPPSkitでパッチを当てたカーネルソースの場所(通常/usr/src/linux)の下の include/linuxディレクトリに展開されるtimepps.hとtimex.hである。 逆に言えばLinuxではPPSkitなしではカーネルのPPS信号への対応もできなければ、 ntpdをPPS信号に対応させることもできないことになる。 ntpdをコンパイルし直す際にはtimepps.hとtimex.hを/usr/include/sys/などにコピーするか、 シンボリックリンクを張るなどする必要がある。
FreeBSDではカーネルのPPS対応が以前から公式にサポートされているためか、 標準のPORTSに含まれるntpdはPPS対応済のバイナリが配布されている模様である。 そのため特にコンパイルし直さなくても設定だけでPPS対応で動作することが確認された。 ただしntpdのNMEAドライバをTS-820と組み合わせて使うためには若干のソース変更が必要なので、 結局はソースの入手と再コンパイルをすることになる。
以下はLinux/FreeBSD共通の作業である。 次はntpdの最新安定版ソースを www.ntp.org などから入手する。 2002年1月末の最新版は4.1.0であった。 ソースファイルを/usr/local/src以下などの適当な場所に展開する。
TS-820の出力する文字列の初期化を行いRMC形式での時刻情報の出力をさせるため、 ntpd付属のNMEAドライバに若干の修正を加える。 (前述のようにRMC形式でなくTS-820の初期設定のままの出力で、 ntpd側でGGA形式を読むように設定する運用方法もある。) 展開したソースファイルのうちntpd/refclock_nmea.cを修正する。 ntpd/refclock_nmea.c内でgps_sendという関数が呼び出されている場所が2個所ある。
gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);を
gps_send(pp->io.fd,"$PFEC,GPint,ZDA00,GGA00,GSV00,VTG00,RMC01\r\n",peer);に変更する。
gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);をコメントアウトする。
以上が済んだらあとは基本的には以下の手順だけで済む。
./configure make make install
念のためconfigureでPPS信号への対応がされていることを確認しておく。 NMEAドライバではシリアルポートをTS-820と通信できるように初期化するので、 特にブート時などにシリアルポートの設定をしなくても動作可能である。
次はntpdがGPSとの通信に使用するデバイスファイルの作成を行う。 ntpdのNMEAドライバでは/dev/gps1や/dev/gps2という名前のデバイスファイルを使用することを前提としているので、 実際に使うGPSが接続されているシリアルポートに対応するデバイスファイルへのシンボリックリンクを作成する。 Linuxでは例えばGPSがシリアルポートCOM1に接続されており、 これをgps1として使う場合には以下のようなリンクを張る。 (当然作業にはroot権限が必要である。)
ln -s /dev/ttyS0 /dev/gps1
同様にFreeBSDでは
ln -s /dev/cuaa0 /dev/gps1
となる。
以上の準備が全て整えばあとは設定ファイルを準備してntpdを起動するだけである。 標準の設定ファイルは/etc/ntpd.confで、 最低限以下の内容を記述する。 ディレクトリ名やファイル名は環境に依存するので適宜書き換える。
driftfile /var/lib/ntp/ntp.drift statsdir /var/log/ntpstats/ # ログファイルに残す統計データの設定 statistics loopstats peerstats clockstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable # TS-820 GPS on /dev/gps1 server 127.127.20.1 # NMEAドライバ(20)でgps1を使用 fudge 127.127.20.1 flag3 1 # PPS信号使用
ntpd起動前にコンピュータの時計がある程度正確な時刻に設定されている必要がある。 dateコマンドで手動設定するか、 他のntpサーバを参照してntpdateコマンドなどであらかじめ設定しておく。 そしていよいよntpdを起動する。 起動してしばらくは動作が安定しないのであせらず放置しておく。 TS-820のマニュアルによれば3時間程度で安定するそうである。 またloopstatsファイルには統計データが出力され始める。 PPS信号で1マイクロ秒程度の精度が確保されていれば、 ntpq -pコマンドの出力結果はdelay、offset、jitter共に安定して小さな値(単位はミリ秒)になるのが確認できる。
> ntpq -p remote refid st t when poll reach delay offset jitter ============================================================================== *GPS_NMEA(1) .GPS. 0 l 3 64 377 0.000 0.000 0.001
これらの値が大きなままであればどこかに問題がある。 PPS信号が利用されていることを確認する別の手段としてntptimeコマンドがある。
> ntptime ntp_gettime() returns code 0 (OK) time c077e3f7.901fb7f8 Tue, Apr 30 2002 0:23:35.562, (.562984784), maximum error 1926 us, estimated error 5 us, TAI offset 0 ntp_adjtime() returns code 0 (OK) modes 0x0 (), offset 1.536 us, frequency 33.334 ppm, interval 256 s, maximum error 1926 us, estimated error 5 us, status 0x2107 (PLL,PPSFREQ,PPSTIME,PPSSIGNAL,NANO), time constant 6, precision 3.769 us, tolerance 496 ppm, pps frequency 33.334 ppm, stability 0.012 ppm, jitter 2.192 us, intervals 14647, jitter exceeded 11208, stability exceeded 347, errors 0.
PPS信号が利用されていればこのようにPPSFREQ、PPSTIME、PPSSIGNALなどがstatusとして表示される。 表示されない場合にはカーネル設定、ntpdのPPS対応、 設定ファイル、ケーブル接続、TS-820の衛星捕捉などのどこかに問題がある。
以上でTS-820を用いたNTP Stratum-1サーバの基本的な設定は終りである。 動作確認して問題なければブート時にntpdが自動起動するように初期化スクリプトを用意しておく。
上記の方法によって構築されたNTP Stratum-1サーバについて精度評価を行った。 数日間運用してどの程度の精度が安定的に確保できるのか評価したが、その際に
などについての評価を行った。
まずCPU性能がNTPサーバの時刻精度に与える影響について調べた。 Intel PentiumIII 550MHzとIntel Pentium 133 MHzの二種類のCPUについてFreeBSD 4.5上にNTPサーバを構築し、 同一の設定で運用した。 ソフトウェア上は全く同一設定であるが、 ハードウェアの相違点はCPUおよびマザーボードだけである。 図1は二種類のCPUで運用したNTPサーバの、ある一日における時刻の変動を表している。 横軸は一日を秒単位で表しており、 縦軸は秒単位(一目盛が2マイクロ秒)での時刻の変動である。 赤色の線がCPUがPentiumIII 550MHzのもので緑色の線がPentium 133MHzのものである。 これらの値はntpdが出力する統計データの中で、 loopstatsファイルに記録されるデータから抜き出している。
図1: CPU性能による時刻精度の比較
この様にNTPサーバでは時刻情報は様々な要因から一日を通じて微妙に変化しており、 その変動をntpdが修正しながら高い精度を保持するように働いている。 ここで用いた2つのデータはそれぞれのCPUのタイプで観測された数日間のデータの中から、 比較的一日を通じての変動が少ないものを選んだ。 日が違えば変動の仕方も変わってくるが、 それぞれのCPUの種類別に日毎のデータを比較すれば、 概ねここで取り上げたデータと同様の変動となっている。
グラフから明らかなように、性能の高いCPUの方が時刻の変動が少なく安定している。 特にPentiumIII 550MHzの方は変動が概ね±1マイクロ秒の範囲内に収まっており、 これはTS-820自体のPPS信号の精度が±1マイクロ秒程度であることを考慮すると、 サーバ本体側での変動要因はそれを下回っておりGPS自体の精度が時刻精度を決定づけていると考えられる。 従ってTS-820と組み合わせてNTPサーバ専用マシンとして運用するのであれば、 これ以上高性能なCPUを用いても無駄である。 一方で性能の低い方のPentium 133MHzマシンでは、明らかにGPS以外の誤差が生じている。 ntpdのドキュメントによれば性能の低いCPUでは、 シリアルポートからのPPS信号の割り込みを処理する時間が余計にかかり、 また処理時間自体の変動幅も大きくなるために時刻の変動が大きくなる。 しかし今回測定された時刻変動を見れば、 Pentium 133MHz程度でもStratum-1サーバとして十分な精度を確保できることもわかった。 それはStratum-1サーバと通信する際のネットワーク上での通信時間の揺らぎの方が、 数マイクロ秒程度の時刻変動よりもずっと大きいためである。
次にCPUはPentium 133MHzとしてOSだけLinuxからFreeBSDに変えた場合の精度の比較を行った。 まず図2に示すのがLinuxでのNTPサーバの時刻の変動の様子で、 前出の図1と同様にして測定した連続した一週間分のデータを重ね合わせたものである。 縦軸の標準偏差は1.24マイクロ秒であった。
図2: Linux 2.4.17 (+PPSkit 2.0.1) Pentium 133MHz 一週間の時刻変動
次に図3は同一ハードウェア上でFreeBSDで運用した場合の一週間の時刻変動の様子で、 こちらもLinuxの場合とほとんどかわらず標準偏差は1.29マイクロ秒であった。
図3: FreeBSD 4.5 Pentium 133MHz 一週間の時刻変動
この結果からLinuxとFreeBSDによる精度の違いはみられず、 どちらを使用しても安定したNTP Stratum-1サーバが構築できると考える。
GPSによるNTP Stratum-1サーバを運用し、 数日間にわたり時刻の変動を観察する中で気づいたことは、 日毎に時刻の変動の仕方が異なっているということである。 日毎に異なる条件として考えられるのは一日を通じての唯一温度変化だけである。 図4はPentiumIII 550MHzのNTPサーバを数日間運用した中で、 温度変化が比較的大きかった一日(緑色)と小さかった一日(赤色)における時刻の変動を表している。
図4: 温度変化による精度変化
パソコンの内部時計の進み具合いは温度の変化に大きく影響されることは良く知られている。 一日を通じて温度変化の大きい場所に設置されている場合には、 温度管理された場所に設置された場合に比べてNTPサーバとしての精度はどうしても落ちてしまう。 精度を確保するためには温度管理は重要である。 今回構築したNTPサーバはアンテナ設置場所の関係でパイプシャフト内に設置しなければならなかった。 このためどうしても一日を通じての温度変化の影響を受けてしまう。 とは言え温度変化による時刻変動の割合は高々3マイクロ秒程度であるので、 これもネットワーク通信による揺らぎを考えればほとんど無視できる程度である。 またCPUをPentium 133MHzにした場合には温度変化以外の要因が相対的に大きくなり、 図2や図3からも明らかなように一日を通じての温度変化による時刻変動はあまり見られなくなる。
以上述べてきた要因の他にNTPサーバの精度に影響を与えると考えらているものを列挙する。
以上PC-UNIXとGPSを用いた安価なNTP Stratum-1サーバの構築と、 その精度評価について述べた。 この様に古くなったPCと安価なGPSを組み合わせることで、 誰でも簡単に高精度のStratum-1サーバを構築できる。 この報告が他大学でのNTPサーバ構築の参考になれば幸である。