Azure FunctionsでPlaywrightを使ったWebスクレイピング

この記事は、Serverless Advent Calendar 2020 1日目の記事です。

qiita.com

アドベントカレンダーの12月がはじまりましたが、みなさんどれくらい読んでますか?

私も情報収集に使っているモヒカンSlackでは、毎年 #advent-calendar-2020 などといったチャンネルがあり、気が向いた人がAdventarQiita Advent CalendarのカレンダーRSSフィードのURLを登録し、流れてくる記事を毎年楽しんでいます。

あ、モヒカンSlackというのは共有RSSリーダーのように使える公開Slackワークスペースで、Vulsでおなじみのサウナおじさんkotakanbeが運用しています。1万7千人くらいが登録していて、340のチャンネルでテーマ毎に様々なRSSフィードが流れてきます。無料プランということで1週間で10,000メッセージを使い切ってどんどん古い情報は見えなくなるので、古い情報は割り切りましょう!

qiita.com

さて、その昔はAdventarやQiitaのカレンダー一覧を見ながら、温かみのある手作業でRSSフィードを登録していたのですが、ちょうどこの記事が流れてきたので、Azure Functionsの上でPlaywrightを使ったバッチ処理を動かして、Webスクレイピングで全部のアドベントカレンダーを取ってきてSlackに登録するようにしました。

anthonychu.ca

ソースコードはここで公開しています。

github.com

Webスクレイピングには、URLから取得したHTMLをパースして欲しい情報を抽出するものと、ブラウザをHeadless(画面無し)で起動してAjaxなどを動かした結果からDOMなどを経由して抽出するものがあります。今回は、AdventarがgRPC APIを使っていて面倒くさい、SlackがレガシーAPIでないとスラッシュコマンドを投げられないなどいくつかの理由があり、Headlessブラウザを使うことにしました。

この手のHeadlessブラウザの操作ライブラリでは、Chromiumの開発者が作っているPuppeteerが定番かなと思いますが、FirefoxやWebKit(Safari)にも利用できるPlaywrightを今回は使ってみました。

つくりかた

この手のWebスクレイピングは、とにかくローカルで試行錯誤しながら組み立てていくことが多いかと思います。今回は、最初にベタなスクリプトとして動く部分を作り上げてから、それをAzure Functionsの関数アプリに変換するという手順を踏みました。開発環境としてはWSL2上のUbuntuにVSCodeで接続しています。VcXsrvを併用すると画面を使うアプリも動かせるので、一時的にHeadlessを解除して実際のブラウザ画面を見ながら試すこともできます。

動くスクリプトができてしまえば、host.json、functions.json、index.jsの三つを用意することで関数アプリとしてそのままデプロイできるようになります。対応するコミットがこれです。

github.com

いったんHTTP APIとして動作確認し、それからタイマートリガーに設定変更しました。これはfunction.jsonの変更だけでいけます。

github.com

これで10分に1回、スクレイピングして自動でSlackにRSSフィードのURLを足りない分だけ登録してくれます。

はまったところ

これだけ書くとさらっと動く感じですが、詰まるところが無いわけでは無いです。

1. Headlessを解除したときにダイアログが出ると操作ができない

動作確認のためにHeadlessを解除できる(lib/AdventCalendarCrawler.jsのL128あたりのheadless: false)のですが、Slackはブラウザで開くとデスクトップアプリを開くよう誘導され、Chromeのモーダルダイアログが開いてしまいます。この状態だとダイアログを閉じるまでウェブページ内の操作ができないため、後続の処理が失敗してしまいます。

dialogイベントをハンドリングしても上手くいかなかったので、とりあえず動作確認中はダイアログが出たらすぐに閉じるという運用でカバーしました。

2. Playwright内のchromeインストール場所

上の記事をよく読めばきちんと書いてあるのですが、Playwrightはnpm install中にChromeのバイナリをインストールしてくれます。してくれるのですが、普通に入れるとnode_modulesの下ではない場所にインストールしてしまうので、環境変数PLAYWRIGHT_BROWSERS_PATH0に設定する必要があります。

また、デプロイ時も、VSCodeからデプロイするなら.vscode/settings.jsonを、コマンドラインなら--build remoteを付けることでリモートでビルドが走り、その中でChromeのインストールが走ります。そのためデプロイに3分間ほどかかりますが待ってください。

