Amazon Time Sync Serviceがマイクロ秒単位で時刻同期できるPTPをサポートしたのでEC2で試してみた

2023.11.30

こんにちは。CX事業本部のakkyです。

2週間ほど前となりますが、Amazon Time Sync ServiceがPTPをサポートしました。

この時には見落としてしまったのですが、今回のre:Inventで発表されたAurora Limitless Databaseでは、分散データベースを実現するために精密な時刻同期を必要としており、このために新しいAmazon Time Sync Serviceが使われているという発表がありました。

今回は、このPTP時刻同期をEC2インスタンスで試してみましたのでご紹介します。

Amazon Time Sync Serviceとは?

無料で使えるフルマネージドな時刻同期サービスで、いままではNTPのみがサポートされていました。EC2を使っている方はほぼ間違いなく利用しているはずです。

そんなの設定してないよ?という疑問がわくかもしれませんが、推奨AMIを使い、なおかつ設定を変更していない場合、ntpクライアントで169.254.169.123というサーバにアクセスしていることが分かります。

また、time.aws.comというパブリックNTPサーバも公開されているので、通常のPCからインターネット経由でも使うことができます。

PTPとは?

Precision Time Protocol(PTP)はマイクロ秒精度の時刻同期が可能になるプロトコルです。NTPではミリ秒精度です。

NTPは、やりとりされるパケットでは233ピコ秒の解像度で時刻を表現できるのですが、ネットワークの遅延に対応する仕組みがサーバとクライアントのラウンドトリップタイムの考慮しかないため、ランダムなネットワーク遅延の影響で同期精度はそれほど高くなりません。

一方PTPは専用のスイッチングハブやネットワークカードを使うことで、ネットワークパケットのバッファリング遅延の時間の考慮などが可能になり、より高い同期精度を実現できるようになりました。

PTPの導入にはハードウェアの対応が必要となるため、AWSはNitroのアップグレードによって対応したと考えられます。

参考ページ

EC2でPTPを使ってみた

ここからが本題です。EC2のインスタンスで実際にPTPを時刻ソースとして使ってみました。

ひょっとすると将来的には何も意識せずとも使えるようになるかもしれませんが、現時点では自分で行うべき作業がいくつかあります。

必要な環境

  • R7gインスタンスのみの対応となります
  • ap-northeast-1(東京)リージョンのみの対応となります

検証環境

  • R7g.medium (1vCPU/8GB RAM)
  • Amazon Linux 2023(カーネル6.1.61-85.141.amzn2023.aarch64)
  • ENAドライバ 2.11.0
  • ap-northeast-1リージョン
  • インターネットからデータをダウンロードできるVPCサブネットに配置

注意点

カーネルモジュールを新たなものに差し替えますので、作業を誤ると起動しなくなる可能性があります。十分検証してから導入してください。

準備

PTPはENAドライバの対応が必要です。 公式ドキュメントの手順では、ENAドライバがすでにPTPに対応していることを前提に書かれていますが、現時点では対応していないので自分でビルドして入れ替える必要があります。

公式サイトからリンクされているENAドライバのドキュメント公式ブログを読みつつ作業しました。

まず、デフォルトでPTPが使えないことを確認します。

$ ls /sys/class/ptp
ls: cannot access '/sys/class/ptp': No such file or directory

ENAも非対応です。

$ ethtool -T ens5
Time stamping parameters for ens5:
Capabilities:
        software-transmit
        software-receive
        software-system-clock
PTP Hardware Clock: none
Hardware Transmit Timestamp Modes: none
Hardware Receive Filter Modes: none

PTPモジュールの設定を確認すると、組み込まれていないということがわかります。

$ grep -w '^CONFIG_PTP_1588_CLOCK=[ym]' /boot/config-`uname -r`
CONFIG_PTP_1588_CLOCK=m

では、単にPTPモジュールを読み込めば使えるようになるかというとそうではなく、ENAドライバの対応も必要となります。 そこで、ENAモジュールの設定を見てみると、PTPには対応していないことがわかりました。

対応している場合はparmにphc_enableという項目が出るはずです。ENAドライバのPTP対応には、ビルドの際にENA_PHC_INCLUDE=1という環境変数を設定しておく必要がありますが、この環境変数を設定せずにビルドしているのだと思われます。

