フレクトのクラウドblog re:newal

http://blog.flect.co.jp/cloud/からさらに引っ越しています

エッジデバイス上での画像認識

みなさんはじめまして。2019年1月にフレクトへ入社した技術開発室の岡田です。 今回は自己紹介も兼ねて、私が担当しているエッジデバイス上での画像認識技術について、概要をご紹介したのちに作成したサンプルをいくつかご紹介したいと思います。

画像認識技術

近年の深層学習の盛り上がりに伴い、多種多様な画像認識技術が生まれてきています。 その中でも次の3つが代表的なものになるかと思います。

  • Image Classification (物体認識)
  • Object Detection (物体検出)
  • Semantic Segmentation

Image Classification とは画像のクラス分類を行う技術です。手書きの数字を認識する問題(MNIST)などが有名ですのでご存じの方は多いかと思います。 たとえば、手書き数字よりもう少し高度な例だと、次の画像を入力すると「ねこ」と判定してくれたりします。 f:id:Wok:20190602220740p:plain

Object Detectionは、画像内に写っている物体の種類と位置を特定する技術です。 先程のねこの画像を入力するとこのような結果を返してくれます。 f:id:Wok:20190602220626p:plain

社内勉強会ではNintendo Switch ゼルダの伝説に登場する「シーカーストーン」の「ウツシエ」と類似の技術(推測)と説明してみましたが、 なかなかピンと来なかったみたいです。残念。一応、参考までにURL貼っておきます。 シーカーストーン ウツシエ - Google 検索

Semantic Segmentationは、さらに細かくピクセル単位でクラス分類を行う技術です。 ふたたび先程のねこの画像を入力として使ってみますと、次のような結果が帰ってきます。見事にねこと背景をピクセル単位に分類して塗り分けてくれていますね。

f:id:Wok:20190602221555p:plain

その他、顔認識やポーズ(姿勢)検出など面白い技術があります。 また、画像認識技術から話が少しそれますが、深層学習により画像からノイズを除去したり、ぼやけた画像を鮮明にする、絵のスタイルを変換するなど、画像の加工や画像の生成を行う技術もあります。

次の例は、社内勉強会ネタとして弊社社長の黒川の写真をスタイル変換にかけてみたものです。あまりうまく行かなかったのですがせっかくなので載せておきます。 f:id:Wok:20190602200654p:plain

エッジデバイス上での実現例

さて、今回は深層学習を用いた画像認識技術の中で代表的なImage Classification, Object Detection, Semantic Segmentationについて、 エッジデバイス上での実現例をご紹介したいと思います。実験的な要素も含んだものとなっていますがご容赦ください。 なお、以下、全てエッジデバイスAndroidスマホ)上で動作させたものとなっています。

Image Classification on Edge Device (Android)

スマホのカメラ画像を分析し、何が写っているかをリアルタイムに判定します。 この動画では、あひるといぬを見分けています。画面上部に判定結果とその確からしさ(1.0が最大)が表示されています。


Andoroidでの画像認識

Object Detection on Edge Device (Android)

スマホのカメラ画像を分析し、何がどこに写っているかをリアルタイムに判定します。 この動画では、あひるといぬがどこに写っているかを判定し、赤枠で囲みます。


AndoroidでObject Detection

Semantic Segmentation Object Detection on Edge Device (Android)

スマホのカメラ画像を分析し、何がどこに写っているかをリアルタイムにピクセル単位で判定します。 この動画では、あひるといぬをピクセル単位で判定して、領域をオーバーレイで表示しています。 ただし、精度も低く処理ももたついていますね。これについてはもっと改良が必要です。


AndroidでSemantic Segmentation

(応用例) Auto Shutter

被写体が特定の条件を満たす写り方をしたときに自動的に撮影する機能です。 この動画の例では、あひるが正面に向いたことを検出して自動的に撮影します。


画像認識技術を活用したオートシャッター機能

最後に

今回は、深層学習による画像認識技術の概要とエッジデバイスでの実現例をご紹介しました。 この記事を通じて、私を含めFlectの活動(の一部)を知っていただけたら幸いです。 次回はもう少し技術的に踏み込んだ内容をご紹介したいと思います。

多量のリクエストを送信するには

エンジニアの佐藤です。こんにちは。今回は、とある技術検証を通じて筆者が経験したドタバタについて書かせていただきたいと思います。

きっかけ