3. Azure Functionsで動かしたらタイムアウトする

ローカルでは普通に動いていたんですが、じゃあいざAzure Functionsの関数として動かしてみたら見事にタイムアウトしました。まあ、こういうこともあるということで。

ちなみにAzure Functionsの従量課金プランでは一つの関数呼び出しの最大実行時間は10分間なので、それを超えると強制終了されます。試した範囲では5分ぐらいで終わっていたので、今回の範囲ではまあなんとかなるかなと。もしこれを超えるようであれば、処理を分解してDurable FunctionsでFan-outしたりする必要がありそうです。

4. Slackがクロールしてくれない

これは今回作ったものの問題ではないのですが、Slackに一度に大量の/feed subscribeを投げたせいか、今朝実際にフィードを登録したのですがアドベントカレンダーの初日の記事がまだSlackのチャンネルに流れてきていません。

設定では登録されているので大丈夫だとは思うのですが、最終的な確認ができていないのでまだ不安です……。

追記:日付変わったら来始めました。おそらくRSSフィードの時刻が0時になっていたために最初のエントリの検知に失敗していたように見えます。

まとめ

というわけで、Webスクレイピングができるとちょっとした自動化がささっとできるようになるので、手札として持っておくと便利です。またこういう雑なバッチ処理を適当に動かすのにFaaSは極めて強力なので、合わせ技で使っていくと良いかなと思います。

 

セキュリティ・キャンプ全国大会2020 応募期間延長!

セキュリティ・キャンプは、ITつよつよ人材の発掘と育成を目的とした取り組みです。毎年夏に行っている全国大会を、今年はオンライン形式で実施します。

www.ipa.go.jp

応募期間が当初は25日までだったのですが、大人の事情でちょっとだけ伸びて

2020-09-03 23:59 JST

になりました!

単に例年の講義をオンラインでやるというだけでは無く、10月から12月にかけて毎週ペースで講義が進むため、講義ごとの事前学習に時間が掛けられたり、特に集中コースのハッカソンは全体の開発期間が大幅に伸びたりなど、今回オンライン開催だからこそできることがたくさんあります。

また、今年度参加した人でも、来年度以降の「セキュリティ・キャンプ全国大会」にも応募可能です。

今からでも遅くないので是非応募をお待ちしています!

今年度のトラック構成おさらい

今年の全国大会オンラインは、以下のトラック構成です。

  • A【コンテストとワークショップトラック】 (選択コース)
  • B【プロダクトセキュリティトラック】 (選択コース)
  • C【脅威解析トラック】 (選択コース)
  • D【課題駆動トラック】  (選択コース)
  • L【暗号ファジングトラック】 (集中コース)
  • X【IoTセキュリティトラック】 (集中コース)
  • Y【システムソフトウェア自作トラック】 (集中コース)
  • Z【プラットフォームセキュリティトラック】 (集中コース)

www.ipa.go.jp

担当講義:クラウド時代における分散Webシステムの構成とスケーリング

それと、今年もクラウドを上手く使う講義を担当します。

よろしくです!

www.ipa.go.jp

 

 

IoTデータ処理の考え方

世の中いろいろな「IoT」がありますが、突き詰めればデバイスから上がってくるデータを処理して何かを実現するのがIoTです。IoTにおけるデータ処理を考える上で、ネットワークプロトコルの設計指針を参考にするとうまく整理できます。

シンタックス、セマンティクス、そしてコンテキスト

ネットワークプロトコルを設計するときにはシンタックス(Syntax; 文法)とセマンティクス(Semantics; 意味)に分けて考えます。そしてネットワークプロトコルの外側にあるコンテキスト(Context; 文脈)に基づいて処理が行われます。

それぞれ掘り下げていきます。

シンタックス:どのようにデータをやりとりするか

どのようにデータを送り、受け取るかという「文法」を決めるのがシンタックスです。

たとえばHTTPであれば、HTTPクライアントがHTTPサーバにTCPで接続し、以下のフォーマットでリクエストを送り、

[HTTPメソッド](空白)[URI](空白)[プロトコルバージョン]
(いくつかのヘッダ)
(空行)
(もしあればメッセージ本体)

HTTPサーバから以下のようなレスポンスが返ってくる、というのがシンタックスに相当します。

