投稿日

SORACOM API こぼれ話

ソラコム開発チームの小熊(おぐま)です。

この記事は SORACOM リリース記念リレーブログ の 10月9日分です。

そうそうたる顔ぶれの皆様のあとで、しかもソラコムからのトップバッターという二重の重圧の中、記事を書かせていただきます。

フルスケールエンジニア

さて、ソラコムのリリース直前、弊社 CEO 玉川を取材していただいた エンジニア Type 様の記事 が公開されました。
この記事の中で「フルスケールエンジニア」という言葉が使われていて、そのキーワードが一部で話題となっていたかと思います。

実はその「フルスケールエンジニア」という言葉を考えたのは、何を隠そう私です。

「フルスケール」は、ある時パッとひらめいた言葉ではありますが、自分の中ではこれから先の理想のエンジニアを表現する言葉としてけっこうしっくりきていて、それはいったいどんな理想像なのかということについて、ちょっとこの場を借りてご説明させていただけたらなと思います。


これまで、ハードウェアや組込みソフトウェアの世界とクラウドや Web のような世界との間には、活発な交流があったとは言いづらく、エンジニアのスキルもそれぞれの分野で全く異なるものだったのではないかと思います。

ハードウェアや組込みソフトウェアの世界は、1ビット単位のデータ、1本1本の信号線、ナノ秒単位の電圧の変化、ナノメートルオーダーの半導体、というようなものを取り扱うような世界です。
一方、クラウドというのは TB(テラバイト)もしかしたら PB(ペタバイト)というスケールのデータ、数万・数千万というクライアントからのコネクション、何年間にもわたってデータを蓄積しつづけ、日本とアメリカといったような1万キロも離れたような場所との地理的な分散を意識する、そういった規模感の世界です。

IoT が「難しい」と言われるのは、そのような何万倍も何億倍も異なるスケールの両方を、同時に取り扱う必要があるのが一因ではないかと個人的には考えています。
それだけではありません。その両極端の間には、スマホ、PC、エンタープライズ、Web などさまざまなスケールの世界があって、どれも IoT と無関係とは言えません。

このようにさまざまな「スケール」に対応しているエンジニア=「フルスケールエンジニア」こそが IoT の世界では必要になってくるのではないかと思います。

私たちソラコムのプラットフォームは IoT デバイスとクラウドをつなぐという重要な役割を担っているという自負があるのですが、私たちソラコムのエンジニア自身がまずもって IoT とクラウド、そしてその間に存在するさまざまなスケールの世界に精通している「フルスケールエンジニア」である必要があると考えています。