先月だったか、「毎秒X万のHTTPSリクエストを遅延なく処理するための実装要件を教えてほしい。」という要望が筆者に寄せられました。世間のメジャーエンドポイントがどのくらいのアクセスを想定しているのかわかりませんが、X万というのは筆者には未経験のゾーンで、試してみるしかないと思いました。

ちなみにその時点で筆者が過去に経験していた、最も多数のリクエストを処理するエンドポイントは、Heroku(https://www.heroku.com/)で実装しました。難しいことはしていません。Dynoをぐぐぐと増やしていけば、あっさり目標要件を満たしました。今回もHerokuでやったらどうかと答えたのですが、AWS指定とのこと。筆者はロードバランサとECSで検証サイトを作成しました。これを外から多量のリクエストを発信して検証すればいいと思いました。

心配事

とは言え、そんなに素直に行かないだろうなとも思っていました。心配したのは以下の2点です。

  1. そもそも、狙ったリクエスト数を発信できるか。
  2. エンドツーエンドで計測できるか。

一般的にサーバーサイドは、どんな実装であれ、可能な限り高い効率でリクエストを処理することに最適化されています。効率の悪いサーバーなど、誰も欲しがらないからです。しかしクライアント側もそうとは限りません。ブラウザであれアプリであれ、1箇所から多量にリクエストが発信される実用上のシナリオというのは存在しません。(もしそうなら、設計がまちがっているのです。)需要が無いということは、いざやろうとすると、仕様だけ見ていてはわからない落とし穴がある可能性があるということです。

もう一つの「計測できるか」ですが、単純にサーバーサイドでカウントして「毎秒X万回達成!」とやったとしても、それだけでは期待したユーザー体験を検証したことにはなりません。ひょっとしたらその瞬間、個々のリクエストはあり得ないぐらい待たされているかもしれないからです。となるとクライアント側にもそれなりの計測機能を実装して数字を収集しなければなりません。すぐにビッグデータ的スケールになってしまいます。

備え

多数のリクエストを送信するクライアント群をどうやって構成するか、また、個々のリクエストが要求を満たすことをどうやって計測するか。筆者のアイディアは以下のようなものでした。

  1. 非同期的にリクエストする。
  2. 時間的に分散させる。
  3. 計測結果を一定時間メモリにプールし、まとめてレポートする。

1. 非同期的にリクエストする

今回はHTTPSリクエストでしたので、リクエストを送信し、レスポンスを検証して完了です。つまり受信待機があるわけです。受信待機があるということは、直列的にリクエスト処理をつなげては目標を達成することが難しいということでしょう。仮にレスポンス検証まで0.01秒だったら、毎秒100回で頭打ちです。「スレッド処理」というささやきが聞こえてきますが、やたらに多数のスレッドを上げるわけにも行きません。スレッド切り替えの負荷が相対的に高まり、これまた頭打ちになるからです。なのでプログラム処理上は、レスポンスを待機することなくリクエストを投げられる仕様にしなければなりません。

筆者が今回使ったのは、Apache HTTP ComponentsのHttpAsyncClient(https://hc.apache.org/httpcomponents-asyncclient-4.1.x/index.html)でした。このライブラリではIOリアクターと呼ばれるスレッドプールでリクエストを処理します。ここへ、処理負荷とネットワーク遅延を勘案し、今回は論理コアの10倍のスレッドを設定します。また、タイムアウトも忘れずに設定します。(拙稿「アウトバウンドリクエストはAWS NAT Gatewayに握りつぶされていた」http://cloud.flect.co.jp/entry/2018/08/24/130542 参照)

IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
    .setIoThreadCount(Runtime.getRuntime().availableProcessors() * 10)
    .setConnectTimeout(5 * 1000)
    .setSoTimeout(5 * 1000)
    .build();
PoolingNHttpClientConnectionManager connManager =
    new PoolingNHttpClientConnectionManager(ioReactor, ...
CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
            .setConnectionManager(connManager)
            .build();

// 上記の初期化が終わったhttpClientに対し、以下繰り返す。
HttpGet hg = new HttpGet(url);
// サーバーの負荷試験なので、キャッシュは無効に
hg.setHeader("Cache-Control", "no-cache");
httpClient.execute(hg, new FutureCallback<HttpResponse>(){
    public void completed(HttpResponse hRes) {
        try {
            // ここへ完了処理を書く
        }
        catch (Exception ex) {...}
    } // end of completed

これでレスポンスを待たずに、設定個数のリクエストを連続的に送信できる仕掛けができました。

2. 時間的に分散させる

非同期化によっていくらでも詰め込めるからといって、一気に多数のリクエストを送信するのは良くないと思います。現実世界ではX万台のクライアントをエミュレートしているのですから、揃うわけがないのです。今回は0.1秒ごとに、全体の1/10のリクエストを送信し、さらにこのインスタンスを複数個起動することにしました。

3. 計測結果を一定時間メモリにプールし、まとめてレポートする

次に計測ですが、基本的な数値として、何回リクエストして、いくつレスポンスを受け取ったのか、また、遅延時間(注:ここでの「遅延時間」は、いわゆるレスポンスタイムではなく、レスポンスボディに含まれる時刻とレスポンス時点のクライアント時刻の差分。込み入った話になりますので、詳細は割愛します。)の平均はどれだけだったのかを、5秒に1回計測します。また、別途全てのリクエストの遅延時間を記録し、これも5秒ごとにgzip圧縮してGoogle Cloud Storageに保存しました。

いざテストしてみると。。。

一通りプログラムが動作したところで、いよいよお待ちかねのパフォーマンステストです。起動パラメターを変化させて毎秒あたりのリクエストを増やしていきました。ところが、リクエスト回数が毎秒20回を超えたあたりで予想外の事象が発生しました。

リクエスト送信個数は増えるのに、レスポンス受信個数は増えなくなったのです。

何かのボトルネックにあたったようでした。他のメトリクスも確認したところ、「CPU利用率は低いまま」「メモリ使用量がわずかずつ増えている」の2点が確認されました。サーバー側はどうかというと、依然として涼しい顔。つまり受け取ったリクエストは楽勝で返していました。これらを総合すると、 クライアント側で、何らかの理由で送信リクエストが実際にネットワークデータ送信されることなく積み上がっている、と考えられます。 いったいなぜこういうことになってしまったのでしょうか。

方々、疑う

筆者が最初に考えたのは、「インスタンスあたりの時間あたりの送信パケット上限に到達したのでは?」ということでした。冒頭に書いた通り、一つのインスタンスから一つのエンドポイントへ毎秒20回HTTPリクエストが送信されるなど、普通は無いわけです。強いて言うなら、DOSアタックなどの悪事ということになります。何らかの予防線があってもおかしくありません。また、過去にはホスティング業者も認識していなかった制約を踏んだ記憶もあります。(拙稿「AWS EC2 "悪い" EIPにご用心」http://blog.flect.co.jp/cloud/2015/11/aws-ec2-eip-c3c5.html)こういう暗黙の制約があってもおかしくありません。

それならばと、インスタンス数を50まで増やしてみました。すると合計リクエスト回数は1,000まで上昇したものの、やはりそこで頭打ちとなりました。予防線の存在を確信した筆者でしたが、目標リクエスト数X万のためにはいったいどれだけのインスタンスが要ることかと、半分諦めの心境でした。

GCPでも同じ上限に

しかし、、、いくらググっても、アウトバウンドリクエストのインスタンスあたりの上限というマニュアルも、ブログも、出てきません。さらに、筆者がかつてUDPプロトコルで似たような実験をした時の記憶から考えると、低すぎるリミットに思えました。

筆者は思い切って、クライアントの実装環境をGCPへと変えてみました。(GCPを選んだ理由は特になく、使い慣れていただけです。)すると、、、やはりインスタンスあたり毎秒20リクエストで頭打ちでした。いくら何でも、2つの環境でぴったり同じというのはおかしいような気がします。

原因はライブラリのリミット

次に筆者が疑ったのは、使用したライブラリに設定された制限です。冒頭に書いた通り、サーバー側であればパフォーマンスは高度に最適化されている一方、クライアントから大量リクエストするシナリオは世間的には稀。何らかの足枷があるのではないかと思ったのです。結果として、これが原因でした。

たどり着いた以下のAapache HTTP Componentsオフィシャルページには、次のように書かれていました。 https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e393

Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total.

それならばと以下のように設定すると、リクエスト数が頭打ちになる現象は解消されました。

PoolingNHttpClientConnectionManager connManager =
    new PoolingNHttpClientConnectionManager(ioReactor, ...
connManager.setMaxTotal(Integer.MAX_VALUE);
connManager.setDefaultMaxPerRoute(Integer.MAX_VALUE);

これにて無事、目標とする毎秒X万件のHTTPSリクエストが実行でき、必要となるサーバー要件が確認されました。

本当に正しく多数のリクエストを送信していたのか

前述の通り、今回の検証では全てのリクエストについて遅延時間を計測しています。毎秒X万リクエストの全てですから、検証時間中のリクエストの合計数はかなりの数です。それらの遅延時間の分布はどうなっているのでしょうか。Google Cloud Storageに保存されている記録をBigQueryにインポートして調べてみましょう。詳細は割愛しますが、前述の通りここでいう遅延時間とは、レスポンス直後のシステム時刻とレスポンスボディに書かれた時刻の差分のことで、もしクライアントサイドからのリクエスト時刻の分布が時間的に偏りなく一様ならば、遅延時間も0秒から3秒まで均一な分布になると予想されていました。

予備調査によると遅延時間の最小値は50ミリ秒、最大値は3650ミリ秒でした。そこで遅延時間を0 ~ 100, 100 ~ 200, ..., 3600 ~ 3700のスロットで分け、それぞれについてスロット内での平均と標準偏差を計算してみました。

結果は下記のグラフの通り、両エッジのわずかなサンプルを除くと分布には何の偏りも見られませんでした。スロットの大きさを10ミリ秒にもしてみましたが、傾向は同じでした。

f:id:masashi-sato-flect:20190430123935p:plain
遅延時間の分布

検証用のクライアントプログラムは、目論見通り、時間的に一様に、かつ緻密に、リクエストを発信してくれたようです。

最後までお読みくださり、ありがとうございました。

Alexaスキルのデザイン・開発・公開

エンジニアのオクダです。こんにちは。今回のテーマは「Alexaスキルのデザイン・開発・公開」です。

今回お話する内容は

  • Amazon Alexaと応用開発

  • スキル「全国の郵便番号検索」

  • スキル「西暦・元号変換」

  • スキル「よく当たるタロット占い」

  • 審査と公開

です。

みなさんはスマートスピーカーに話しかけてみたことはありますか?Alexa (アレクサ)はアマゾンエコーの実装技術の名前です。最近は音声認識技術が向上し、応用開発が現実的になってきました。

Amazon Alexaと応用開発

Alexaは、以下のような仕掛けになっています。

Alexaの概要図
Alexaの概要図

応用開発の全体的な仕掛け

Alexaデバイスの一つであるEcho Dotが受信した音声は、アマゾンのAlexaに送信されます。ここで音声から文字への変換と文法解析が行われ、AWS Lambdaなどの機能を呼び出すというのが基本的な流れです。 最初に決めなければならないのがinvocationNameです。

ウェイクワードとも呼ばれ、Alexaを自分のスキルに向かすための言葉となります。注意しなければならないのは、 英数字は使用できないことです(漢数字はOK)。また もう既に登録されているinvocationNameは使用できません。 認識されにくい言葉も使用できない(弊社名「フレクト」はfreakedと誤認される)。さらに、 助詞「に」「は」を含むinvocationNameも使用できません。

invocationNameが検知されたら、以後ユーザーが話した内容がコールバックされてきますが、そのままテキストで通知されるわけではありません。事前に拾いたい文書表現をIntentとSlotという形で登録しておき、これに該当するものだけが処理対象になります。図示すると以下のようになります。

音声からテキスト変換の流れ

この図ではPostCodeSearchという名前のIntentが定義され、「の郵便番号を」の周辺に4つの{}書きされたSlotが定義されています。Alexaはこの文法構造に該当する発話を捉え、Lambda関数をコールバックしてきます。

なお、intent名に使用できるのは英字大文字小文字とアンダースコアのみで、数字は使用できません。

Intent Slotsの作成

Alexaでいうslotとは、Synonym(同義語)を含んだ単語群の総称です。カスタムslotだけでなく、標準slotも利用可能です。他にも「日付」を表すAMAZON.DATE、「数字」を表すAMAZON.NUMBERなどがあります。

なお、intent同様、slot名に使用できるのは英字大文字小文字とアンダースコアのみで、数字は使用できません。intent名との重複も許可されていません。

ValuesとSynonymの定義

Slotに含まれる実単語をvaluesと呼びます。ひとつのslotに複数のvalueを指定することができます。valuesには、Synonym(同義語)も登録出来ます。

Lambdaの実装

Lambdaの実装の前に、Alexa Developer ConsoleのEndpointをLambdaに登録する必要があります。Lambdaのリソース名をAlexa Developer Consoleに登録する必要もあります。 相互のEndpointを登録するとAlexa SkillからLambdaのmain handlerである、lambda_handlerにeventが送られてきます。 そのeventにはsession(その会話中の情報を保持、明示的に保持しなければ空)、context(System/device情報、Viewport情報、Geolocation情報(位置情報を許可))、request(request type情報やintent情報)が含まれています。

Alexa Skillから送られてきたevent['request']['intent']['name']やevent['request']['intent']['slots']['slot name']['value']の値によって、Alexaにspeech outさせたい言葉をtextで指定します。 2つ前の会話内容をsessionに登録したり、device情報やGeolocation情報を使用して、speech outさせる言葉を決定することも可能です。

次に具体的にスキルの開発方法について説明します。

スキル「全国の郵便番号検索」

(https://www.amazon.co.jp/dp/B07PBXH5Y9)

日本郵政が公開している住所と郵便番号の対応表を使って、住所に対応する郵便番号や、その逆を答えてくれるスキルです。

Lambda関数からS3にアクセスする必要がありますので、AWSLambdaBasicExecutionRoleとAmazonS3FullAccessをLambda関数のRoleとして設定します。

Lambda関数内の処理では、intentの特徴より、住所から郵便番号を読み上げるか、郵便番号から住所を読み上げるかを決定します。

スキル「西暦・元号変換」

(https://www.amazon.co.jp/dp/B07PYQ3Z94)

西暦から元号を、または元号から西暦を答えてくれるスキルです。日本人のみなさんなら、特に公文書記述でよく必要となる暦の変換です。 このスキルを開発している途中で、新元号「令和」が発表されました。Alexaが事前に知るはずもない、完全に新しい単語ということですが、このような場合はSlotにValueを登録することで認識を改善することができます。 f:id:flect170:20190421151149p:plain

例えば、Slot Valueに「令和」が登録されていない場合、Alexaは既知単語のどれかに当てはめようとし、失敗します。f:id:flect170:20190421151343p:plain

このような場合、Slot Valueに「令和」を登録することで、このValueへと単語認識を誘導することができます。 f:id:flect170:20190421151501p:plain このノウハウは活用シーンがいろいろあるのではないでしょうか。

スキル「よく当たるタロット占い」

(https://www.amazon.co.jp/dp/B07PPN25MT)

このスキルでタロット占いをお願いすると、本日のタロットカードを1枚引いてくれます。

画像付きEchoは何が違うか?

Echo ShowやEcho Spotなど、Amazon製のディスプレイ付きスマートスピーカーは、音声に加えて映像を表示させることができます。(ただし、ディスプレイがあってもiPhoneAndroidには画像を表示することが出来ません。) 画像を表示させるには「alexa presentation language」を使用します。

画像対応デバイスの認識

f:id:flect170:20190421151828p:plain
画像対応デバイスの認識

画像非対応デバイスEcho Dotの場合、Echo Dotからイベントが送られ、そのコンテキストのsupportedInterfacesが空になっています。 画像対応デバイスEcho Spotの場合、Echo Spotからイベントが送られ、そのコンテキストのsupportedInterfacesにAlexa.Presentation.APL属性が含まれています。

f:id:flect170:20190421152022p:plain
画像の出し方

画像の出し方は、画像対応デバイスであると判断した後、Lambdaが本文で表示させる内容をAmazon Alexaに送信します。それと同時にS3に登録されたimageのパスも送信され、S3に保存された画像をAlexaに送信し、Echo Spotで表示するという仕掛けになっています。この場合はAlexaに通知するパスが無認証でアクセスできるように配慮する必要があります。

審査と公開

開発が完了したスキルを公開するには、アマゾンによる審査を受けなければなりません。

ここでは筆者が経験した代表的な指摘事項とその対応方法について記載します。

指摘事項その1。スキルの呼び出し名

呼び出し名が一般的である。呼び出し名がAmazonが指定するフォーマットに合っていない、スキルの呼び出し名に、助詞や接続詞を使用できないなどがある。

対応方法

呼び出し名をAmazonが指定するフォーマットに変更する。

指摘事項その2。スキルの説明

スキルの説明には、ユーザーがスキルを使用する際に十分に理解できるように説明しなければならない。 Alexa標準機能と混同するような説明を記載してはいけないなどがある。

対応方法

Amazonからの指示通りに、スキルの説明文を修正。

指摘事項その3。サンプルフレーズ

サンプルフレーズ1番目には「アレクサ、...を開いて」にしなければならない。 言い回しの異なるサンプル発話が不足している。 サンプル発話に記載したフレーズは必ずIntentに登録しなければならない。などがあります。

対応方法

サンプルフレーズ1番目を「アレクサ、...を開いて」に変更したり、 Amazonの指示通りに、サンプルフレーズに使用している言い回しをSlotに追加したりして対応した。

指摘事項その4。Slot関連

Slotに使用できない記号、Slotに使用できるが正しく認識できない記号などがあります。 記号「(」、「)」や「〜」や「−」をSlotに使用することはできません。 Slotにスペースを使用することはでき出来ますが、実際のSpeech to Textではスペースは文字として変換されません。

対応方法

Intentから記号を全て削除しました。

指摘事項その5。標準Intent関連

AMAZON.CancelIntentには、開発者には見えない既存のSlotが含まれています。そのSlotをAMAZON.StopIntentに登録してはいけません。 AMAZON.DATEをSlot typeとして使用している状態で、特定の言葉を話すとスキルがエラーを返します。

対応方法

同じSlot valueが複数の標準Intentに使用されないようにする。 AMAZON.DATEとして認識して欲しくない場合は、別途カスタムSlotを定義したり、スキルがエラーを返さないようにLambdaを修正しなければならない。

指摘事項その6。終了処理

スキルがタスクを完了した後、ユーザーへのプロンプトが提示されていないにもかかわらずセッションが開いたままになっている。 ユーザーが2回連続無言だとエラーになる。などがあります。

対応方法

スキルがリクエストを完了した後、ユーザーの入力を求めるプロンプトを提示していない場合はセッションをクローズします。 Lambdaでイベントのリクエストタイプが"SessionEndedRequest"の時、終了処理を入れてあげます。

指摘事項その7。プライバシー

スキルで、ユーザーの生年月日など個人の情報を収集する場合、法的に適切なプライバシーポリシーを提示しなければなりません。

対応方法

「誕生日を教えて下さい」から「調べたい年月日を教えて下さい」に変更して対応しました。

指摘事項その8。著作権

Amazonにとって知的財産権の保護は非常に重要です。コンテンツの内容を使用する権利を持っていることを示す文書を提示してください。

対応方法その1。

コンテンツ変更により、著作物を使用を諦めました。

対応方法その2。

著作物の商用利用が可能な場合、著作元URLをスキルの詳細説明欄に貼り付けました。

感想

今回、Amazon Alexaを使用して、Alexaスキルの開発・公開を行いましたが、開発する苦労を改めて実感しました。 しかし、音声アシスト分野の利用はこれから需要が見込まれるので、引き続き、調査・開発に取り組んでいきたいと考えています。

Heroku Metrics について

Heroku Adevent Calendar 2018 の18日目の記事です。17日目はsilverskyvicto さんの「Heroku のアドオンを自作する方法を見てみた」でした。

なお、15日目は弊社代表取締役 黒川 幸治 による寄稿でした。 Re:Invent から帰ってきてすぐにHerokuの記事書いて…となかなか精力的なエンジニアっぽい感じですが、肩書は社長です。

Heroku の強み

Heroku を使いはじめてから気づく魅力の一つに、標準で用意されている機能の豊富さが挙げられます。たとえば Postgres/Redisアドオンや Github とのインテグレーション、Pipelines/Heroku CIでのCI/CD、CLIAPIなどなど…

マネージドという言葉でIaaSプラットフォームもたくさんの機能を複雑な設定なく利用できるようになりましたが、開発者がプログラミングに集中する、それを実現するための万全な体制をプラットフォームが引き受ける。言うなれば引き算の美学は、まさしく Heroku が作り上げてきたものです。Heroku Metrics も同じ考え方の元で用意された標準機能の一つと考えられます。

今回紹介するHeroku Metrics は、ほとんど導入コストなしに、アプリケーションのパフォーマンス監視ないし必要に応じた通知を行える機能です。DynoやAddonのPlanを柔軟に変えられるためか、Metrics自体の機能をそのまま使わずにカットオーバーを目指しているプロジェクトを見かけることがあったので、どういうことができるんだろう・ひとまず使ってみましょうという思いから今回の記事を作成しました。

Heroku Metrics でできること

1. メトリクス監視

f:id:shns:20181216161802p:plain

アプリケーションの 「Overview」の左上部にある「Metrics」が Heroku Metrics によるモニタリングレポート。イメージとしては Zabbix なり CloudWatchのダッシュボードに近いと思いますが、エージェントを設定したりダッシュボード自体を作る必要はなし。いくつかの手順を踏むだけで使えるようになります。

以下は、いくつかのダッシュボードの例です。管理者用サイト、マイページのデモサイト、ショッピングサイトと用途はそれぞれ。develop, staging, production の違いだったり、JVM , PHP, Ruby など言語の違いによってもある程度これらの数値は変わってきます。いずれにしても、アプリケーション開発者はほとんど何も実装や設定をせずに使い始めることができます。

f:id:shns:20181217105422p:plain f:id:shns:20181217105438p:plain f:id:shns:20181217105452p:plain

メトリクス

以下のメトリクスが見られます。はじめは Events あたりで Platform のイベントと、Dyno restart などを見ながら、それ以外のメトリクスの動き方をじっくり眺めるのが良いんじゃないかと思います。

  • Events
  • Memory Usage
  • Response Time
  • Throughput
  • Dyno Load

JVMメトリクス

アプリケーションのRuntime によって追加のメトリクスも用意されていて、JVM だと以下も追加で閲覧可能。

  • Heap Memory Usage
  • Non-Heap Memory Usage
  • Aggregate Time Spent in Garbage Collection
  • Aggregate Garbage Collections

設定の仕方

前述の通り、設定自体はほとんどすることがなく、 Dynoが動いていればダッシュボードに Metrics の情報が表示されるようになります。

対象のDynoの選択

f:id:shns:20181216170741p:plain

上の選択リストで対象のDynoを選択。

メトリクス期間の選択

f:id:shns:20181216170730p:plain

こちらの選択リストでメトリクスの期間を選択します。選べるのは「過去2時間/過去24時間/24~48時間前/48時間前〜72時間前/過去3日間/過去7日間」のいずれか。Cloud Watch が15ヶ月くらいだったと思いますが、稼働中だったりサービス稼動目標があるアプリなんかだとよほど遡及せざるを得ない理由が無い限り、そこまでの期間は必要ないですね。

メトリクスの設定

f:id:shns:20181216170327p:plain

歯車アイコンからメトリクスの設定が可能で、ダッシュボードの見た目だったりRuntimeごとのメトリクスをここで有効化します。GAになっているJVM以外にも、2018/12時点で Public Beta の Ruby / Node.js。Dev Center の Getting Started 通り、適宜 push して様子を見ていればいつの間にかメトリクスに上がってくるようになります。

アラート(閾値・通知方法)の設定

「Configure Alerts」 から、Response Time と Failed Requestsについてはしきい値を設定して、超えた場合にメール通知を行うことも可能です。

f:id:shns:20181216170313p:plain

AWS あたりだと、一度 SNS に渡してから LambdaなりSQSなりに繋げることが多いと思いますが、こちらは「アプリのMember全員に送信」「5通までの任意のメールアドレス」あとは PagerDuty に一度渡してポリシー適用というのが可能です。投げ先としては運用チームのメーリングリストなり、SlackのEmailAppを設定済みの監視Channelなりを選ぶのがシンプルだと思います。

ちょっとだけ注意したいのは、Addonをいくつか使っていると通知系が渋滞気味になるので、ちゃんと通知系の設定の粒を揃えておくべきということです。たとえばNewRelic/PagerDuty/Bugsnag/PapertrailとHerokuMetricsでそれぞれ通知の系があるのであれば、通知やサマリー送付などの頻度・条件を揃えておくか、ひと目でわかるように一覧化しておきましょう。時間差があると障害対応時に錯綜することがあるので。

ユースケース

1. 本番の稼動監視

アプリケーションの運用保守用途に使います。 PagerDutyやPingdom、Bugsnagと組み合わせることもありますが、基本的には Alert 設定までは必須で。設定先としては、上に挙げたような、監視用MLへの通知、Slackへの通知。

Alert の時間間隔は「1分/5分/10分」から選べますが、連携システムがある場合はそちらに合わせることが多いです。AWS側が詳細モニタリングを有効化しているなら、1分に合わせたり、など。

上に書いたメトリクス一覧のうち、見ることが圧倒的に多いのは Events と Throughput 。 Memory Usage とかは本番稼働後というよりは設計/実装時のサイジングの検証時に見ることが多いです。まず Events で事象や時系列を確認したら、 Throughput をみながら、問題箇所を特定していきます。

ポイントとしては、プラットフォーム/アーキテクチャレイヤーでの解決が可能かどうかの切り分けをすること。

もしDynoやAddonのPlanを変えてもエラーが出続ける場合は、ソースコードのロジックに何か問題がある場合があります。コードレベルの問題特定だったら、 NewRelic に任せましょう。…というと敷居が上がりそうなのですが、Heroku標準でここまでできている部分がほとんどで学習コストがほぼほぼゼロと言って良いものなのと、Heroku Metrics と NewRelic で役割分担ができるので、そこまで大変ではないと思います。RailsだとScout使うと良いって話もあるのですが、HerokuMetricsとNewRelicで慣れてしまっているならそれでも良いし、bullet とか特定用途で結構Gem入れちゃってたりすることもあると思うので、うまい棲み分けが正直知りたいところ。

2. 非機能系テスト用

パフォーマンステストと監視テスト、障害復旧テストあたりで使います。stagingまたはtest用環境を用意して、本番想定の状態でテストを行い、しきい値が適切か、きちんとアラートが飛ぶか、または通知後の復旧手順が正しく踏めたかを検証する際に利用します。

なお、必須ではないと思います。ミニマムプロジェクトや検証用途では必ずしも非機能周りはスコープになるとは限らないし、Heroku の拡張性や柔軟性の高さから、順次考えていけばよい、その時に設定すれば良い、という考え方もできるので。ただ、Dynoのコレクションについてはメモリやネットワーク、GPUなり特化型のインスタンスが用意されているというよりは事前定義済みのプランからの選択になるので、スケールアップ/ダウンの勘どころは IaaS と比べて少し変わってくるかなと思ってます。

最後に

cloud.flect.co.jp

  • 早く容易に導入ができる(インフラ基盤、ミドルウェアまで提供されているため)
  • 柔軟かつ早いスケーラビリティが実現できる
  • 運用が容易にできる
  • Salesforceとの親和性がよい 等々

Heroku Metrics は縁の下の力持ちな存在として、Herokuでのアプリケーション運用を支える重要なサービスであり、黒川が書いたようにHerokuを使う価値をわかりやすく体現した存在であると思います。簡単に使い始められるので、ぜひ使ってみてください。

Herokuのビジネス的な利用価値

Herok Adevent Calendar 2018 の15日目の記事です。

はじめに

はじめまして、フレクト代表取締役の黒川です。

フレクトはHeroku、SalesforceAWSのパートナーとして、IoTやAIなどデジタルサービスの構築をご支援しているマルチクラウド・インテグレーターです。 そしてB2Bのリアルタイム車両管理「Cariot」をSaaSで提供していてます。

Herokuは2012年から利用していて、当時、TV番組連動のWEB・モバイルサイトを3週間の短期間で、かつ高い性能要件を満たしてリリースできたのは、Herokuだからこそ成せる業として社内で語り継いでいます。(語り継がれているわけではありません。)

またオフィシャルな「Heroku実践入門」のトレーニングカリキュラムの作成や講師も担当していました。(途中からSalesforce社にバトンタッチして今はやっていません。)

もちろん現在でもHerokuを広く活用している会社がフレクトになります。

  

HerokuとAWS

さてそんなフレクトでも現場においてHerokuとAWSの選定は議論になるところです。 案件においてSalesforceのインテグレーションがあればHeroku、顧客の指定があればそちらのクラウド、またHerokuもAWSも適材適所で使い別けてマルチクラウド環境で組み合わせをするといったことも多々あることです。

そこでHerokuを使うビジネス的な価値について、AWS re:invent 2018の「How Modern Dev Teams Build on Salesforce Heroku and AWS」セッション資料を引用しながらご紹介します。

まず言わずもがなではありますが、HerokuはAWS上で提供されているPaaSです。多くのAWSサービスをHerokuも利用しています。

f:id:flect_kurokawa:20181214191607p:plain

f:id:flect_kurokawa:20181214191623p:plain

ちなみにAWS re:invent 2018の期間中だけでもAWSのサービスリリースは100以上もありアップデートがすこぶる早いです。 もちろん全てのサービスを抑えることは困難ですが、部分的でも最新のサービスをキャッチアップし続けることは、それはそれで大変です。 そもそもAWSを利用する際は、インフラ設計・実装ができるリソースが必要になります。

ではHerokuを使う価値は、

f:id:flect_kurokawa:20181214235240p:plain

  • 早く容易に導入ができる(インフラ基盤、ミドルウェアまで提供されているため)
  • 柔軟かつ早いスケーラビリティが実現できる
  • 運用が容易にできる
  • Salesforceとの親和性がよい 等々

Herokuは開発・運用におけるエンジニアのリソースをアプリケーション開発に注力することができる、また生産性を高めることができる環境と言えます。エンジニアにとっても顧客にとっても価値があるので、要件見合いとはいえ、これからも広く利用していきたいと思います!

  

最後に

Dreamforce 2018期間中に、縁(訳?)あってBiz側の人間ながら記事投稿させていただくことになりました。 Tech内容ではありませんが、ご容赦ください。 またこのような機会をいただけたことに社員、Herokuのみなさまに感謝!