[プロトコルバージョン](空白)[ステータスコード](空白)[テキスト]
[いくつかのヘッダ]
(空行)
(もしあればペイロード本体)

ステータスコードは3桁の整数であるまでは決めますが、どの数字がどんな意味を持つか、例えば404が「URIが存在しない」を表すなどはシンタックスでは決めません。

これをIoTの分野で考えてみます。

Case 1: MQTT

MQTTでセンサーのデータを集める場合を考えてみます。

性能やコストをそこまで詰める必要が無い場合、後々の拡張性などを考えてメッセージに直接値を埋め込むのでは無く、JSONなどの汎用フォーマットに入れて送ることが多いかと思います。また、デバイスのIDをトピック名に入れて識別できるようにします。

そうすると、このようなシンタックスが考えられます。

  • トピック名は「sensors/{デバイスのID}」
  • ペイロードはJSON形式で符号化

シンタックスの段階ではどのようなセンサーがありどんな値を含めるかなどは決めず、セマンティクスに任せます。

f:id:nekoruri:20200811034013p:plain

JSONオブジェクトに含まれるキーや値の型までをシンタックスとみなす場合もありますが、この記事ではもう少し緩いところまでをシンタックスとみなしています。あくまでシンタックスかセマンティクスかは分類方法でしかないので、視線の先をどこに置くかでその境目は変わってきます。

Case 2: LoRaWAN

LPWAで代表的なLoRaWANでは、一番小さな設定ではメッセージサイズが11バイトになります。11バイトに集めたいデータを全て詰め込む必要があるため、1ビットは血の一滴と無駄にすることができません。

たとえばGPSトラッカーからデータを集めたい時に、以下のようなシンタックスが考えられます(この例はソラコムさんの記事をもとにしました)。

  • 先頭1バイトはヘッダ
  •  ヘッダの上位2bitはステータス(0~3)
  •  ヘッダの下位6bitはバッテリー(0~100を1bit右シフトして符号化)
  • 次の4バイトは緯度
  • 次の4バイトは経度
  • 次の2バイトは高度
  • 緯度経度海抜は浮動小数点数とし、ビッグエンディアンで符号化

f:id:nekoruri:20200811034827p:plain

MQTTの例と同様に、ステータスの意味はセマンティクスの範疇となります。

 

このように、データの形を決めるのがシンタックスです。たとえばSORACOM Beamバイナリパーサーはシンタックスの変換と考えることができます。

セマンティクス:データをどのように扱うか

受け取れるデータの形を決めるのがシンタックスなら、受け取ったデータの意味を決めるのがセマンティクスです。

先ほどのHTTPならば、受け取った3桁の数値が「404」ならば指定したURIにデータが存在しない、「301」ならばレスポンスのヘッダ「Location」で示されたURIに移動してしまった、というようなことを決めます。また、どのようなリクエストメソッドがあるのかもセマンティクスに相当します。

先ほどのIoTの例でセマンティクスを考えてみます。

Case 1: MQTT

実際のセンサーデータはJSON形式で符号化することがシンタックスで決まっていますが、その中身はセマンティクスに委ねられました。

今回使うセンサーでは、温度と湿度が取得できるので、temperatureとhumidityのキーでそれぞれのセンサーで取得した値を入れる事にします。温度は摂氏、湿度は100分率で表現します。このように数字の意味を細かく決めていきます。

Case 2: LoRaWAN

ステータスは、以下のような値を出すこととします。

  • 0: GPS位置情報の取得ができなかった
    (後に続く緯度経度高度のデータは正しくない)
  • 1: GPS位置情報の取得に成功した
  • 2: 未定義
  • 3: 故障している

バッテリーはフル充電時の最大電圧と、停止直前の最小電圧の間を100分率で表します。

緯度経度高度は、GPSで使われるWGS 84測地系で表現された値を利用します。緯度経度はともかく、高度はWGS 84測地系では地球をきれいな楕円体とみなしたときの表面からの高さになるので、実際の標高である平均海水面との差を計算したりするなどは、データを受け取った側の責任になります。

このように決めていくことで、ようやくセンサーで集めた情報が、正確にその意味をくみ取って利用できるようになります。それぞれの「値」に対してそれをどのような意味を持っているのかを細かく決めていくのがセマンティクスの役割です。