フルスケールエンジニアは「理想のエンジニア像」と上で書いたように、私自身はまだまだ精進が必要ではありますが、いつか胸を張って「フルスケールエンジニアです(キリッ」と言えるように、これからもいろいろな分野に挑戦していきたいなと思っています。

SORACOM API Gateway

さて、前置きが長くなりましたがここからが私の記事の本題です。

SORACOM のプラットフォームは API 経由でコントロールしていただくことができるのが大きな特徴の一つで、すでに SORACOM リレーブログやその他のブログ記事等でも API (CLI) 経由でいろいろ試してみていただいております。

SORACOM ユーザーコンソールも内部的には SORACOM API を呼び出す “シングルページ Web アプリケーション“ (SPA) となっておりますし、CLI(soracom コマンド)も API のラッパーになっています。すなわち、コンソールや CLI でできることは基本的にすべて API でできるということになります。(一部非公開の API もあります)

具体的な API の使い方については、開発者サイトにもドキュメントがありますし、さまざまなブログ等の記事で取り上げていただいているので、ここでは詳しくは触れません。

その代わりに、ちょっとしたエピソードをご紹介したいと思います。

SORACOM の API は、https://api.soracom.io/v1/ という URL をベースとして呼び出していただいておりますが、このホスト名を解決すると ELB (Elastic Load Balancer) の CNAME となっていることがわかると思います。

この ELB が入口となって AWS 上に構築されたゲートウェイを経由してバックエンドのサーバー群にリクエストが転送されます。

SORACOM のバックエンドはいわゆるマイクロサービス的な作りになっており、複数のサーバ上に散在している API を、ゲートウェイを通すことで外から見た時に一箇所にアクセスしているように見せています。

他にも、ゲートウェイで簡易的な認証(有効な API キーが付いているかどうかのチェック)、アクセスのスロットリング(不当に多くのアクセスを行っていないかのチェック)などを行って、有効なリクエストのみをバックエンドに展開するようにしています。

このゲートウェイなのですが、当初から現在の形のように SORACOM プラットフォームの内部に存在していたわけではなく、紆余曲折を経た上で現在の構成になっています。

今日は、ソラコム開発秘話のような感じでそのことについて書いてみたいと思います。

Apigee 時代

SORACOM の開発が始まった初期の頃、私たちは Apigee という外部サービスを利用して API ゲートウェイを構築しておりました。

Apigee はとても便利なサービスで、Web コンソール画面から API の定義を作成したり、転送先の設定を行ったり、API のデバッグを行ったり、JavaScript で書いたコードを Apigee 上で実行したりといったことができました。

私たちはさまざまな API ゲートウェイサービスを比較し、この Apigee が最も使いやすくて最も私たちのニーズに合っていると判断し、導入を決めました。

数ヶ月の間は順調に使えていたのですが、ある日 Apigee のメンテナンスが行われたタイミングで、私たちの API がまったく呼び出せなくなるという事態が発生しました。

Apigee のサポートに問い合わせたところ、私たちが依存していた一部機能に問題が発生し、現在復旧作業中であるとの連絡をもらいました。一応の回避策(依存していた機能を迂回する)も教えてもらいましたが、それでは Apigee を使っている理由がなくなってしまうくらい重要な機能でした。

API を呼び出すことができないとなると、SORACOM プラットフォームの大きな特徴が失われてしまいますし、なにより SORACOM をご利用いただくお客様に多大なご迷惑をお掛けすることになります。

SORACOM にとって API はプラットフォームの生命線であり、決してオマケ機能などではなく、これなしには SORACOM 自体が成り立たないような重要な存在なのだということを改めて認識しました。

そしてこのことをきっかけに、API ゲートウェイは外部で運用されているサービスを利用するのではなく、私たちのプラットフォームの内部で動かした方が良いのではないかという議論が社内で起こりました。

Apigee のオンプレミスバージョンを AWS 上で動かすという選択肢もあったのですが、私たちのような小さな企業で small start するには少しお値段が、、、ということで、私たちは SORACOM プラットフォーム内(すなわち AWS 上)で動かせそうないろいろな代替のサービスを検討しました。

まず目に止まったのは、ちょうどそのときタイミングよく発表された AWS のサービス、Amazon API Gateway でした。

Amazon API Gateway の検討

そんなわけで、喜び勇んで Amazon API Gateway を試してみたのですが、使ってみるうちに以下のようなことがわかりました。

  • API の作成は Web コンソールから行えるが、Apigee ほど簡単ではない
    • Apigee では、API の Path のパターンに応じて一括して「この Path の配下へのアクセスはすべてこのバックエンドサーバに振り向ける」というような設定ができましたので、Apigee 上で作成する必要のあった定義はせいぜい 5〜6 個程度だったのですが、Amazon API Gateway を使うと API の Path の数だけ(非公開のものを含めると 60 近く)を一つ一つ定義していく必要があります。ほとんど内容が同じものをひたすら作らないといけないので、一つ一つは単純でもメンテナンスなどを考えるとせめて自動化ができないと辛そうです。発表当初は Amazon API Gateway を制御するための API がとくにアナウンスされていないようだったのと、AWS 公式の SDK も、どの言語のものも Amazon API Gateway にはまだ対応していなさそうだったので自動化も難しそうでした。
  • リクエストヘッダーの中身をチェックしたり、バックエンドにリクエストを送る前に独自のヘッダーを付与するというような単純なことが簡単にはできなさそう
    • Apigee では、ヘッダーを操作する処理を XML で定義しないといけないという辛さはありましたが記述量自体は大したことがなく、比較的直感的にヘッダーを操作できたのですが、Amazon API Gateway ではテンプレートを定義してヘッダーの中身をボディの JSON に組み込んでそれを処理したり、逆にボディに書かれている値をヘッダーに入れたり(これもテンプレートを定義する必要がある)、しかもこれを API ごとにやらないといけなかったのでテンプレートの記述量が多くなってしまいそうだったのと、もしかしたらバックエンドのサーバ側にも変更が必要になりそうだったのと、あとは上と同様に自動化できなさそうなのがとても辛そうでした。

これらの点に関しては、私が単に調べきれなくて実は簡単にできることを見逃していて難しく考えすぎていただけかもしれませんし、現在はもうできるようになったりしているのかもしれませんが、当時の私の結論としては Apigee から Amazon API Gateway への移行は難しいという結論を下しました。

Amazon API Gateway 自体はとても良いサービスで、SORACOM Beam との相性なども抜群なのでぜひみなさん使ってみてください。たまたま私たちのやろうとしていたこととはちょっと方向性が違ったというだけのことだと思います。

StrongLoop の検討

次に、弊社 CTO 安川が「これいいかも」と言って見つけてきたのが StrongLoop でした。

StrongLoop に関しては、SORACOM のインターン 1 号、shun が熱心に調べてくれました。

StrongLoop API Gateway は当時まだベータ版でしたが、shun の調査により私たちの必要としている機能は一通り揃っていそうだということがわかりました。

StrongLoop は Node.js で実装されており、AWS 上で動作させることもできましたのでこれはイケる!!と思って喜び勇んでデプロイしかけたのですが、StrongLoop のインスタンスを単体で動作させるのはうまく行ったのですが、複数インスタンスでクラスタリングしようとするとどうにもうまく動かすことができなかったのです。shun も調査を続けてくれましたし、StrongLoop に問い合わせたりもしたのですが数日かかってもなかなかうまく行かず、、、

この問題がもし解決できても、実際にサービスを開始したあとにもしも何かエラーが起こったりしてうまく動かなくなってしまったときに、同じように何日も原因がわからないというようなことになったら、これはやっぱりまずいんじゃないか、、、という空気が社内に流れ始めました。

もちろんサービスイン前には有償プランに入って正式なサポートを StrongLoop から受けられる見込みがあるとはいえ、これは大きな不安要素です。

外部サービスを私たちのプラットフォーム上で動かすだけではダメで、コアな機能はそのサービス自体を自分たちで作らないといけないという結論に達し、StrongLoop とは契約寸前まで行っていたのですがお断りの連絡を入れました。

すると、そう決断した翌日くらいに「StrongLoop が IBM に買収された」というニュースが。天下の IBM 様が買収するようなサービスなので、StrongLoop は本当に良いサービスだと思いますのでみなさんはぜひ利用を検討してみてください。

そんなこともあろうかと・・・

そんなこともあろうかと、というわけではないのですが、ここで白羽の矢が立ったのは、自社内で管理コンソール(外部からアクセスできない、SORACOM の中の人しか見れない Web 画面)用の API ゲートウェイとして Go 言語でサクッと私が作ったプログラムでした。社内では Go Proxy とか Ogu Proxy とか呼ばれています。

この Ogu Proxy をベースに、少し足りない機能を足せば実は外部サービスを利用しなくても十分なんじゃないか?ということになり、急遽体裁を整えて運用に載せることになりました。

初期の頃は API ゲートウェイという存在そのものがよくわかってなくて自前で作るなんてまったく想像もできなかったのですが、実際に数ヶ月 Apigee などを使ってみて自分たちに本当に必要な機能が何なのかということが見えてきていた事もあって、自信を持って Ogu Proxy で十分と思えるようになっていました。

Ogu Proxy – Windows インスタンス時代

その Ogu Proxy ですが、当初は本当に社内用ということで、専用の EC2 インスタンスを割り当てるのももったいないという感じで、EC2 上で動いていた(けどめったに使われていなかった)Windows のインスタンスを間借りして動いているような状態でした。

それじゃさすがにマズいということで、いったん Linux のインスタンスへと移行しました。

移行はまったく難しくなく、というかソースコードには全く手を入れず、コンパイル時のターゲットオプションの変更だけで Linux で動作しました。Go で書いておいて本当によかった。

Ogu Proxy – Elastic Beanstalk 対応

とはいえ、素のままの EC2 インスタンスの Linux 上で動いていると、負荷が高まった時にどうするか、とか新しいバージョンをデプロイするときにどうするかといったような管理上の問題が出てきます。

そこで Ogu Proxy を Elastic Beanstalk (以下 EB) で動作させるようにしました。

当時は EB の Go サポートは Docker ベースだったので、EB の Go 環境(実態は Docker コンテナ)を作りました。
環境を 2 つ作って Blue-Green Deploy のようなこともできるようになりました。

Ogu Proxy – ELB + AS 版

しばらくは EB で動作させていましたが、デプロイにやけに時間がかかっていたのが難点でした。(Docker コンテナを毎回ビルドしてたからと思われます。現在の EB は Go を直接サポートしているので改善している可能性があります)

そんなとき、クラスメソッドさんの「Auto Scaling環境でのBlue-Green Deploymentの切替がAWS ELBでできるようになりました。」 という記事に触発され、さっそく Ogu Proxy もこの方法で Blue-Green デプロイができるようにしました。

こちらの方式をさらに推し進め、EC2 インスタンスの起動時のスクリプトで Ogu Proxy のバイナリと設定ファイルを S3 バケットから持ってきて実行するようにしました。すると、Ogu Proxy のデプロイはバイナリと設定ファイルを S3 のバケットに入れるだけ、という運用にできましたのでとても楽ですし速いです。

EC2 インスタンスは素の Amazon Linux のままでよく、追加で何かインストールする必要すらないです。

現時点で動作している Ogu Proxy はそんな構成になっています。

ちなみに Ogu Proxy は Go で書いたので非常に軽量です。

たとえばメモリのフットプリントがアイドル時で 8MB くらい、現時点までのピークでも 16MB くらいととてもコンパクトです。(/proc/${pid}/status で VmRSS などを参照しました)

簡単な負荷かけテストをしても CPU 使用率は 1% 程度までしか上がりません。(ほとんどネットワークの I/O 待ちになるためと思われます)

今後 SORACOM のユーザー数が増えてきてアクセス数が増えてもしばらくはスケールアップ・スケールアウトは必要ないかもしれません。

Go のエコシステム(標準ライブラリや Github 等で公開されているプロジェクト)のおかげで、Ogu Proxy のソースコードは空行・コメント行等含めても 1200 行程度と非常にコンパクトに収まっています。

まとめ

Go 言語最高