蟻地獄

Twitterに書ききれない長めの文とか書くよ

VALUのパロディサービス「NILU」を2週間で作るのを支える技術

www.itmedia.co.jp

NILUは以下のような構成となっています。

バックエンド

  • GAE/Go
  • Gin
  • Cloud Datastore
  • Firebase Authentication

フロントエンド

  • Vue.js
  • Bootstrap4
  • plotly.js

RDBは一切使っておらず、Cloud Datastoreだけで頑張っています。 Cloud Datastoreってトランザクション的なことはできるんですが、求められるテーブル設計がRDBとは大きく違ってCloud Datastore固有のノウハウが必要なので毎回設計に迷います。どっかにノウハウ落ちてないですかね。オライリーから「実践ハイパフォーマンスCloud Datastore」みたいなやつ発売されろ。

という制約を軸にテーブル設計していくんですが、1つのエンティティグループに何でも突っ込むと1秒1回制限に引っかかり、逆にエンティティグループを細かく分けすぎると25個制限のために1回のトランザクションバッチ処理できる量が減りやっぱり1秒1回制限に引っかかるという、如何ともしがたい感じです。

証券取引なんてトランザクションの化け物みたいなものなのでこんなん無理やろって感じなんですが、NILUではどうやっているのかというと、売買注文は板に反映されないリクエストキューに一旦書き込み、定期処理でキューから取り出して順番に処理しています。画面への反映に5分くらいかかるのはこの定期処理待ちです。

こうすると並列処理できないのでスケーラビリティは落ちるんですが、並列処理したところでCloud Datastoreは楽観的ロックで競合しまくる可能性が高いので、処理がシンプルになるこの方法を取りました。1回の買い注文でも注文数量が多いと複数人の売り注文とマッチする場合があり1トランザクションで捌ききれない可能性がありますが、直列に処理しとけばたとえ途中でエラーが起きても単にリトライし続ければ注文順に捌けます。

Firebase Authenticationについては、基本スマホとかSPA用っぽいのでページ遷移のあるWebでの使い方が正しいのかいまいちわかっていません。JWTをcookieに保存するのはなんか違う気がしたのでログインが必要なページは一旦枠のhtmlだけ返した後非同期でユーザー情報を取得してきてるんですが、こういうやり方で良いんですかね。よくわかりません。

フロントエンドは雑に使えるVue.js+伝統と信頼のBootstrapです。フロントエンドについては本業ではノータッチなのでほぼ公式ドキュメントからのコピペとかで設計はテキトーです。恥ずかしいのであまりソース見ないでね。

あとplotly.js便利。VALUさんも見づらい謎チャートやめて素直に既成のチャートライブラリ使った方が良いんじゃないですかね。

マストドンのOAuth認証でログインできるWebアプリの作り方

マストドンにpixivアカウントとかでログインするほうじゃなくて、自分が作ったWebアプリにマストドンアカウントでログインする機能を付けるほう。 完成品はこちら。 concept-auction.appspot.com

OAuth2準拠のAPIなのでTwitterログインとかとほぼ同じですが、大きな違いが2つあります。

1. ユーザーにドメインを入力してもらう必要がある

Twitterの場合は https://api.twitter.com/oauth/authorize を決め打ちで叩けばよかったんですが、マストドンインスタンスは自由に立てられるので、ただボタンが押されただけだとどのインスタンスにリクエストを投げればよいか分かりません。なので、ユーザーにマストドンインスタンスドメインを入力してもらう必要があります。 というわけでこんな感じのUIになりました。 f:id:mitomemel:20170422143231j:plain

2. client_id/client_secretはインスタンスごとに必要