コンテキスト:文脈の上でデータの価値を見いだす

ここまでで、IoTデバイスから上がってきたデータをしっかり解釈することができましたが、それを具体的に役に立つようにするにはもう一手間必要です。それがコンテキスト(文脈)による価値付けです。

コンテキストも、細かく分けると2種類があります。

データの履歴と状態遷移

例えば温度センサーで30度という値を受け取ったとします。温度に応じて冷房のon/offを制御したいとき、たとえば部屋の温度が29度から30度に上がったときには冷房の電源を入れ、27度まで下がったときに冷房を止めて欲しいわけです。また、センサーからの値には誤差が含まれるため、移動平均なども計算したいです。

f:id:nekoruri:20200811035626p:plain

これを実現するには最新の温度データだけがあっても駄目で、過去のデータや冷房の状態があったうえで新しいデータを使って判断する必要があります。

このようにデータの履歴や状態をつかった処理を行うため、データを収集した側で様々な道具を使う必要があります。たとえばAWS IoT Eventsなんかはそのためのエンジンですし、Azure FunctionsやAWS LambdaなどのFaaSを使って自分で実装することもできます。

qiita.com

www.slideshare.net

外部のデータ

GPSで測位した位置情報が分かったとして、その座標を使って何かを行うためには、たとえば登校前後に親御さんにメールする「みまもりサービス」であれば自宅と学校の座標など、そもそも他のデータと組み合わせる必要があります。

先ほどの冷房on/offであれば、そのセンサーの所有者が設定した目標温度も必要になります。

いわゆるETLの範疇にもなりますが、リアルタイムデータを別のマスタデータとJOINするようなケースでは、Azure Stream AnalyticsやAmazon Kinesis Data AnalyticsなどでリファレンスデータとJOINしたりできます。

docs.microsoft.com

docs.aws.amazon.com

データ量によってはリアルタイムで処理することにこだわらず、RDBMS等に放り込んで閲覧時やバッチでJOINしても良いでしょう。

このように、IoTデバイスからのデータは、ただそこに存在するだけでは価値が発揮できず、過去のデータ・状態や外部のデータと紐付けることでようやく様々な役に立つことができます。逆に言えば、この領域で何をやるかこそが「IoTを活用する」ということそのものと言えます。

まとめ

IoTにおけるデータ処理は全体をふわっと見ると複雑ですが、データの表現方法を決めるシンタックス、その意味を細かく決めるセマンティクス、そこから価値を見いだすコンテキストに分けて整理すると分かりやすいです。

7月のまとめ

40歳になりました

f:id:nekoruri:20200718000002j:plain f:id:nekoruri:20200722233215j:plain

Amazon欲しいものリストからもたくさんプレゼントをいただいてしまいました。個人的な方針で個別のお名前を出す事は割愛させていただいているのですが、みなさまありがとうございます、とても嬉しかったです。

このお礼は世界への貢献をもって返していきます。

バケツはスタッフがいただきました。

f:id:nekoruri:20200728143714j:plain

例年通りいきなり!ステーキのタダ肉300gも食べました。

f:id:nekoruri:20200728161306j:plain

30代の10年間は、エクストーンへの転職に始まり、サイバーエージェント、WHEREと3社(正確にはパシャオクを入れて4社)を渡り歩きつつ、たくさんの方々のおかげで色々貴重な経験をさせていただいています。

次の10年は若者の手を引きながら世界に恩を返していけるよう健康にがんばります。

SecHack365 2020年度

sechack365.nict.go.jp

6月末に選考結果の発表があり、7月からいよいよ2020年度のSecHack365が本格始動しました。今年度も開発駆動コースの仲山ゼミ担当として、世界を変える若者の手助けをしていきます。

今年度は全国行脚ができない中ではありますが、SecHack365オンラインの初年度ぐらいの感じでがんばっていきたい感じです。

Microsoft MVPアワード (Azure)

f:id:nekoruri:20200803230145j:plain

自分としては正直アウトプット便秘ではあるのですが、4期目受賞することができました。

カンファレンスや同人誌即売会がオンライン化したりする中ではありますが、自分らしいアウトプットの形を模索しつつ、あらためて再始動フルスロットルで頑張っていきます。

動画配信

