English / Japanese
EOS4.12.0 から eAPI が使えるようになった。
eAPI は JSONRPC over HTTP/HTTPS によって EOS の CLI コマンドを外部から投入し、その結果を JSON 形式で得ることを可能にする。
端的に結果を示すと、eAPI では秒間 180 コマンド程度が処理可能である。
show version コマンドは 5.5ms 程度で処理された。
ここでは eAPI のレスポンスタイムを計測したので事例として紹介する。
注意: この実験は安田が自分の手元の環境でテストしただけで、一般的な結果(特に性能数値)とは異なる可能性があることに注意されたし。
Yutaka Yasuda (Arista Square)
24/June/2013 : 最初のリリース。モデル 7048T・EOS 4.12.1 で実験。
1. はじめに
1.1 eAPI 概要
1.2 eAPI の起動
2. 実験:レスポンスタイムの計測
2.1 評価対象・方法
2.2 機器構成・動作環境
2.3 事前確認事項
2.4 処理時間計測結果・考察
3. 結論
eAPI は JSONRPC over HTTP/HTTPS によって EOS の CLI コマンドを外部から投入し、その結果を JSON 形式で得ることを可能にするアプリケーションインタフェイスである。 コマンドは JSONRPC 2.0 に基づいてフォーマットし、それを HTTP あるいは HTTPS によって Arista スイッチ自身に与える。 レスポンスもまた JSON フォーマットで得られるため、必要な情報をパース、あるいはスクレイピングする必要がない。
eAPI は Arista を SDN (Software Defined Network) の一部とするために重要な機能であるが、OpenFlow との最大の違いは eAPI はフォワーディングテーブル(OpenFlow で言うフローエントリ)の設定にとどまらず、Arista の全機能にアクセスできる点にある。 ポートの設定からソフトのインストールまで、必要なら EOS 自身のバージョンアップすら eAPI 経由でリモートからコントロール可能(なはず)である。(何かしらの安全策としての機能制限があるかもしれないが)
eAPI は JSONRPC over HTTP/HTTPS でサービスされるため、eAPI サービスを起動すると Arista 自身が Web サーバとなる。 動作確認のために eAPI サービス(実体は HTTP あるいは HTTPS サーバ)を起動した状態でスイッチ自身の IP アドレスにブラウザでアクセスすると、図1. に示す Command API Explorer の画面になるだろう。 ただしアクセスに際しては Basic 認証が要求され、EOS 登録ユーザ名とパスワードを指定する必要がある。
この Command API Explorer を用いて簡単に eAPI の呼び出し形式、レスポンスのフォーマットを知ることが出来る。 実際に eAPI を利用するアプリケーションを書くときにとても便利なツールとなるだろう。
なお図 1. の画面上の方にある Overview, Command Documentation のリンクが eAPI のマニュアルとなっている。 次に図 2. に Command API Explorer で show version コマンドを実行した場合の結果を示す。
結果が JSON 形式で得られていることがわかる。 eAPI を利用するプログラマはこのレスポンスを JSON パーサに掛け、目的とするキー(例えば "version" )を指定して必要な値(例えば "4.12.1" )を得ることになる。
https://eos.aristanetworks.com/2013/03/eapi-learning-the-basics/ を見ながら起動する。 作業は非常に簡単で、以下のようにするだけである。
localhost#config localhost(config)#management api http-commands localhost(config-mgmt-api-http-cmds)#protocol ? << 何があるんだろうと思うと HTTP/HTTPS だ http Configure HTTP server options https Configure HTTPS server options localhost(config-mgmt-api-http-cmds)#protocol http % Cannot enable HTTP and HTTPS simultaneously <<< 同時にはだめ(つまり HTTPS が動いていた) localhost(config-mgmt-api-http-cmds)#no protocol https <<< HTTPS を落として localhost(config-mgmt-api-http-cmds)#protocol http <<< HTTP を選択 localhost(config-mgmt-api-http-cmds)#no shutdown <<< サービス開始(起動) localhost(config-mgmt-api-http-cmds)#
この状態で eAPI が動いているはずである。 次回起動でも eAPI を有効とする場合はいまの状態をメモリに書いておくと良い。
localhost#write memory localhost#
EOS CLI からは以下のようにして起動を確認できる。
localhost(config-mgmt-api-http-cmds)#show management api http-commands Enabled: Yes HTTPS server: shutdown, set to use port 443 HTTP server: running, set to use port 80 VRF: default Hits: 1 Last hit: 139 seconds ago Bytes in: 0 Bytes out: 0 Requests: 0 Commands: 0 Duration: 0.000 seconds URLs -------------------------------------- Vlan12 : http://192.168.11.111:80 <<< アクセスできる URL を出してくれている Management1 : http://xxx.xxx.xxx.xxx:80 <<< これも localhost(config-mgmt-api-http-cmds)#exit localhost(config)#
上に現れていたアドレス、たとえば http://192.168.11.111:80 などにアクセスすると、認証画面が出る。
EOS 登録ユーザで login すれば、図1. に示した Command API Explorer が表示されるだろう。 eAPI を通して管理者権限が必要になる場合は、そのような権限が与えられているユーザで login すること。
今回のセットアップは一つの事例に過ぎないことに注意されたい。 動作環境は特定のものしか試しておらず、全ての Arista スイッチで同じ結果が出るとも限らない。
単純に eAPI のレスポンスタイム、すなわち通信が始まってからメッセージを得られるところまでの所要時間を調べる。 コマンドは一つの JSONRPC リクエストに複数詰め込むことができるため、その場合の遅延の伸び具合いも見る。 指標としては負荷が軽そうな show version コマンドを用いる。 これを 1 回の JSONRPC リクエストに一つだけ詰める場合、複数回繰り返して詰めた場合の変化について調べる。 具体的には以下のような JSONRPC リクエストを Arista に投げることになる。
単一のコマンド {"id":0,"method":"runCmds","params":{"cmds":["show version"],"format":"json","version":1},"jsonrpc":"2.0"} 複数コマンド {"id":0,"method":"runCmds","params":{"cmds":["show version","show version","show version"....],"format":"json","version":1},"jsonrpc":"2.0"}
今回の実験環境を図4に示す。 利用した Switch は 7048T である。EOS は version 4.12.1。 デバッグのしやすさから HTTPS ではなく HTTP を用いているが、実運用では HTTPS の利用が多いだろう。 アクセスするクライアントは MacBook Air (2012 model, Sandy Bridge) に USB-Ethernet アダプタをつけて使っている。 サーバまでの途中経路はほぼ Gigabit Ethernet であるが、この USB-Ethernet が100Mbps で経路中の最低速部分となっている。 (しかし処理時間の計測はせいぜいミリ秒単位であり、この部分に起因する遅延が実験に対して大きな影響を与えることはない)
ベンチマークに用いたクライアント側処理系は Java であり、JSON-RPC 2.0 ライブラリを利用している。
ソフトウェア環境の詳細については別に記す。[ Java による eAPI のベンチマーク ]
計測を行う前に幾つかの事項について調べた。 遅延として観測される数値に、それらが大きな影響を与えていないことを確認しなければならない。
計測には Sytem.nanoTime() を利用している [ プログラム詳細 ] 。 そこで Javaパフォーマンス計測 そんなタイマーで大丈夫か? を参考に、Sytem.nanoTime() による時間計測の精度について確認した。 この blog にあったサンプルコードを走らせたところ、結果として得られた数字は 0 か 1000 ( 1usec )だけだった。 元記事ではバラついて出たというが、そういう状況では無い。 テストに用いた MacBook Air (Sandy Bridge) は MacOS X Lion、javac のバージョンは 1.6.0_45 であり、恐らく OS の違いではないか。 1000 回ループした後で (t1[999] - t1[0]) を出力させると 97000 と出た。 一回あたり 97ns で呼び出せている状態で、System.nanoTime() の分解能が 1000ns しかない、という事だと解釈する。 いずれにしても msec 精度の測定しか必要ない今回には充分と判断した。
クライアント・サーバ(Arista)間の ping の反応は 0.5ms 前後だった。 ネットワークおよびパケット処理に起因する遅延はこの程度と考えれば良いか。
$ ping 192.168.11.111 PING 192.168.11.111 (192.168.11.111): 56 data bytes 64 bytes from 192.168.11.111: icmp_seq=0 ttl=64 time=0.446 ms 64 bytes from 192.168.11.111: icmp_seq=1 ttl=64 time=0.571 ms ....
今回は JSONRPC 2.0 ライブラリ と Authenticator.setDefault() による Basic 認証処理を組み合わせてテストした。 これで Basic 認証は正しく働いているが、内部的には一度 Authorization: ヘッダなしで POST リクエストを送り、401 authorization fail で断られ、その後自動的に同じ内容の POST request を Authorization: ヘッダつきで送って成功させる、といった処理が行われている。 (この動作自体は Web ではごく自然なものであり、それほどおかしな挙動ではない。) つまり Benchmark プログラム[ プログラム詳細 ] で用意したタイマー処理( long t1 = System.nanoTime(); )は t1 から t2 がセットされるまでの間に TCP コネクションも二度作り、HTTP POST リクエストも二度行っている。
しかしこの二往復処理のために大きな遅延が生じていたのでは本当の eAPI のレスポンス時間が分からなくなるため、そうでないことを確認した。 具体的にはパケットモニタで二つの POST パケットとそれぞれのレスポンス(一つは 401 fail, もう一つは 200 OK)がいつ頃出てくるかをチェックした。 以下に実際にキャプチャしたあるセッションの重要パケットのタイムスタンプ、それらのパケット間のインターバルタイム(ミリ秒)を示す。21.102 はキャプチャ開始から 21.102 秒経ったことを意味する。
time int packet description ======= ===== ==================================== 21.102 ( 0) : 最初の Authorization: ヘッダがない POST リクエスト送信 21.104 ( 2) : 401 authorization fail のレスポンス 21.108 ( 4) : 二度目の Authorization: ヘッダつき POST 送信 21.292 (184) : 200 OK のレスポンス ここで 180ms 程度を要している
これから分かるように Authorization fail の返答は僅か 2ms 程度で返っており、二度目の POST 送信の開始も数ミリ秒後には行われている。 そして実際に eAPI がコマンド処理を開始してから返事が出るまでに 180ms 程度を要しており、結果のほぼ全ては純粋に Arista 内で eAPI を通してコマンド処理するために必要な時間と考えて良いことがわかる。
図 5. に show version コマンドを JSONRPC over HTTP で実行させた場合の処理遅延について示す。 グラフは show version コマンドを 1 つだけ、あるいは 10, 20, 30, 40 回連続して詰めた場合についてその処理時間を打点した。 横軸が詰め込んだ個数、縦軸は処理時間(ミリ秒)である。 全く同じ横軸位置に打点すると重なりすぎて事象の密度がわからなくなるため、横軸については打点位置をランダムに散らしてある。
全体としてとてもリニアに伸びている。 グラフ中の各試行のうち、一つだけ飛び抜けて高い処理時間を示す打点があるが、これらはすべて初回(最後のアクセスからしばらく経ってから)アクセスのものである。これについては後述する。 いまは初回を除くデータについてフィットした赤い破線だけを見るとして、二つのことがわかる。
一つは、全ての試行に共通な、50ms 程度の処理時間であり、これは EOS のコマンドプロセッサが起動するのにかかる時間と推定される。 もう一つは show version コマンドの個数を増やすほど伸びていく処理時間であり、これは純粋に show version の処理のために必要な時間の累積と思われる。
事前の確認事項とこの結果からざっくりと分析・計算すると、
これらのことから show version コマンドは一つあたり 5.5ms (220ms / 40) で処理されたと考えられる。
グラフ中の各試行のうち、一つだけ飛び抜けて高い処理時間を示す打点があるが、これらはすべて初回(最後のアクセスからしばらく経ってからの)アクセスである。 つまり初回の eAPI アクセスは必ず遅れる傾向がある。 恐らくこれは eAPI が利用する EOS の command processor がしばらくすると sleep あるいは優先順位の低い状態になり、そこから再準備するためにこれだけの遅延が必要になると考えられる。
この最準備に時間が掛かる原因が Arista が利用している Web サーバにあるのか、command processor にあるのかを調べるために、(最後のアクセスから随分時間をあけて)TCP 接続、GET リクエスト、受信完了までの時間を計測する自作プログラム geturl を用いてアクセスした。 その結果を以下に示す。 (このアクセスはすべて authorization fail となる。もし Arista が用いている Web サーバそのものが遅延の原因であるとすれば、このリクエストのレスポンスもまた初回は遅れるはずである。)
初回(しばらく空けてから)の実行 $ geturl -tv http://192.168.11.111/ done : 2013/06/21-11:26:01.82 : CONNECT 0.549 msec : GET 3.448 msec : FILE 0.470 KB : Avg. 1090487 bps $ それ以降繰り返しての実行(一秒間隔程度で実行) done : 2013/06/21-11:26:03.61 : CONNECT 0.412 msec : GET 3.018 msec : FILE 0.470 KB : Avg. 1245858 bps done : 2013/06/21-11:26:05.71 : CONNECT 0.402 msec : GET 3.208 msec : FILE 0.470 KB : Avg. 1172070 bps done : 2013/06/21-11:26:07.59 : CONNECT 0.365 msec : GET 3.098 msec : FILE 0.470 KB : Avg. 1213686 bps done : 2013/06/21-11:26:09.51 : CONNECT 0.417 msec : GET 3.171 msec : FILE 0.470 KB : Avg. 1185746 bps done : 2013/06/21-11:26:11.45 : CONNECT 0.362 msec : GET 3.092 msec : FILE 0.470 KB : Avg. 1216042 bps done : 2013/06/21-11:26:13.34 : CONNECT 0.351 msec : GET 3.083 msec : FILE 0.470 KB : Avg. 1219591 bps done : 2013/06/21-11:26:15.24 : CONNECT 0.394 msec : GET 2.600 msec : FILE 0.470 KB : Avg. 1446154 bps ....
何度か試みたが結果は安定して初回を含めて 3ms 程度の遅延となった。 上の例では初回がそれでも 0.5ms 程度遅いとも思えるが、しかしグラフに現れるような 120ms 程度の遅延とは関係が無い。 つまり EOS のコマンド処理の機能が立ち上がるのに 120ms 程度掛かっているように見える。 プライオリティが普段下がっているのだろうか?
初回アクセスの大きな遅延を解決する一つの方法としては、毎回 JSONRPC を新しく起こさずにセッションを Keep Alive しておくことが考えられる。 実際にテストで用いた JSONRPC 2.0 のライブラリは Keep Alive オプションを付ける。 以下に実際に投入された POST リクエストの HTTP ヘッダを示す。
POST /command-api HTTP/1.1 Accept-Charset: UTF-8 Content-Type: application/json User-Agent: C/YasuTest Host: 192.168.11.111:80 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Content-Length: 118 Authorization: Basic WjdWu7DwjD2xhw9Di
しかし困ったことに eAPI サーバは現状では Keep Alive を断っており、レスポンスを返すごとにセッションを切断してしまう。 以下に先の POST リクエストに対する HTTP レスポンスのヘッダを示す。
HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7 Date: Fri, 21 Jun 2013 09:58:51 GMT Cache-control: no-store Cache-control: no-cache Cache-control: must-revalidate Cache-control: max-age=0 Cache-control: pre-check=0 Cache-control: post-check=0 Pragma: no-cache Set-Cookie: COMMAND_API_SESSION=0; Path=/ Content-type: application/json Content-length: 542 Connection: close
つまりこれ以上効率良くコマンドを処理させる方法は(現状では)無い。
実験の結果を簡単にまとめる。
従前は ssh login をしてコマンド・スクレイピングをするなり、EOS 上の shell script などから Cli を呼び出して与えていたことに較べると eAPI は十倍以上高速(EOS の CLI シェルは起動に一秒程度掛かる)である。 つまり eAPI は Arista をプログラマブルにするためには充分実用的で利用価値があるものと言える。
ただし上記 2. および 3. のことから、できるだけ複数のコマンドを一つの JSONRPC リクエストに詰め込んで処理させる方が良いと言える。
今後は初回アクセスの遅さと、Keep Alive への対応が行われるとより高速なレスポンスが期待でき、実用性が更に上がると思われる。
なお OpenFlow がネットワーク越しにミリ秒のオーダーでフローエントリを設定可能なことと比較して、最低でも 50ms 程度必要とする eAPI が極端に遅いと短絡的に結論することには意味が無い。 OpenFlow はフォワーディングテーブル(OpenFlow で言うフローエントリ)の設定に特化されているが、eAPI は Arista の全機能にアクセスできる。つまりポートの設定からソフトのインストールまで、必要なら EOS 自身のバージョンアップすら eAPI 経由でリモートからコントロール可能(なはず:何かしらの安全策としての機能制限があるかもしれないが)である。 経路設定だけが SDN が可能にしてくれることの全てではない。