tag:crieit.net,2005:https://crieit.net/tags/Database/feed 「Database」の記事 - Crieit Crieitでタグ「Database」に投稿された最近の記事 2018-12-17T12:18:17+09:00 https://crieit.net/tags/Database/feed tag:crieit.net,2005:PublicArticle/14667 2018-12-17T07:09:08+09:00 2018-12-17T12:18:17+09:00 https://crieit.net/posts/Firebase-Realtime-DB Firebase Realtime DBの実戦投入を振り返る - 採用方針やセキュリティで気をつけたことなど <p>「<a href="https://crieit.net/advent-calendars/2018/crieit">Crieit Advent Calendar 2018</a>」の記事です。2018年は、業務で「Firebase Realtime Database」を使った1年でした。</p> <p><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/database/?hl=ja">https://firebase.google.com/docs/database/?hl=ja</a></p> <p>Realtime Databaseは、 <strong>数ミリ秒で各クライアントへデータを同期</strong> します。はじめて使ったときは、とても感動しました。開発したシステムでは、リアルタイムのデータ表示が必要な、特定機能に限定してRealtime Databaseを投入しています。</p> <p>色々と工夫した点がありますので、今回はその辺りの知見を共有します。</p> <h2 id="RDB(Relational Database)との併用"><a href="#RDB%28Relational+Database%29%E3%81%A8%E3%81%AE%E4%BD%B5%E7%94%A8">RDB(Relational Database)との併用</a></h2> <p>「Firebase Realtime Database」は、データベースとして単体で使うわけではなく、 <strong>PostgreSQLと併用して運用</strong> しています。</p> <p>それには、いくつかの理由があります。</p> <ol> <li>はじめて使うので、ミニマムにプロジェクトで採用し、様子を見ることにした</li> <li>データ容量や転送量に連動する従量課金のため、最低限のリアルタイム表示に必要なデータだけ置くことにした</li> <li>Realtime Databaseは、柔軟なクエリ発行が苦手です。管理画面をはじめとする、細かな検索条件が発生するシーンには不向きでした</li> </ol> <p>棲み分けとしては、リアルタイム表示が必要なデータをRealtime Databaseに投入し、それ以外はRDB(PostgreSQL)に保存しています。</p> <p>また、Firebase Console上の誤操作で、データを上書きしたり消失できてしまう可能性があります。そこで、復旧スクリプトも用意しました。</p> <p>具体的には、PostgreSQLにあるマスターデータを元にして、API経由でデータを再セットするスクリプトです。ただ、一度も出番はなかったです。</p> <h3 id="セキュアなデータはRDB(PostgreSQL)に置く"><a href="#%E3%82%BB%E3%82%AD%E3%83%A5%E3%82%A2%E3%81%AA%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AFRDB%28PostgreSQL%29%E3%81%AB%E7%BD%AE%E3%81%8F">セキュアなデータはRDB(PostgreSQL)に置く</a></h3> <p>また、PostgreSQLを併用しているもうひとつの理由に、セキュアなデータを置きたくなかった点があります。</p> <p>後述するセキュリティルールを工夫すれば対策も可能ですが、保険をかけて、セキュアなデータはサーバーサイドのRDBに暗号化して保存してします。</p> <h2 id="セキュリティルールの調整で、書き込みを拒否する"><a href="#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E8%AA%BF%E6%95%B4%E3%81%A7%E3%80%81%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF%E3%82%92%E6%8B%92%E5%90%A6%E3%81%99%E3%82%8B">セキュリティルールの調整で、書き込みを拒否する</a></h2> <p>セキュリティルールは、基本的に以下の設定で運用しています。私の場合、 <strong>書き込みは許可せず運用する</strong> ことにしました。</p> <p>また、リアルタイムのデータ表示に必要な特定のテーブルに絞って、読み込みを開放しています。</p> <pre><code class="json">{ "rules": { ".read": false, ".write": false, "sampletable": { ".read": "auth != null", ".write": false } } } </code></pre> <p>書き込みを拒否した理由は、主に以下の3点です。</p> <ol> <li>PostgreSQLのマスターデータにも反映したかったので、書き込みはサーバーサイドで処理したかった</li> <li>フロントエンドJSから直接データを書き込ませないことで、安全性を高めたかった</li> <li>認証は自前でやっており、Firebase Authenticationで認証していない。そのため、細かな書き込み権限の制御が難しかった</li> </ol> <p>なお、書き込みを許可しなかったとしても、 <strong>Admin用のライブラリを使えば書き込みは可能</strong> です。PHPには公式のAdmin SDKがなかったので、OSSを利用しました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/kreait/firebase-php" target="_blank" rel="noopener">GitHub - kreait/firebase-php: Unofficial Firebase Admin SDK for PHP</a></p> <p>読み込み側の権限は「auth != null」にしています。念のため、Firebase Authenticationの匿名認証を挟んで運用している形です。</p> <p><a href="https://crieit.now.sh/upload_images/47df150c84d76efc71630f2cd88618255c1633230c89a.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/47df150c84d76efc71630f2cd88618255c1633230c89a.png?mw=700" alt="20181216200759.png" /></a></p> <h2 id="GCP(Google Cloud Platform)と連動している点に注意"><a href="#GCP%28Google+Cloud+Platform%29%E3%81%A8%E9%80%A3%E5%8B%95%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E7%82%B9%E3%81%AB%E6%B3%A8%E6%84%8F">GCP(Google Cloud Platform)と連動している点に注意</a></h2> <p>Firebaseのプロジェクトを開設すると、 <strong>GCP(Google Cloud Platform)のConsoleでもアクセスできる</strong> ようになります。この点はかなり重要です。</p> <p>私が技術書典4で頒布した「<a target="_blank" rel="nofollow noopener" href="https://konosumi.booth.pm/items/836447">Realtime Database x React本</a>」でも、注意事項を書いてます。抜粋して掲載します。</p> <blockquote> <p>「APIとサービス」の認証情報を確認すると、Firebaseが自動で作成したキーがあることが分かります。そして、APIキーにおける警告マークは、APIキーが無制限であることを示しています。実運用で使用される場合は、設定は必須であると言えます。開発段階でも、可能な限り制限を設定することが望ましいでしょう。</p> </blockquote> <p>WEBサービスであればリファラで、モバイルアプリであればバンドルIDなどでAPIキーを制限するのが基本形です。これを設定しておかないと、 <strong>Firebase用のアクセスAPIキーが無制限状態で運用</strong> されてしまいます。</p> <p>少し内容が古くなってしまいましたが、技術書典4で頒布した本にもFirebaseの概要を書いてます。無料でダウンロードできます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://konosumi.booth.pm/items/836447" target="_blank" rel="noopener">Firebase Realtime Database と React.js で始めるリアルタイム アプリケーション入門 - このすみ堂 - BOOTH</a></p> <h2 id="Realtime Databaseの実装は、メルカリを参考にするのがオススメ!"><a href="#Realtime+Database%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%AF%E3%80%81%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%AA%E3%82%92%E5%8F%82%E8%80%83%E3%81%AB%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8C%E3%82%AA%E3%82%B9%E3%82%B9%E3%83%A1%EF%BC%81">Realtime Databaseの実装は、メルカリを参考にするのがオススメ!</a></h2> <p>私がプロジェクトで採用した構成は、 <strong>「PHPカンファレンス2017のメルカリチャンネル」</strong> をベースにしています。</p> <p><a target="_blank" rel="nofollow noopener" href="https://tech.mercari.com/entry/2017/10/16/190000" target="_blank" rel="noopener">PHPカンファレンス2017でFirebase Realtime Databaseについて登壇してきました #phpcon2017 | メルカリエンジニアリング</a></p> <p>会場でメルカリの<a target="_blank" rel="nofollow noopener" href="https://twitter.com/sota1235">@sota1235</a>さんに質問して、 <strong>「半年ほど運用しているが、一度もダウンしたことはない」</strong> という返答をもらったのが、採用の決め手になりました。</p> <p>メルカリチャンネルにおけるRealtime Databaseの知見は、他の記事でも共有されています。ぜひ参考にしましょう!</p> <p><a target="_blank" rel="nofollow noopener" href="https://tech.mercari.com/entry/2017/12/16/151224" target="_blank" rel="noopener">メルカリチャンネルにおけるFirebaseの利用例 | メルカリエンジニアリング</a></p> <h2 id="Cloud Firestoreとの関係性"><a href="#Cloud+Firestore%E3%81%A8%E3%81%AE%E9%96%A2%E4%BF%82%E6%80%A7">Cloud Firestoreとの関係性</a></h2> <p>Realtime Databaseの対抗馬として、Cloud Firestoreがあります。</p> <p><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/?hl=ja" target="_blank" rel="noopener">Firestore &nbsp;|&nbsp; Firebase</a></p> <p>個人的には、以下のような印象を持っています。</p> <ol> <li>Cloud Firestoreは、まだベータ版である</li> <li>クエリの柔軟性は、Cloud Firestoreのほうが高い</li> </ol> <p>Cloud Firestoreの特徴である <strong>「クエリ処理の機能性、効率性、柔軟性」</strong> は、とても魅力的です。</p> <h2 id="さいごに"><a href="#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB">さいごに</a></h2> <p>リアルタイムのデータ表示が必要な、特定機能に限定してRealtime Databaseを投入しました。感触はとても良いです。</p> <p>また、オフライン対応があるのも魅力的です。もしデータ同期に失敗しても、クライアントがオンラインになったら、自動的に同期を再開します。これを自前のWebSocketで実装するとしたら、相応の苦労が必要なことは間違いありません。</p> <p>巨人の肩の上にのることのメリットを、改めて実感した1年でした。</p> このすみ