なんか色々機材が整ってしまったこともあり、迷走しつつ色々楽しんで手札を増やしていこうと思っています。

www.youtube.com

www.youtube.com

艦これ

E1甲、E2乙、E3甲、E4乙までやったところでボーキが尽きました。

f:id:nekoruri:20200803233447p:plain

米帝になりたいです。

ニューノーマルWFH

現在社内ニートのくせに、ストレス発散で色々揃えてしまったので、反省のために自慢していきます。

インスパイア元はこちらです。

note.com

現状

f:id:nekoruri:20200619002259j:plain

ちなみにここは元々押し入れでした。

椅子

某勉強会(もはや互助会かもしれない)Slackにてたまたまスケベ椅子の話題が出たのですが、そこから色々話題が盛り上がって10万円前後と言われる人権椅子がオフィスバスターズ等で中古を狙うと3-5万円ぐらいで買えることがわかりました。

で、見つけたのが、アーロンチェアで有名なハーマンミラー社のセラチェアが約3万円という案件です。というわけで、朝一に車で駆けつけてささっと買ってきました。

www.officebusters.com

このセラチェアは、ウレタンでもメッシュでもなく、セルラーサスペンションというプラスチックの小さな丸型パッドがハニカム上になっているもので、座面が堅くちょっと人を選ぶところはありますが、ハーマンミラー製お得意の様々な調整機構はたくさん付いていますし、少なくとも私にはちょうど良かったです。

www.ofnt.co.jp

買ってきたら、その日のうちに近くに居る奴がわらわらとうちまで座りに来て、結局某勉強会Slackメンバーだけであと数台売れて速攻で売り切れていました。

デスクトップ(物理)

もともと、サンワダイレクトの半額セールで2つの机をL字に置いていました。

direct.sanwa.co.jp

direct.sanwa.co.jp

ただこれ奥行き55cmというのがかなりネックで、ディスプレイとキーボードを置くと前後にまったく余裕が無い状態で、ノートPCを使うときはキーボードを片付ける必要がありました。

というわけで、IKEAで天板だけ買ってきて上に載せちゃいました。

www.ikea.com

奥行き55cmから75cmになっただけですが、体感は3倍ぐらいになって別次元になりました。5000円でこの満足度が得られるならもっと早くやれば良かった。

フットレスト

写真には写っていませんが、足下にフットレスト(足置き)があります。

これがあると椅子をちょっと高めにしてディスプレイの高さと目線があうので、かなり快適になりました。

マイク

コロナ禍が始まった早々にとりあえず必要そうだということでピンマイクを買いました。これはServerless Communityのメンバーから紹介してもらったやつです。

ただ、元々自宅にはアームスタンド付きコンデンサーマイクのPod Pack 1を買っていたので、結局Serverless Meetup収録の1回だけで、カバンに入れっぱなしです。

ちなみにPod Pack 1はこれはこれでおすすめです。

オーディオインターフェース

マイクだけならPod Pack 1でまったく不満がなかったのですが、自宅に居るとなんとなく色々やりたくなってきた結果、某勉強会Slackで聞き回ったりして、これを買いました。 

Steinberg 6 x 4 USB 2.0 オーディオインターフェース UR44

Steinberg 6 x 4 USB 2.0 オーディオインターフェース UR44

  • 発売日: 2014/01/27
  • メディア: エレクトロニクス
 

家に電子ピアノとかもあるので、そのあたりでMIDIとかでも色々やりたいなあとか色々夢を詰め込んだら少し上の機種を買ってしまいました。物欲やばいですね。

マイクはPod Pack 1がUSB直出しでXLRが食えず接続できていないので、今のところただ遅延の少ないヘッドホンアンプになっています。

カメラ

ウェブカメラが大昔の画質低いものしか持っていなかったので、ちょうど余っていたRakuten miniにiVCamを食わせてカメラとして固定運用しています。UN-LIMIT?なにそれ。常時Wi-Fi接続ですが何か?

小さすぎて斜めにマウントしているのがチャームポイントです。

ライト

何が良いか判らなかったので安いのを適当に買いました。特に不満は無いです。

ディスプレイ

1台もらってきて3台になりました。ありがとうございます。

まとめ

環境構築で満足してしまうのはエンジニアの性ですよね!

懐かしのCGI掲示板スクリプトをAWS Lambda+EFSで動かしてみた

