ラベル Web service の投稿を表示しています。 すべての投稿を表示
ラベル Web service の投稿を表示しています。 すべての投稿を表示

2018年9月11日

続・気象庁防災情報XMLの受信と周辺サービスをGCPに移行した話

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

まず、北海道胆振東部地震で被災された方にお見舞い申し上げます。
今回の地震は熊本地震と同様の最大震度7が観測された為、自分自身が2年前に体験した熊本地震の時の様子を思い出しながら、今必要な情報は何か?を考えて仕事をしていました。

それにしても、まさか札幌にお天気カメラを設置しに行った3日後に大地震が発生するとは思ってませんでしたが...

設置の翌日、台風が北上してくる中、15時の便にフライトを振り替えて新千歳空港から飛び立ち、17時ごろに羽田についたら以降の便が全便欠航していた&翌日(5日)も台風による悪天候でダイヤが乱れていたので、振り替えていなければ人生で2度目の震度7クラス地震を体験するかもしれないところでした...

さて、今回は、気象庁防災情報XMLの受信と周辺サービスをGCPに移行した話 の続きのお話です。
※これは防災情報デザインと配信に関する個人的な研究の一環として私費でやっている物の話です。

あれから半年程度運用を続けてきましたが、全体の運用に毎月1500円〜1700円の費用が掛かっていました。(それでも十分に安い)

この「全体」というのは、気象庁XML受信のためのサブスクライバ&閲覧のためのビューアをホストしているAppEngine、XMLやJSON、画像保存のためのStorage、QUAKE.ONEをホストしているFirebase、その他内部的な処理に使っているCloud Functions (15個の関数)、Pub/Sub (5個のトピック)、JMAXMLのメタデータや地震情報、気象警報・注意報のステートを保存しているDatastoreを含みます。

例えば、2018年6月に掛かった実際の費用はこんな感じ。


全体の費用として一番大きいのが、Compute Engine g1-smallインスタンスx1で毎月2000円から継続利用の割引で約1400円と実に全体の80%以上。
このインスタンスは、Twitterへの投稿やPushbulletでのプッシュ通知の際に添付される震源・震度マップ画像を、headless Chrome&PuppeteerでレンダリングしてCloud Storageに保存するためにだけに使用されているものです。
f1-microインスタンスでは、CPUバーストが効いた状態でレンダリング(960x540)に10秒以上掛かる上に、地震が頻発すると何度目かのレンダリングでCPUバーストが効かずに実行がタイムアウトしてしまうという残念なことが発生したため、g1-smallインスタンスで運用していました。

ところが、2018年8月のアップデートで、Cloud FunctionsにてNode.js 8系が利用できるようになると共にheadless Chromeが利用可能であることがアナウンスされました。

Introducing headless Chrome support in Cloud Functions and App Engine | Google Cloud Blog

これに伴って、構成を以下のように変更。


(クリックで拡大してご覧ください)

大きな変更点は以下の通りです。

1. 画像のレンダリングをCloud Functionsで実行
2. 画像レンダリング用のg1-smallインスタンスを廃止
3. WebSocket配信サーバをConoHaからf1-microインスタンスに変更

これにて、毎月の利用額がCloud Storageのオペレーションとデータの保管に掛かる費用のみとなり、200円以下となりました。
(f1-microインスタンス1台はAlways-freeなので0円)

Cloud Functionsでのレンダリングは、asia-northeast1のメモリ2GBで最短3900ミリ秒(ページの読み込みのために入れたwait 3000ミリ秒を含む)、最大でも7秒程度とブラウザを利用した画像の生成(かつ無料枠範囲内)の方法としては優秀。
もちろん、スピードが重視されるような防災情報配信用途としてはとてもとても遅い(ゲヒルンで製作・運用している描画エンジンはフルHD1枚200ミリ秒程度)ので、あくまで実験・実証としての利用、またはスピードが求められない場面での利用に限られるのですが...。

ひとまず、ConoHaに全てを載せていた時の価格(毎月1000円程度)と比較して1/5くらいになったので、クラウドは上手く使えば安くなりますよ事例として記しておきます。
ただし、これはアクセス数に大きく依存するので、今くらいの利用者数であれば200円で済むものが、利用者が数倍になればGCPに支払う費用も数倍、数十倍以上になり得るということです。
あくまで個人的な実験・試行というところでの運用を続けているので、流石にそういう状況になったら続けることはできませんが、こういった複数の要素を使ったサービスを数十円、数百円のレベルから始めることが出来るのがGCPやAWS、Azureといったクラウドのメリットということでしょう。

2018年3月26日

気象庁防災情報XMLの受信と周辺サービスをGCPに移行した話

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

そろそろ何かアウトプットしておかないとNo Activityマンになってしまうと思いつつも色々やることは山積みで筆の捗らない今日この頃、みなさんいかがお過ごしでしょうか。

