イベントページ
資料
www.slideshare.net
振り返り
朝まで飲んでちょっとだけ寝てから登壇したところ、めちゃくちゃテンションが低くなる現象が発生しましたが、PaaS組み合わせて使って楽になろうという話をしてきました。
おばかIoTのイケメンだけ撃てる銃とか、The DAOの事件の話とか面白かったです。
www.slideshare.net
朝まで飲んでちょっとだけ寝てから登壇したところ、めちゃくちゃテンションが低くなる現象が発生しましたが、PaaS組み合わせて使って楽になろうという話をしてきました。
おばかIoTのイケメンだけ撃てる銃とか、The DAOの事件の話とか面白かったです。
Azure FunctionとWebJobで、Azure Storage Queueを介して、LINE Bot APIのメッセージの収集と送信を行うサンプルを作成しました。
LINE Bot APIへリクエストするにはServer whitelistにIPアドレスを設定する必要があります。*1
おそらく同一MIDを使ったDDoS攻撃への対策だと思いますが、このwhitelistのせいでグローバルIPアドレスを固定できないPaaSが使えなくなってしまいます。 *2
DDoS攻撃への対策についてはwhitelistではなく、一定時間内に一定数を超える複数のIPアドレスから、同一MIDが正しいChannel IDとChannel Secretでリクエストしてきた場合、ブラックリストへ登録してリクエストを一定時間遮断するような実装にするのが良いと思います。*3
例えば下記のような方法があります。
{ "ipAddress": "192.168.1.1", "addressChangedCount": 0, "isBlocked": false }
現状、whitelistチェックのためにデータストアへアクセスしているならば、処理コストをあまり増やさずにBOT開発者の利便性を向上させることができると思います。
ちなみにサンプルで作成した構成は下記の通りで
この構成だと返信ジョブが失敗した場合に、一定回数のリトライも、リトライに失敗した場合のデータの保存もWebJob SDKが面倒見てくれます。*4
PaaSだと面白いBOTを思いついたら手軽に試せてスケールもしやすいので、LINE Bot APIの開発者の方にはServer whitelistの撤廃を検討頂けるとありがたいです。*5
*1:Callback URLをリクエストしてもらうのはServer whitelistの設定不要
*2:「Azure Web AppsはグローバルIPアドレスを固定にすることは可能ですか?」とMicrosoftに問い合わせてみたところ「まだその機能がありません。将来的にも組み込まれるかどうかもわからないようです。」とのこと
*3:弊社のゲームではBOT検出&遮断アルゴリズムの1つにリクエスト元IPアドレスを使ったものを実装している
*4:queueのアイテム名に「-poison」を付けて別queueに保存される
*5:トライアル版だからServer whitelistがあっただけだったなら杞憂
BigQueryをLINQで扱えるようにするためのライブラリです。
StartActionに宣言したRequest.Pathへアクセスされるとログ採取スタート。 LoggingSpanに宣言した期間離脱するとキャッシュが無くなって採取おわり。 期間内にアクセスするとIndexを増やしながらFromPathとToPathをBigQueryへログ出力していく。
スキャン対象となるデータ量を抑えるために、BigQueryのテーブル名にはyyyyMMを付与しています。
サンプルコードではutil.getJSONがAPI呼び出しをしていますが、その奥にあるのはjQueryのajaxメソッドです。
jQueryのajaxメソッドを呼び出すようにサンプルコードを修正しました。
色々とAPIのパスが見えているので画像はぼやけさせていますが、Sankey Diagram(サンキーダイアグラム)感は、感じて頂けるのではないでしょうか。
今回のサンプルコードでは、OwinContextにログインユーザーのIDしか入っていないパターンだったので、期間とステップ数でしか対象者を絞れませんでした。他にもユーザーの属性(例えばゲームならレベルとか)をBigQueryへ保存し閲覧する時に絞り込めれば、目的に合わせて分析できてなお良いのではないでしょうか。
*1: 公開用に改変しているのでこのままでは動作しません、他のサンプルコードも同様。 GitHub - neuecc/CloudStructures: Redis Client based on StackExchange.Redis. をカスタマイズして GitHub - cloud9-plus/CloudStructures: Redis Client based on StackExchange.Redis. 使ってます。
*2:GitHub - filipw/AspNetWebApi-OutputCache: ASP.NET Web API CacheOutput - library to allow you to cache the output of ApiControllers を使ってます。
昨日「Microsoft Project OxfordのComputer Vision APIを使ってみる」という記事を書きました。
Google Cloud PlatformにもVision APIがあるので試してみようと思います。
Visual StudioでWeb APIプロジェクトを作成。
NuGet Gallery | Google.Apis.Vision.v1 1.57.0.2634 をインストール
APIを作成。今回はGoogle Cloud Storageへ 「エンジニアなんだからFAXも直せるでしょ」と言われるの写真素材 - ぱくたそ のお姉さんの画像をアップロードして使用。全機能リクエストしてます。
結果はこちら。JSONが大きいのでスクリーンショットではなくテキストで。
{ responses:[ { error:null, faceAnnotations:[ { angerLikelihood:"VERY_UNLIKELY", blurredLikelihood:"VERY_UNLIKELY", boundingPoly:{ vertices:[ { x:353, y:34, eTag:null }, { x:664, y:34, eTag:null }, { x:664, y:395, eTag:null }, { x:353, y:395, eTag:null } ], eTag:null }, detectionConfidence:0.8755698, fdBoundingPoly:{ vertices:[ { x:418, y:114, eTag:null }, { x:642, y:114, eTag:null }, { x:642, y:338, eTag:null }, { x:418, y:338, eTag:null } ], eTag:null }, headwearLikelihood:"VERY_UNLIKELY", joyLikelihood:"VERY_UNLIKELY", landmarkingConfidence:0.592607558, landmarks:[ { position:{ x:541.064636, y:175.69809, z:0.00113653147, eTag:null }, type:"LEFT_EYE", eTag:null }, { position:{ x:606.808533, y:206.526047, z:62.9831734, eTag:null }, type:"RIGHT_EYE", eTag:null }, { position:{ x:516.7551, y:147.708527, z:-8.272155, eTag:null }, type:"LEFT_OF_LEFT_EYEBROW", eTag:null }, { position:{ x:574.37146, y:159.893372, z:10.4143019, eTag:null }, type:"RIGHT_OF_LEFT_EYEBROW", eTag:null }, { position:{ x:606.229858, y:173.236755, z:40.98865, eTag:null }, type:"LEFT_OF_RIGHT_EYEBROW", eTag:null }, { position:{ x:625.407654, y:192.494385, z:96.7955, eTag:null }, type:"RIGHT_OF_RIGHT_EYEBROW", eTag:null }, { position:{ x:588.6517, y:183.960876, z:19.3756, eTag:null }, type:"MIDPOINT_BETWEEN_EYES", eTag:null }, { position:{ x:599.7611, y:235.518936, z:-15.2664413, eTag:null }, type:"NOSE_TIP", eTag:null }, { position:{ x:580.7478, y:269.287048, z:-9.681131, eTag:null }, type:"UPPER_LIP", eTag:null }, { position:{ x:572.713135, y:300.852, z:-14.1530352, eTag:null }, type:"LOWER_LIP", eTag:null }, { position:{ x:544.012451, y:279.2989, z:-21.0170631, eTag:null }, type:"MOUTH_LEFT", eTag:null }, { position:{ x:588.0662, y:295.959778, z:28.44663, eTag:null }, type:"MOUTH_RIGHT", eTag:null }, { position:{ x:574.9631, y:282.396027, z:-8.923364, eTag:null }, type:"MOUTH_CENTER", eTag:null }, { position:{ x:593.7063, y:252.415634, z:24.9813824, eTag:null }, type:"NOSE_BOTTOM_RIGHT", eTag:null }, { position:{ x:559.2501, y:241.225586, z:-9.623048, eTag:null }, type:"NOSE_BOTTOM_LEFT", eTag:null }, { position:{ x:584.410034, y:250.873962, z:-4.506706, eTag:null }, type:"NOSE_BOTTOM_CENTER", eTag:null }, { position:{ x:547.282837, y:170.129669, z:-2.050267, eTag:null }, type:"LEFT_EYE_TOP_BOUNDARY", eTag:null }, { position:{ x:557.2416, y:182.196564, z:13.7818327, eTag:null }, type:"LEFT_EYE_RIGHT_CORNER", eTag:null }, { position:{ x:540.6396, y:183.45163, z:-2.0629003, eTag:null }, type:"LEFT_EYE_BOTTOM_BOUNDARY", eTag:null }, { position:{ x:522.974548, y:173.02684, z:-6.10401154, eTag:null }, type:"LEFT_EYE_LEFT_CORNER", eTag:null }, { position:{ x:542.6806, y:176.329376, z:-2.00644469, eTag:null }, type:"LEFT_EYE_PUPIL", eTag:null }, { position:{ x:612.3812, y:197.071289, z:60.93033, eTag:null }, type:"RIGHT_EYE_TOP_BOUNDARY", eTag:null }, { position:{ x:613.783142, y:210.560913, z:81.82983, eTag:null }, type:"RIGHT_EYE_RIGHT_CORNER", eTag:null }, { position:{ x:606.9622, y:210.3664, z:61.05775, eTag:null }, type:"RIGHT_EYE_BOTTOM_BOUNDARY", eTag:null }, { position:{ x:593.684265, y:199.262146, z:50.88671, eTag:null }, type:"RIGHT_EYE_LEFT_CORNER", eTag:null }, { position:{ x:609.48584, y:203.937683, z:62.56031, eTag:null }, type:"RIGHT_EYE_PUPIL", eTag:null }, { position:{ x:551.33905, y:142.170044, z:-0.1636725, eTag:null }, type:"LEFT_EYEBROW_UPPER_MIDPOINT", eTag:null }, { position:{ x:621.85144, y:171.3207, z:68.1858139, eTag:null }, type:"RIGHT_EYEBROW_UPPER_MIDPOINT", eTag:null }, { position:{ x:412.211426, y:214.9295, z:28.4080238, eTag:null }, type:"LEFT_EAR_TRAGION", eTag:null }, { position:{ x:559.8016, y:278.0976, z:170.527115, eTag:null }, type:"RIGHT_EAR_TRAGION", eTag:null }, { position:{ x:593.098938, y:165.201691, z:23.6455746, eTag:null }, type:"FOREHEAD_GLABELLA", eTag:null }, { position:{ x:560.7295, y:341.240265, z:-17.0568733, eTag:null }, type:"CHIN_GNATHION", eTag:null }, { position:{ x:440.485, y:275.949, z:-9.309473, eTag:null }, type:"CHIN_LEFT_GONION", eTag:null }, { position:{ x:573.0591, y:328.770172, z:119.69677, eTag:null }, type:"CHIN_RIGHT_GONION", eTag:null } ], panAngle:44.0354538, rollAngle:7.173631, sorrowLikelihood:"VERY_UNLIKELY", surpriseLikelihood:"VERY_UNLIKELY", tiltAngle:16.4116535, underExposedLikelihood:"VERY_UNLIKELY", eTag:null } ], imagePropertiesAnnotation:{ dominantColors:{ colors:[ { color:{ alpha:null, blue:110, green:84, red:70, eTag:null }, pixelFraction:0.107155956, score:0.173213258, eTag:null }, { color:{ alpha:null, blue:235, green:231, red:228, eTag:null }, pixelFraction:0.2768196, score:0.155500337, eTag:null }, { color:{ alpha:null, blue:21, green:22, red:25, eTag:null }, pixelFraction:0.08605505, score:0.0613242574, eTag:null }, { color:{ alpha:null, blue:99, green:112, red:145, eTag:null }, pixelFraction:0.00281345565, score:0.00267118076, eTag:null }, { color:{ alpha:null, blue:143, green:109, red:90, eTag:null }, pixelFraction:0.08672783, score:0.138454765, eTag:null }, { color:{ alpha:null, blue:209, green:201, red:191, eTag:null }, pixelFraction:0.121957183, score:0.106325813, eTag:null }, { color:{ alpha:null, blue:69, green:26, red:null, eTag:null }, pixelFraction:0.0002446483, score:0.0006086802, eTag:null }, { color:{ alpha:null, blue:81, green:60, red:46, eTag:null }, pixelFraction:0.0321712531, score:0.0508035943, eTag:null }, { color:{ alpha:null, blue:54, green:52, red:53, eTag:null }, pixelFraction:0.05877676, score:0.0491721, eTag:null }, { color:{ alpha:null, blue:87, green:78, red:74, eTag:null }, pixelFraction:0.0503975525, score:0.0448334664, eTag:null } ], eTag:null }, eTag:null }, labelAnnotations:[ { boundingPoly:null, confidence:null, description:"disc jockey", locale:null, locations:null, mid:"/m/02dsz", properties:null, score:0.904773355, topicality:null, eTag:null }, { boundingPoly:null, confidence:null, description:"profession", locale:null, locations:null, mid:"/m/063km", properties:null, score:0.8840673, topicality:null, eTag:null }, { boundingPoly:null, confidence:null, description:"person", locale:null, locations:null, mid:"/m/01g317", properties:null, score:0.8571039, topicality:null, eTag:null } ], landmarkAnnotations:null, logoAnnotations:null, safeSearchAnnotation:{ adult:"VERY_UNLIKELY", medical:"VERY_UNLIKELY", spoof:"VERY_UNLIKELY", violence:"VERY_UNLIKELY", eTag:null }, textAnnotations:[ { boundingPoly:{ vertices:[ { x:1039, y:818, eTag:null }, { x:1089, y:818, eTag:null }, { x:1089, y:844, eTag:null }, { x:1039, y:844, eTag:null } ], eTag:null }, confidence:null, description:"JusTio ", locale:"fr", locations:null, mid:null, properties:null, score:null, topicality:null, eTag:null } ], eTag:null } ], eTag:null }
お姉さんの表情、顔の各パーツの位置、画像のラベル付け、コピー機に書かれている「JusTio」という文字列まで様々な情報が取り出せました。
GoogleのCLOUD VISION APIはバッチでまとめて画像のメタデータを作成しておいて、後からそれを使用するのに向いているかもしれませんね。
Microsoft Azureのアプリケーション監視サービスです。 azure.microsoft.com
月間クォータの他にも、データ速度でのスロットルの上限もあります。上限は、Free 価格レベルでは、5 分間の平均が 1 秒あたり 200 データ ポイント、有料レベルでは、1 分間の平均が 1 秒あたり 500 データ ポイントになります。
とあるゲームアプリをApplication Insightsで監視しているのですが、初期にデフォルト設定で本番投入したらスロットルが発動し続けました。
こんなメッセージがAzureポータルに表示され続けます。
スロットルが発動するということは不要にデータ送信していることになっていてネットワーク帯域がもったいないし、ポータルにすごい頻度でメッセージが表示され続けるのは辛いです。
そこで「Application Insights の価格とクォータの管理」に記載されている下記の2つを実施したところ、スロットルが発動しなくなりました。
- サンプリングの使用。このテクノロジは、メトリックや、検索で関連するアイテム間を移動する機能を損なうことなく、データ レートを削減します。
- ApplicationInsights.config を編集し、不要なコレクション モジュールを無効にします。たとえば、パフォーマンス カウンターや依存関係のデータが重要ではないと判断した場合などに検討します。
TelemetryModulesは下記の2つのみに
RequestTelemetryによるサンプリングを全リクエストの1%に
現状、下記の3項目です。
Application InsightsにはProactive Detectionという、機械学習およびデータ マイニングのアルゴリズムを使用して異常パターンを検出してくれるサービスがあるので、レスポンスタイムやException数ぐらいなら監視項目設定の必要が無いかもしれません。
Azure App ServiceはappSettingsをスロット毎に上書きできるので、InstrumentationKeyをWeb.configへ定義してApplication_Startで設定しておくと便利です。
protected void Application_Start() { Microsoft.ApplicationInsights.Extensibility. TelemetryConfiguration.Active.InstrumentationKey = // - for example - WebConfigurationManager.Settings["ikey"]; //...
Application Insights便利ですが、データ送信量を間引くのはconfigファイルやTelemetryConfigurationクラスのプロパティへの設定で簡単に出来てほしいところ。DependencyCollectorなんかも間引ければ本番で使用したいです。