AWSにはフルマネージドなNFSファイルシステムを提供するEFSがありますが、AWS Lambdaからマウントできるようになりました。

aws.amazon.com

これをうまく使うと、ファイルシステムへの保存を前提とした古いアプリケーションを楽にクラウドにリフト(移行)することができます。

というわけで、さっそく、前世紀からインターネットで遊んでいた人でお世話にならなかった人は居ないであろうCGI RESCUE様のminibbs.cgiこと簡易BBSをサーバーレスに動かしてみました。みんなminibbs.cgiの書き換えでPerl覚えましたよね?

動いているもの

f:id:nekoruri:20200618020439j:plain

df6mbqlkt7.execute-api.ap-northeast-1.amazonaws.com

※インターネット老人会の治安が悪いので注意
※ここはそのうち忘れないうちに落とします。

レポジトリ

github.com

しくみ

まず、今回の新機能を使うためにEFSのボリュームを作ります。この手順は上のページに書いてあるそのままで大丈夫です。完全に同じ手順でやると /mnt/msg にマウントされるので、その下にデータファイルが置かれるように設定します。この当時のCGIスクリプトなので、minibbs.cgiを直接編集して上の方で変数に設定します。

$tmp_dir = '/mnt/msg';

これで、あとはこのminibbs.cgiをAWS Lambdaで動くようにすれば良いわけです。

そしてこのPerlのCGIスクリプトを動かすにはいくつかの道具を組み合わせていきます。

  1. カスタムランタイムでPerlを動かす AWS::Lambda
  2. AWS LambdaのインターフェースをPerl標準のPSGIに変換する AWS::Lambda::PSGI
  3. PSGIをCGIインターフェースに変換する Plack::App::WrapCGI

この3段階をハンドラ関数としてまとめたものが、上のレポジトリにあるhandler.plです。

use utf8;
use warnings;
use strict;
use AWS::Lambda::PSGI;
use Plack::App::WrapCGI;

my $app = Plack::App::WrapCGI->new(script => "$ENV{'LAMBDA_TASK_ROOT'}/minibbs.cgi", execute => 1)->to_app;
my $func = AWS::Lambda::PSGI->wrap($app);

sub handle {
    $ENV{'TZ'} = "JST-9";
    return $func->(@_);
}

注意事項として、正しく動かすためには以下の設定も必要です。

  • minibbs.cgiに実行権限が必要なので、chmod +x minibbs.cgi してからZIPファイルでデプロイが必要(コンソールからの編集不可)
  • 1行目のshebangが配布状態だと/usr/local/bin/perlになっているので、/usr/bin/perlに変更する
  • URLをminibbs.cgi内に設定する必要があるので、先にAPI Gatewayを設定する(運用でカバー)
  • あらかじめ空のデータファイルが必要なので、初回だけhandler.plでtouch /mnt/msg/data.cgiとかやっておく(運用でカバー その2)

このあたりをクリアすると、前世紀に普通に使っていたminibbs.cgiを、ほぼそのまま一般的な設定項目以外いじることなく、令和時代のサーバーレス環境AWS Lambda上で実行することができました。

運用でカバーした2点も、minibbs.cgi自体を少し直せばもちろん対応できるわけですが、今回はそういったプログラム本体の修正を一切せずに、そのままAWS Lambda上で動かす事ができるというデモンストレーションなので、上で紹介したperlのパスと変数以外は一切変更していません。

おそらく性能もさほどでないと思われますし、古いアプリケーションをそのまま動かしているので脆弱性対応は依然として必要ですが、まずは手軽に今動いているサーバ環境の運用コストを下げるために、このようなサーバーレス+共有ディスクの構成は極めて有用です。あくまで「リフト&シフト」のリフト策として、クラウドシフトのためのリソースをひねり出すために使うのが望ましいですが、カードの一つとしてこういったことがすぐに実現できるんだ!という紹介でした。

宣伝

nekoruri.booth.pm

AWSによるサーバーレスアーキテクチャ

AWSによるサーバーレスアーキテクチャ

  • 作者:Peter Sbarski
  • 発売日: 2018/03/14
  • メディア: 単行本(ソフトカバー)
 
CGI & Perl ポケットリファレンス (Pocket reference)