さて、2015年12月にEVI 地震火山詳報を公開してから約2年と3ヶ月(その前身の桜島詳報から数えると3年7ヶ月)が経過しました。
実は、2017年10月頃のConoHaの障害によりサブスクライバが長時間止まってしまい、気象庁のPuSH配信から外されたため同月よりEVIのサービスが停止しておりました。
この際、本業(ゲヒルンUN_NERVへ作画提供)でも震源・震度地図の作画エンジンを作っているので完全にサービスを畳んでしまおうかとも思ったのですが...
振り返って周りを見てみれば、インタラクティブな震源・震度マップに挑戦している方が意外と少なく、作画方法も本業の仕組みとは全く異なるので 防災情報デザインに関する異なるアプローチの研究 ということで緩く継続してみようと思い立った訳です。

#防災情報デザイン、特に地震に関するものに関しては、様々な方が主にUN_NERVで提供されている地図デザインをパクって何度も何度も車輪の再発明をされていますが、みなさん少しは配色を変えてオリジナリティを出したり、「俺ならこうする!」といった伝え方の工夫を取り込んでみてはいかがでしょうか...? 芸が無さすぎて全くつまらんです。

EVI 地震火山詳報のサービスと後ろ側については、以前書いた記事をご覧ください。

地震とか火山噴火情報を閲覧できるWebサイトを作った (2015年12月)

上記の記事の通り、EVIは後ろ側がかなり複雑に絡み合っており、機能追加や改修をするにも面倒になっていました。
また、受信したXMLや生成したGeoJSON、画像の保管も同じインスタンス内に入っていたため、ある一定期間ごとに古いデータを削除する等のメンテナンスが必要でした。

...そこで、今回EVIを改修するにあたり以下の目標を立てて移行計画を実行することにしました。

1. 出来る限りマネージドなクラウドサービスに載る(俗にいうサーバレス)システムにする
2. 出来る限り最新の設計・構築方法、技術を用いる
3. デザインをなんかイケてる感じにする←重要

ということで、これらを念頭に置きつつ、隙間時間を使って3ヶ月ほどで作ったものがこちらになります。(冒頭のスクリーンショットのサービス)

QUAKE.ONE
https://quake.one/

#火山要素が消えたことには目をつぶってください

Twitterは以前のIDのまま Prioris_EVI を使っています。

Pushbulletも以前のままです。

日本国内で発生した全ての震源・震度情報
earthquake_jp

日本国内で発生した震度3以上の震源・震度情報
earthquake_int3over

さて、ここからは技術的なお話。

EVIからの進化ポイントは以下の通り。

1. 小さな画面を持つデバイスにおいて、操作可能な地図が非常に小さくなる問題を解決
→どの画面サイズのデバイスにおいても全画面で地図を表示し、情報をマップ上に配置する新しいデザインを採用

2. OpenLayersのバージョンアップ
→OL3から最新のOL4へ移行

3. ページを動的から静的生成に変更、SPA(single-page application)化
→地震発生をトリガーにしてレンダリング用のJSONをあらかじめ生成

4. Twitter、Pushbulletにて配信する画像形式の震源・震度地図のデザイン変更
→画像の生成方法もwkhtmltoimageからPuppeteer + Headless Chromeに刷新

また、これに伴ってサブスクライバから後ろも全て刷新しました。
構成図は以下の通り。(横に非常に長いので、拡大してご覧ください)


使用したサービスは以下の通り。

Google Cloud Platform
・App Engine
・Compute Engine
・Cloud Functions
・Cloud Datastore
・Cloud Storage
・Cloud Pub/Sub
・Firebase Hosting

地震が発生して「震源・震度に関する情報」が流れてきた時のパターンを簡単に説明すると...

1. 気象庁からPubSubHubbubでJMAXML publishing feedを受ける
2. atomを解析してEntryを取り出し、Task Queueに投げ入れ、Entryの内容をDatastoreに書き込む
3. WorkerはXMLを取得、XMLスキーマを適用してJSON形式に変換、XMLとJSONをStorageに保存し、JSONをPub/Subに流す
4. 3種のPub/Subトピックのうち地震に関係するトピックにぶら下がっているCloud Functionsが実行、Datastore内の地域コード対地域重心座標に基づいてGeoJSONを生成してStorageに保存、概要をPub/Sub(topic: quake-one)に流す
5. Pub/Sub(topic: quake-one)にぶら下がっているCloud Functionsが実行、Puppeteer(+Express)が待ち受けているGCEインスタンスに画像生成リクエストを送信
6. Headless Chromeで画像用ページを表示して撮影、Storageに保存
7. 画像生成リクエストが成功すると、当該eventIDの地震の概要と画像のURLをPub/Sub(topic: quake-one-with-image)に流す
8. Pub/Sub(topic: quake-one-with-image)にぶら下がっている各Cloud Functionsが実行、PushbulletやTwitterへ投稿
9. QUAKE.ONE はStorageを参照し、概要の入ったJSONとインタラクティブ地図描画用のGeoJSONを取得、JavaScriptでレンダリング

以前の複雑に絡み合った状態からすれば、随分とメンテナンスしやすいシステムへと変わりました。