$ modinfo ena
filename:       /lib/modules/6.1.61-85.141.amzn2023.aarch64/kernel/drivers/amazon/net/ena/ena.ko
version:        2.10.0g
license:        GPL
description:    Elastic Network Adapter (ENA)
author:         Amazon.com, Inc. or its affiliates

(略)

parm:           debug:Debug level (-1=default,0=none,...,16=all) (int)
parm:           rx_queue_size:Rx queue size. The size should be a power of 2. Depending on instance type, max value can be up to 16K
 (int)
parm:           force_large_llq_header:Increases maximum supported header size in LLQ mode to 224 bytes, while reducing the maximum TX queue size by half.
 (int)
parm:           num_io_queues:Sets number of RX/TX queues to allocate to device. The maximum value depends on the device and number of online CPUs.
 (int)
parm:           enable_bql:Enable BQL.
 (int)
parm:           lpc_size:Each local page cache (lpc) holds N * 1024 pages. This parameter sets N which is rounded up to a multiplier of 2. If zero, the page cache is disabled. Max: 32
 (uint)

なお、Amazon Linux 2023ではPTPモジュール自体は既にインストールされていました。

ENAドライバのビルドとインストール

まずはENAドライバをビルドします。modprobeで読み込む方法も紹介されていますが、今回はDKMSで全部管理することにします。

ビルドに必要なパッケージをインストールしましょう。

sudo dnf update
sudo dnf install kernel-devel-$(uname -r) git dkms

ドキュメントの「Installing Driver with dkms」の部分をほとんどそのまま使います。一点変えるのは、makeするときに環境変数を渡すところです。

git clone https://github.com/amzn/amzn-drivers.git
sudo mv amzn-drivers /usr/src/amzn-drivers-2.11.0

/usr/src/amzn-drivers-2.11.0/dkms.confに以下の内容のファイルを作ります(sudo nanoなどで編集してください)。makeコマンドに環境変数を付けて実行するように変更します。

PACKAGE_NAME="ena"
PACKAGE_VERSION="2.11.0"
CLEAN="make -C kernel/linux/ena clean"
MAKE="ENA_PHC_INCLUDE=1 make -C kernel/linux/ena/ BUILD_KERNEL=${kernelver}"
BUILT_MODULE_NAME[0]="ena"
BUILT_MODULE_LOCATION="kernel/linux/ena"
DEST_MODULE_LOCATION[0]="/updates"
DEST_MODULE_NAME[0]="ena"
REMAKE_INITRD="yes"
AUTOINSTALL="yes"

ビルドしてインストールします。

sudo dkms add -m amzn-drivers -v 2.11.0
sudo dkms build -m amzn-drivers -v 2.11.0
sudo dkms install -m amzn-drivers -v 2.11.0

モジュールの設定

PTPモジュールをシステム起動時に読み込ませるには、/etc/modules-load.d/ptp.confというファイルを作成し、モジュール名のptpを書き込みます。(sudo nano)

ptp

次にenaモジュールの設定を行います。PTPを有効にするにはphc_enable=1というオプションを付ける必要があります。そのため、/etc/modprobe.d/ena.confというファイルを作成し、以下のような内容にします。(sudo nano)

options ena phc_enable=1

ここまで出来たらインスタンスを再起動してください。

動作確認

再びログインするとPTPが使えるようになっているはずです。

まずenaモジュールが切り替わっていることを確認します。phc_enableが増えていますね。

$ modinfo ena
filename:       /lib/modules/6.1.61-85.141.amzn2023.aarch64/extra/ena.ko
version:        2.11.0g
license:        GPL
description:    Elastic Network Adapter (ENA)
author:         Amazon.com, Inc. or its affiliates
srcversion:     4A65CC132E6C115C57322E9
alias:          pci:v00001D0Fd0000EC21sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd0000EC20sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd00001EC2sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd00000EC2sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd00000051sv*sd*bc*sc*i*
depends:        ptp
name:           ena
vermagic:       6.1.61-85.141.amzn2023.aarch64 SMP mod_unload modversions aarch64
parm:           debug:Debug level (-1=default,0=none,...,16=all) (int)
parm:           rx_queue_size:Rx queue size. The size should be a power of 2. Depending on instance type, max value can be up to 16K
 (int)
parm:           force_large_llq_header:Increases maximum supported header size in LLQ mode to 224 bytes, while reducing the maximum TX queue size by half.
 (int)