新規にWebアプリを作る場合、Twitterだと https://apps.twitter.com/ でアプリ情報を登録してclient_id/client_secretを発行してもらっていましたが、マストドンの場合、どのインスタンスのユーザーが来るか分からないので事前にアプリ情報を登録しておくことができません。 ではどうするのかというと、新しいドメインのユーザーがログインしてきたタイミングでアプリ情報の登録もその場でREST APIを叩いて行います。一度発行したclient_id/client_secretとドメインの組は自サイトのDB等に保存しておきます。 大まかな流れは以下の通りです。

  1. ユーザーはドメインを入力してログインボタンを押す
  2. ログインリクエストを受け取ったWebアプリサーバは、まず自サイトに保存してあるclient_id/client_secretをドメイン文字列をキーに検索する。データが見つからなかった場合は指定されたドメインの /api/v1/apps を叩いてアプリ情報を登録し、発行されたclient_id/client_secretを自サイトのDBに保存後クライアントにclient_idを返す
  3. クライアントは受け取ったclient_idをパラメータに指定してマストドンサーバの /oauth/authorize にアクセスする
  4. ログイン画面が表示されるのでメールアドレス/パスワードを入力する f:id:mitomemel:20170422143251j:plain
  5. アカウントへのアクセス要求画面が表示されるので承認を押す f:id:mitomemel:20170422143311j:plain
  6. アプリ情報登録時に設定したredirect_uriが認証コード付きで叩かれるので、Webアプリサーバからマストドンサーバの /oauth/token を叩いてアクセストークンを受け取る
  7. アクセストークンを用いて /api/v1/accounts/verify_credentials を叩いてユーザー情報を入手

ただ、マストドンサーバ側のDBデータがDocker神の荒ぶりによって消えてしまった場合が厄介で、2.で自サイトに以前に保存されたclient_idをマストドンサーバに投げたらそんなclient_id知らねえよって言われてしまうので、再度アプリ情報を登録するみたいなエラーハンドリングが必要になります。うわあめんどくさい。

ちなみに今回はGAE/Goで作ったんですが、マストドンAPIへのアクセスにはgo-mastodonを使わせていただきました*1golang最高!

*1:go-mastodonはまだパスワード認証しか対応していないので、OAuthを使用するには若干手を入れる必要があります

お一人様マストドンはメモリ512MBだと無理

ブロックチェーンはセカンドライフに似ている

あらかじめ言っておくと、これはビットコインってリンデンドルみたいなものでしょとかいう話ではありません。セカンドライフもブロックチェーンもある程度知った上での感想です。

セカンドライフというと、「戦闘が無いMMORPG」とか「広告だらけで中身スカスカ」というイメージが強いと思いますが、セカンドライフを現在の言葉で説明すると、「プレイヤーがMODを自由にアップロードできるサンドボックスタイプのMMO」というのが近いかと思います。

マインクラフトをMMO化したいというのは誰でも一度は思い付く妄想だと思いますが、それに近いものが既にセカンドライフで実現されていました。しかもプレイヤーはMODを自由にアップロードでき、それがサーバに即座に反映されて他人にも影響するというとんでもない仕様です。

こんなすごいものが突然出てきたので、当時セカンドライフを見た人は「第二のインターネットだ」と言って持て囃し、大企業も次々にセカンドライフ内に"支店"を作りました。学術的な研究も盛んに行われ、セカンドライフは世界を変えるかのように思われました。

しかし、セカンドライフは世界を変えませんでした。非常に面白い技術だし、実際に今まで成し遂げることができなかったことを実現しているのですが、所詮は「サンドボックスタイプのMMO」でしかなかったからです。第二のインターネットとなるためにはあまりにも多くのものが欠けていました。

これって最近のブロックチェーンの流行り方にそっくりじゃありませんか?ブロックチェーン界隈の皆様におかれましては、ぜひセカンドライフに学び第二のインターネットとなるよう頑張っていただきたく思います。

ちなみに散々アバターがバタ臭いと言われたセカンドライフですが、最近は日本人受けする容姿もデフォルトで選べるようです。これを機にプレイしてみてはいかがでしょうか?

