Webアプリのセッション管理とデータ保存を学ぶ#3(社内勉強会)

#1 Webアプリのセッション管理の基礎 #2 クライアント側のデータ保存方法 #3 サーバー側のデータ保存方法(本記事) 3. Webサービスにおけるデータ保存(サーバーサイド編) 続いてサーバー側でのデータ保存について説明します。 ほとんどのWebサービスでは、最終的なデータをサーバーのどこかに保存しておかなければなりません。Webサーバーは多数のクライアント(及びユーザー)から同時にアクセスを受けるため、それらを個別に処理して、矛盾が生じないように保存する必要があります。 サーバー側でのデータ保存の種類について以下で説明します。 A. ファイルに保存する 最も単純な方法であり、手軽に作成されたフォームプログラムなどではCSVファイルなどから設定情報を読み取り、データ保存もサーバー側のCSVファイルなどに書き出すといった作りをすることがあります ファイルへの保存は最も手軽に行える方式ですが、同じファイルに完全に同時書き込みが発生したときに問題が発生する可能性が常につきまといます。OS側でのファイルロックで書き込みや読み出しに失敗することもあれば、ファイルのデータそのものが破損する可能性もあります。 ファイルへの保存は、更新の不要なデータを読み取り専用で使うのが無難です。 morimorihoge注) もちろんファイル保存形式でも、ロックファイルなどの伝統的な排他制御を実装することで、データの保全を行うことは可能です。 ※著名なオープンソースソフトウェアでファイル保存形式を利用しているものは、ちゃんと排他制御が実装されていることがほとんどです ただ、真面目にきちんとした排他制御をファイルベースで行う場合、ロックファイルの消し忘れ対策などの問題が残る上、ある程度大量のアクセスを捌ける様にするにはOSのファイルAPIや作法に対する知識も必要になってくる(セッションごとの一次データはtmpfsに置きつつ、書き込み時は共通のデータファイルに追記モードで書き込むことでなるべくロックを避けるなど)ため、ちゃんと作ろうとすればするほど元々ファイル保存の魅力であった「お手軽簡単」というところから離れていきます。 というわけで、ほとんど同時アクセスの来ないようなユースケースを除き、ファイルに全ての情報を保存する方法は昨今あまりオススメできません。 B. データベースに保存する RDBMSなどの専用データベースシステムは、Webアプリのデータ保存先の主流となっています。 Web系のソフトウェア開発の世界では、データベースというと多くの場合場合RDBMSを指します。 データ書き込みの排他処理やトランザクション処理を確実に実行できることでデータの矛盾を回避できます。 データベースには、RDBMSなどのWebサーバーとは独立したシステムを使うことがほとんどなので、サーバー側に別途RDBMSをインストールする必要があります(最近ではクラウドのデータベースサービスを使うことも増えています)。 また、自前で準備する場合にはデータベースの設置や管理、SQLの知識も要求されますが、DBサーバーはクラウドインフラやレンタルサーバーが提供するものを使ったり、SQLはDBアクセスを抽象化するDAO(Database Access Object)ライブラリなどを使うことで、単純な利用用途の範囲であれば避けて通ることも可能ではあります。 PostgreSQL、MySQL、Oracle、Microsoft SQL Serverなどがよく使われます。RailsではPostgreSQLやMySQLがよく使われます。 RDBMS: Relational DataBase Management System RDBMSについては本勉強会の範疇を超えるのでごく簡単にとどめますが、Webアプリ開発においても重要な機能を担っています。 RDBMSは、リレーションモデルを基礎として、行(row)と列(column)からなるテーブル(table)という表形式のデータを扱います。RDBMSでは、以下を実現することで安全・高速・正確にアクセスする機能を提供します。 排他制御 トランザクション管理(ロールバックなど) 集計機能 一貫したデータ構造の管理 RDBMSの「ACID」 RDBMSのこうした機能の実現に必要な4つの要素(性質)は、その頭文字を取ってACIDと呼ばれます。 Atomicity(原子性・不可分性) トランザクションの実行後は「完了」「未処理」のどちらかの状態だけを取ること Consistency(一貫性・整合性) トランザクションの前後での整合性を維持すること Isolation(独立性・隔離性) 変更中の内部データを隠蔽すること Durability(永続性・持続性) 処理の完了したデータが障害によって消えず復元可能であること 「NoSQL」という選択肢 データベースには、上述のRDBMSの他に「NoSQL」と称されるデータベースシステムもあり、用途によって使い分けられます。NoSQL系のデータベースシステムでは、RDBMSと異なり、上述のACIDの一部(またはすべて)が保証されないので注意が必要です。 NoSQL系は各々が得意とする特定のユースケースにおいてはRDBMSよりも高性能ですが、ACID特性が犠牲にされるため、キャッシュやPub/Sub(Publish/Subscribe)のように永続化やデータの整合性よりも速度を重視する場面で使うことがあります。 Redisは元々MemcachedなどのKVS(key-value store)の一種ですが、現在はそれ以上の機能が追加されていることもあり、RDBMSが不得意な部分(キャッシュやPub/Sub、ランキングなどの高速な集計)を補う用途で導入されることが増えています。 MongoDBやDynamoDBなどのドキュメント指向データベースは、データ構造の自由さという使い勝手の良さも相まってひと頃人気を博しましたが、RDBMSとは別のノウハウが必要だったり、ACID特性の必要な場面で誤って使われることもあったためか、最近ではやや落ち着いているようです。 morimorihoge注) 昨今ではRedisやらMongoDBやらといったNoSQLがもてはやされる風潮がありますが、特に初学者の人は惑わされてはいけません。世の中のアプリケーションで最も使われているのはRDBです。まずはRDBを使いこなしましょう。 NoSQLがRDBの苦手な特定用途の問題を解決するのに役に立つのは確かですが、RDBも進化しているため多くのユースケースはRDBでカバーできます。 まともなRDB設計ができれば基本的には百万レコードくらいまではほぼチューニングなしでそれなりの実効性能が出せることが多いですし、それ以上になってきてもRDB側のチューニングや適切なDB設計で大抵のユースケースに対応できます。 僕の経験則ですが、RDB以外にデータを保存するのが妥当なケースは以下のケースなどが挙げられます。 画像や動画などのファイル保存 AWS S3を始めとするオブジェクトストレージに入れる方が良い。RDBにバイナリとして入れることもできるが、サイズが大きくなりすぎるのでメンテ上もデメリットの方が多い。 コンテンツキャッシュデータの保存 RedisやMemcachedなどのとにかくI/Oが早いKVSを使う方が良い。RDBの備えるACID特性(後述)の多くが不要。 秘密鍵などのサーバー側機密情報 AWS KMSなどの鍵管理のためのシステムに入れる方が管理上事故が起こりにくいです。ユーザー側機密情報は検索したいケースなどもあるのでRDBに入れる方が開発は楽になります。 チャットなどの高い応答性が必要なPub/Sub機構 短いレイテンシと高いスケールアウト性が求められる場合、RDBだとポーリングが辛いのでRedisのPub/Sub機能やRabbitMQなどのメッセージサーバー、または簡単なPub/Sub機構であればNode.jsやGolangで参考実装があると思うのでそういったものを使う方が良いと思います。 不定形ドキュメントデータの保存 MongoDB・・・という手もありますが、MongoDBはノウハウがないと色々と辛い話も聞くので、PostgreSQLのJSON型で足りるのであればそちらの方が良いと思っています。 文字列一致だけでない高度な全文検索が必要 形態素解析などが必要な場合、Apache Solrなどの全文検索に特化したものを使う必要があります。 何にせよ、まずはRDBを使いこなした上で他の保存形式に手を出す方が実用的なので、上記の例に該当するようなケースを除けばデフォルトはRDBMSを使う、くらいに考えておくのが良いと思います。 データの保存先はアプリケーションが育ってくるとそう簡単に切り換えられません。安直に選ぶと将来に渡って辛い技術的負債を残すことになるので、慎重に検討しましょう。 Web開発初心者向けのデータ保存シナリオ Webアプリでのデータ保存については、さしあたって以下を目安に考えるとよいでしょう。 RDBMS: システム運用の中で書き換えが発生するマスタデータ、及びアプリケーションが永続的に保管したいファイル以外の消えてはいけないデータ ソースコード上の定数: サーバーサイド・クライアントサイドどちらもあるが、基本的にユーザーが考慮しなくて良いプログラム上でのみ利用するもの ファイルとして保存: 画像や動画、ZIPファイル、生成に時間のかかる集計CSVデータなど Cookie: セッションID以外のものは極力保存しない CookieはセッションIDの保存にのみ使うのがポイントです。それ以外の値も追加で保存したくなった場合には、本記事にあるような欠点を考慮した上で利用しましょう。 ※秘密キーや多言語文言などについてはまた別の機会とします。 キャッシュ目的などを別にすれば、NoSQLは原則としてメインのデータベースの検討対象から外れます。ただし、RDBMSのフル機能がなくてもよく、かつ次のような特定の要件に該当する場合は、詳しい経験者に相談のうえで検討しましょう。 1テーブルに格納されるデータ件数が100万件を確実に超える(1000万件級の可能性もある)場合 更新や参照が非常に多く高速なレスポンスが要求される場合 自然言語での全文検索が必要な場合(LIKE検索では不足) まとめ クライアント側(Webブラウザ)のデータ保存には、CookieやWeb Storageがあります。Cookieの利用はセッションIDの保存にとどめましょう。 サーバー側のデータ保存には、原則としてRDBMSを用います。それ以外のNoSQL他の利用については慎重に検討した上で利用しましょう。 #1 Webアプリのセッション管理の基礎 #2 クライアント側のデータ保存方法 #3 サーバー側のデータ保存方法(本記事) 関連記事 Webアプリの基礎とさまざまな実行環境を理解する#1(社内勉強会) Linuxのサービス起動周りとDockerとの関連を理解する#1(社内勉強会)