parm:           num_io_queues:Sets number of RX/TX queues to allocate to device. The maximum value depends on the device and number of online CPUs.
 (int)
parm:           enable_bql:Enable BQL.
 (int)
parm:           lpc_size:Each local page cache (lpc) holds N * 1024 pages. This parameter sets N which is rounded up to a multiplier of 2. If zero, the page cache is disabled. Max: 32
 (uint)
parm:           phc_enable:Enable PHC.
 (uint)

デバイスファイルを確認してみます。

$ ls /sys/class/ptp
ptp0

ありました!ethtoolでも見てみると、デバイス番号0が出ています。

$ ethtool -T ens5
Time stamping parameters for ens5:
Capabilities:
        software-transmit
        software-receive
        software-system-clock
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes: none
Hardware Receive Filter Modes: none

chronyの設定

chronyはNTPクライアントですが、PTPにも対応しています(私も今回初めて知りました)

/etc/chrony.confに以下の内容を追加して、再起動します。

refclock PHC /dev/ptp0 poll 0 delay 0.000010 prefer
sudo systemctl restart chronyd
chronyc sources

すると、PHC0(PTP Hardware Clock)に*が付き、優先使用されるようになりました。

$ chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#* PHC0                          0   0   377     0   +137ns[ +202ns] +/- 5030ns
^- 169.254.169.123               1   4    17     2  -1420ns[-1373ns] +/-   47us
(略)

トラッキング情報を見てみました。

$ chronyc tracking
Reference ID    : 50484330 (PHC0)
Stratum         : 1
Ref time (UTC)  : Thu Nov 30 08:34:18 2023
System time     : 0.000000003 seconds fast of NTP time
Last offset     : -0.000000013 seconds
RMS offset      : 0.000000019 seconds
Frequency       : 4.736 ppm fast
Residual freq   : -0.000 ppm
Skew            : 0.006 ppm
Root delay      : 0.000010000 seconds
Root dispersion : 0.000000887 seconds
Update interval : 1.0 seconds
Leap status     : Normal

以下の出力がNTPの場合です。

$ chronyc tracking
Reference ID    : A9FEA97B (169.254.169.123)
Stratum         : 2
Ref time (UTC)  : Thu Nov 30 08:42:32 2023
System time     : 0.000000277 seconds slow of NTP time
Last offset     : +0.000000094 seconds
RMS offset      : 0.000001779 seconds
Frequency       : 4.749 ppm fast
Residual freq   : +0.000 ppm
Skew            : 0.028 ppm
Root delay      : 0.000076807 seconds
Root dispersion : 0.000033963 seconds
Update interval : 16.2 seconds
Leap status     : Normal

比較すると、わずかながら全体的にPTPのほうが特性が良くなっていることがわかりますね。 Root delayがサーバとの遅延なので重要な点かと思うのですが、PTPは10us決め打ちのようにも見えます。 また、NTPはUpdate intervalが変化するものの、PTPはしばらく置いても1秒のままでした。

testptpコマンド(おまけ)

ソースコードのドキュメントにPHC timestampとして直接タイムスタンプを取るtestptpというコマンドが紹介されています。 これはLinuxカーネルのソースコードに付属されているテスト用コマンドです。

ソースコードを取ってきてビルドすると使えます。

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.64.tar.xz
tar xvf linux-6.1.64.tar.xz linux-6.1.64/tools/testing/selftests
cd linux-6.1.64/tools/testing/selftests/ptp
make

sudoを付けて実行します。

$ sudo ./testptp -d /dev/ptp0 -k 1
system and phc clock time offset request okay
system time: 1701334331.629123687
phc    time: 1701334331.629126222
system time: 1701334331.629127239
system/phc clock time offset is -759 ns
system     clock time delay  is 3552 ns

まとめ

EC2でPTPを使う方法をご紹介しました。カーネルモジュールをビルドし、実際に時刻同期ができることを確認できました。

PTP(IEEE1588)については以前から知っていたのですが、実際に使うとなると専用の機材が必要で個人にはとても無理でした。これがクラウドで使えるとはいい時代です。

ふつうの使い方でここまでの時刻同期精度が必要とされることは少ないと思いますが、これが分散データベースの基盤となっていると思うと興味深いですね。