join.secondlife.com

以上、セカンドライフステマでした:)

3大メガバンクがブロックチェーンではない何かの実証実験をしている

みずほフィナンシャルグループ三井住友銀行三菱UFJフィナンシャル・グループという三大メガバンクが参加したブロックチェーン実証実験の報告書が公開されました。

www2.deloitte.com

システム構成としては、トランザクションを承認するコアノードは信頼できる中立的な機関が担い、各銀行は承認機能を持たないノードでトランザクションの生成およびデータの参照のみを行う、というものです。

実験内容は、銀行間で振込を行うというもので、既存の決済システムとの連携・データ秘匿性など現状問題視されている部分は全てオミットでスループットとデータ完全性を見るだけ、という非常にシンプルな構成となっています。

先日の日本取引所グループが出した報告書と比べるとどうしても物足りなさを感じてしまいますが、一点非常に気になる記述を見つけました。

 p.11 

c. ハードウェア購入費

従来技術では冗長化構成やバックアップセンタ設置により高稼働率を実現しているが、ブロックチェーン技術ではその特性上、これらの措置を施さずに高稼働率を期待できる。また、1 つのシステムで集中的に処理を行う従来技術に対して、複数システムで分散的に処理を行うブロックチェーン技術では、ハードウェアの低スペック化が期待できる。

高可用性は良いとして、ブロックチェーンで負荷分散???

ブロックチェーンというのは、同じデータのコピーを全ノードが持ち、全ノードがそれぞれ検証する、という富豪的な仕組みによってロバスト性を上げるものだと思っていました。負荷分散はブロックチェーンが苦手なものの筆頭のはずで、集中的に処理を行う従来技術よりもハードウェア面で低コストが期待できるというのは考えにくいです。彼らはブロックチェーンではない別の何かを検証していた可能性があります。

ただ私もブロックチェーンについては素人なので、解釈を間違えているのかもしれません。この部分の記述について、どう解釈すれば良いのかわかる方がいましたらぜひコメントを頂きたいです。

Google App Engine と Cloud Datastore だけでオークションサイトを作った

こんばんは!サーバレスしてますか!

Google App Engine (GAE)がなんか最近イケてるとかイケてないとかいう話を聞いて、とりあえず何か小さなサービスを作って試してみようと思ったのですが、どうせ作るなら毒にも薬にもならない掲示板とかじゃなくて罠を踏み倒しそうな感じのが良いと思い、オークションサイトを作ってみました。

concept-auction.appspot.com

データべースはRDBを一切使用せず、Cloud Datastoreのみで構築しています。え、Cloud DatastoreってKey-Valueストアじゃないの?と思うかもしれませんが、実は色々なクエリが使えたりトランザクションが使えたりするので、仮想通貨の受け渡しなんかもわりと真っ当に実装することができます。

ただし、RDBのように扱えるかというとやはりそうではなく、様々な制約があるので、Cloud Datastoreに特化したテーブル設計が必要となります。特にData Consistencyのドキュメントは10回くらい読んだほうが良いです。

Data Consistency  |  Google Cloud Platform

制約はいろいろありますが3行でまとめると、

という感じです。なのでテーブル設計の段階から、トランザクションが必要なデータはルートエンティティにしないようにしたり、1つのエンティティグループへの更新が集中しないような親子関係にするといった工夫が必要になります。1秒1トランザクションという制約はかなり厄介で、今回作ったオークションサイトでも入札の整合性をどうやって保つかで苦労しました。

とは言え勝手にスケールアウトしてくれるというのはとても魅力的で、今回作ったオークションサイトも、アクセスが無ければ維持費$0、何かの間違いでYahoo砲を食らっても無限にスケールする(※ただし予算がスケールするとは言っていない)というのは非常に楽です。

まあそんなこんなで、本当にちゃんとスケールするのか試してみたいのでみんなツイッターで拡散してね!

concept-auction.appspot.com