CGI & Perl ポケットリファレンス (Pocket reference)

 

 

AWS LambdaとDynamoDBがこんなにツライ時代ではない

ありがたいことに、3年前に#ssmjp 2017/06で話したスライド

をTwitterで紹介して頂いた*1 ようで、当時から大幅に改善しているところを振り返りたいと思います。あと、ついでに最近やっているAzureに関しても少し触れていきます。

サーバーレスアーキテクチャ #とは

f:id:nekoruri:20200607114509p:plain

当時はこう説明したのですが、今でもそんなに悪くない表現かなと思います。

f:id:nekoruri:20200607114853p:plain

書籍は現在「Serverlessを支える技術 第3版」まで出ていますので、BOOTHからどうぞ(隙あらばダイマしていく方針)。

サーバーレス三種の神器

f:id:nekoruri:20200607115055p:plain

今このスライドを作るなら、認証認可の話を入れるかなと思います。システム内のAWS IAMとクライアント側のCognitoどちらも重要です。

ちなみにAzureを含めておさらいすると、こんな感じの対応になります。

勝手にスケールするデータストア

  • Amazon DynamoDB、Amazon DocumentDB ↔ Cosmos DB
  • Amazon S3 ↔ Blob Storage、Data Lake Storage Gen2
  • Amazon Aurora Serverless ↔ SQL Database serverless

勝手にスケールするソフトウェア実行環境

  • AWS Lambda ↔ Azure Functions
  • (AWS Fargate ↔ Azure Container Instances)

それらをつなげる枠組み

  • Amazon Kinesis Streams ↔ EventHubs
  • Amazon Simple Queue Service (SQS) ↔ Queue Storage、Service Bus
  • Amazon Simple Notification Service (SNS) ↔ EventGrid
  • AWS Step Functions ↔ Logic Apps、Durable Functions
  • Amazon API Gateway ↔ (Functions組み込み機能)、API Management

f:id:nekoruri:20200607121752p:plain

この辺は今もあまり変わらずです。

この構成の肝は、クラウドサービスの構成と、関数のデプロイを完全に分けていることです。AWS SAMやServerless Frameworkで普通にやると、関数本体がCloudFormationスタックに入ってしまい、リアルからデータが上がってくる「本番環境」で高速に試行錯誤を繰り返すIoTビジネスの特性とちょっと合わないと感じたので、ここを切り離しました。ただApexがメンテされなくなってしまったので、今ならlambrollですね。

Azureでも同じように、全体の構成をTerraformで行い、関数は別レポジトリからデプロイしています。

サーバーレスあるある選手権 Lambda編

f:id:nekoruri:20200607125048p:plain

f:id:nekoruri:20200607125146p:plain

ログそのものは現状でも余り変わっていないのですが、追いかける部分に関してはAWS X-Rayの登場でだいぶ改善されました。AWSサービスへの外部リクエストは何もしなくても記録されますし、外部サービスや重い内部処理をプロファイリングしたければサブセグメントを生成してあげればX-Rayの時系列トレースグラフに表示できます。

Azureの場合はVSCode拡張からリアルタイムでログを見ることができます。Application InsightsからX-Rayと同じようにサービス間のコールグラフやサブセグメントごとのトレースグラフが見られるのも同じです。

f:id:nekoruri:20200607130253p:plain

ここは今でも変わっていませんが、その後運用して判った部分としてはmemory_sizeの調整になった時点で消費メモリ量が問題になることはあまりない(ざっと見て最大消費量より多ければ良い)ので、余程メモリ変動の大きい処理をしていないのであれば、カスタムメトリクスだして追いかけるほどではないです。逆に言えば、メモリ変動が大きい処理があるのであれば、どこかで仕組みを変えて処理量のほうを平準化できないか考えた方が良いです。

f:id:nekoruri:20200607130738p:plain

f:id:nekoruri:20200607131145p:plain

このスライドの中で状況がもっとも変わった部分です。なんとかしてくれました。

そもそもVPC環境でのLambda起動の仕組みが大幅に改善されました。

ENIを生やしたインスタンスを個別に作成していたものが、基盤側で用意した共有ENIにNATされるようになったので、15秒ほどかかっていたのが1秒前後になりコールドスタートが実用的な範囲になりました。