AppEngine、Firebase Hostingは自動的にLet's EncryptでSSL証明書を更新してくれるし、しっかりキャッシュ、CDNが効いてくれます。
Storageは、ライフサイクルを設定することで、古いXMLやJSON、画像データを自動的にNear line→Cold lineと安価なストレージに移行、あるいは削除してくれます。
Cloud Functionsは実行時課金で、気象庁XMLをトリガーにして実行する程度の回数では全て無料範囲内に収まります。
唯一、画像を生成するためのPuppeteer + Headless Chromeが入っているGCEインスタンスだけは面倒を見てあげなければなりませんが、これも永続化が必要なデータやステートは持っていないので管理は楽々です。

さらに、副産物としてJMAXML JSON Viewerも出来ました。
こちらはデータ保存期間が浅い&検索が弱いので受信状況の確認程度用です。
商用利用は禁止ですので、お仕事で使いたい方はゲヒルンの気象庁XML Viewerをご契約ください。

というわけで、出来る限り新しめの手法でマネージドな感じのイケてるサービスが出来ました。

めでたし、めでたし。(終)

追記:その後の話を書きました。
続・気象庁防災情報XMLの受信と周辺サービスをGCPに移行した話

2016年6月4日

秋月で買える電子部品でリスト作成して色々できるサービスを作った

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

大きな地震があったりでバタバタしてたら4月5月と過ぎて6月になっていました...
というわけで2か月ぶりのブログ更新。

タイトル通り、秋月電子通商で扱っている電子パーツでパーツリストを作成、公開、共有、そして秋月の買い物かごに一括して放り込めるWebサービスを作りました。

その名も AkiCart
http://aki.prioris.jp/
(ちょっとダサいネーミングだったかも)

そう、秋月通販をよく使っている人は知っている... 秋月の買い物かごはセッション切れで放置してるとすぐに消えることを...

そこで、このサービスでは秋月で扱っている商品をリストに登録して保存し、リストのページにある「まとめてカートに入れる」ボタンを押すことで、いつでも秋月の買い物かごに商品をまとめて登録できるようにしました。


Twitterでログインすると、ダッシュボードが登場、ここから新しいパーツリストを作成できます。
作成するパーツリストは、アクセスレベルが公開(Public)、限定公開(Unlisted)、非公開(Private)の3種類から選択可能。
公開を選ぶとAkiCartのトップページにリストされる(こともある)ようになり、限定公開を選ぶとリンクを知っている人だけが閲覧可能なリストになり、非公開は文字通り自分しか見れないリストができます。


商品の追加はリストの画面からもできるのですが...
AkiCartの一番の特徴は、超超超便利なブックマークレット。
秋月の商品画面でブックマークレットをクリックすると、一発で作成したリストに追加できます。


ブックマークレットをブラウザに追加しておくと、秋月のページでクリック→個数の変更がない場合はそのままEnterを押すだけでドンドン追加できます。
AkiCartのブックマークを押して登録完了するまで最短2秒くらい。


作ったリストは一括して買い物かごに入れるだけでなく、CSV形式でダウンロードしたり、印刷専用のレイアウトで印刷することもできます。
高専とか大学とかで、事務の人に「これ買ってください」って渡すのも楽チンですね。

〜ここからはちょっとだけ技術的な話〜

今までは、買いたい商品のページをブラウザでブックマークしておいて、買うときに一挙に開いてカートに追加するという作業で購入していました。
流石にこれどうにかならんのか?というのと、何やら秋月の一括通販コード入力画面はリファラをチェックしてないから別サイトからPOSTできるという話を聞きまして...


一括通販コード入力画面からの遷移を見てみると、いつものカート画面(cart.aspx)に対して quick: True を指定して、あとはclass1_xに通販コードのハイフンの左側の英字1文字、goodsにハイフン右側の数字5文字、そしてqtyに数量を入れて、これを繰り返したものをPOSTしてあげればカートに入ることが分かりました。
そしてやはりリファラをチェックしてないので、このページ以外からPOSTしても普通にカートに入ることも確認。
これらを元にして、AkiCartができた...という訳です。
ちなみに、AkiCartの任意のリストページのソースを見ると、まとめてカートに入れるボタンの近くにtype="hidden"でいっぱいinputが転がってますw

バックエンドはEVI(地震火山詳報)でも使っているDjango(Python)です。
ここ数ヶ月触ってなかったので結構忘れてて、調べながらコード書いてたので時間が掛かりました...
6/3のAM2時頃に作り始めて、途中寝たり飯食ったりした時間を抜くと15時間くらいかな...?
バグとかセキュリティ的なアレを発見したら、Twitterでリプライ頂けると非常にありがたいです。

早速要望として、リスト間で商品を移動できるようにしたいとか、リストをブログなどに埋め込めるようにしたい、という意見が出ているので、ぼちぼちアップデートしていきたいと思います。

これとは別件で、そこそこ実用的かつ面白いものづくりのプロジェクトも進んでいるので、また報告できるタイミングになったらブログなどなどに書きたいと思います。

追記 : ブログパーツ(埋め込み用コード)できました。


公開もしくは限定公開のリストであれば、リストページの右サイドバー下に「埋め込みコード」の欄があるので、これをコピーして貼り付ければOK!