また、RDSへの同時接続数も、Lambda側で同時実行数が設定できるようになり、RDS側にもフルマネージドのコネクションプーリングRDS Proxyが提供されたので、問題にならなくなりました。

そもそもVPCを使わずAurora ServerlessのData APIを使うという選択肢もできました。

とはいえ、依然としてRedisなどはVPCの中にしか作成できないので、VPCを廃絶できないのがおしいところではあります。

サーバーレスあるある選手権 Kinesis編

f:id:nekoruri:20200607132542p:plain

f:id:nekoruri:20200607133153p:plain

f:id:nekoruri:20200607133208p:plain

ここも大幅に改善されたポイントです。

待ち時間を指定できるようになったので、データが少ない場合の処理効率が良くなりました。

またKinesis Data Streams側のシャード数と掛け算でLambda側の「Parallelization Factor」で並列実行できるようになったため、時間が掛かる処理をぶら下げたときにシャード数まで引き上げずに済むようになったのも地味に大きなポイントです。これまではKinesis側のリミット(1MB/sまたは1,000レコード/秒)より大幅に少ないデータしかないにもかかわらず、シャード一本月1500円(14.04USD)が掛かっていました。

f:id:nekoruri:20200607140510p:plain

きました。使っています。

f:id:nekoruri:20200607140619p:plain

東京には来てくれたのですが、結局うまく処理にはまらずに現状使っていません。

どちらかというと、Apache Flinkで分析処理を実装できるようになった方が個人的にインパクトが大きいです。

イベントソーシングパターンなど、ストリーミングデータに対してステートを持った継続処理を実装するユースケースがふえているのでもっと活用事例が増えて欲しいところです。

サーバーレスあるある選手権 DynamoDB編

f:id:nekoruri:20200607133813p:plain

f:id:nekoruri:20200607140330p:plain

KVSベースでの設計がRDBに比べて違うノウハウが必要となるのは以前通りです。これはもうキーベースで分散するデータストアである以上は逃げられません。とはいえ、サーバーレス開発の普及によって世の中の情報もだいぶ増えてきたので、3年前よりは実感的にはだいぶ始めやすくなったのではないでしょうか。

f:id:nekoruri:20200607133959p:plain

f:id:nekoruri:20200607134017p:plain

f:id:nekoruri:20200607134031p:plain

DynamoDBのコスト問題はまだまだ苦労する部分ですが、オンデマンドキャパシティーモードが用意されたので、リクエスト数が急激にスパイクするようなケースでも安心して使えるようになったのは大きいです。

ただ、オンデマンドキャパシティーモードの方が「単価」が大幅に高いため、常時リクエストがあるようなケースではかえって高くなってしまうこともあり、そこはユースケースと運用コストや障害リスクに見合った選択が必要です。

f:id:nekoruri:20200607135148p:plain

バックアップは完璧に用意されました。オンデマンドもPITRもあります。

注意としては、あくまでバックアップはDynamoDBサービス内にリストア可能な形で保存されるだけです。データ自体をCSVやJSONなどでエクスポートしたい場合は、これまで通りDataPipelineをつかったり、ひたすらスキャンでページを手繰る必要があります。

まだまだ道半ば

f:id:nekoruri:20200607142046p:plain

結局DynamoDBだけでは厳しくなったので、現在ではRedisも併用しています。

このあたりは、先日のServerless Meetup Tokyo #16でも話しました。

f:id:nekoruri:20200607142209p:plain

現在は、お客様や大人の事情に合わせて、上でも書いたとおりAzureとAWSで両刀でやっています。GCPでもだいたいできそうな感触はありますが、案件ください

f:id:nekoruri:20200607142221p:plain

3年前と比べると、大きな障壁はかなり取り除かれ、頑張ればだいたい問題ない、とはっきり言えるところまで来ました。

昨今、ソフトウェア開発の手法で社会や組織を変革し続けるデジタルトランスフォーメーションの波が来ていますが、特にIoTではとにかくサービスデリバリの高速化が重要です。サーバーレスアーキテクチャという選択肢で正解だったというのがこの3年間の最終的な評価です。

宣伝

 

 

AWSによるサーバーレスアーキテクチャ

AWSによるサーバーレスアーキテクチャ

  • 作者:Peter Sbarski
  • 発売日: 2018/03/14
  • メディア: 単行本(ソフトカバー)