【ポエム】何でもかんでもリレーショナルデータベースに保存するのはやめよう

# はじめに

普段は旧 Twitter ばかりにぼやきを放り込んでいるんですが、今回ばかりは長文になりそうだなと思ったのでこちらに投稿してみようと思いました。

ちなみに自分の知識は素人に毛が生えた程度なのでもしかしたら書いていることが間違っているかもしれないのですが、ポエムとして甘んじて受け入れて読んでください。（自分に甘い、ごめんなさい）


# この記事を書こうと思った背景

最近新しいチームに異動して新規サービスの立ち上げをやっています。

異動先のチームはもともと1年だか2年前に組織されたらしいのですが、目的としているサービスのローンチどころか開発環境とかで動いているものも全くない的なチームでした。
そのチームでデータアーキテクチャの話になったのですが、既存のメンバーたちが言うには

「いったんRDS前提でいいんじゃない？」

という感じで進めているようなのですが、こちらとしては「いやいや、どうしてRDS一択なの？それが最適解なのか？」と思ったわけです。それを挙げても RDS 前提にしたい感じが変わらないので、これから普及活動をしようと思っています。

でも実はこの話、異動前にいたチームでも同じようなことを感じていました。
前のチームの例で、わかりやすくかつ割と一般的な話だと、アプリケーションログを全てMySQLに保存しているのを見て「監査的な観点から保存することは必要でも、絶対1年前のログとかまず滅多にアクセスしないでしょ。一定期間経過したものは S3 に移動させようよ」という話を出したのですが

「え？S3って画像保存するところじゃないの？」

的な話が出てきたわけで、なるほどこの辺の普及活動から必要なんだなと感じたことで、この記事を書くに至ったというわけです。


# 「馴れているから」という理由で同じアーキテクチャを採用すること自体は必ずしも悪くはないけど

昨今でいういわゆるSREとかインフラと呼ばれるような人たちは割と理解があるような気がするのですが、これまで出会ってきたプロダクト開発をやっているようなチームのマネージャーだったりメンバーだとわりと同じアーキテクチャを採用し続けていることが多かったように思います。

RDBくらいしか知識がないチームならリレーショナルデータベースを選択してしまうのもわかりますし、同じアーキテクチャを採用すること自体は別に良いのですが、それが最適であると根拠付けて考えた方が良いかなと思います。

例えば先ほどのアプリケーションログを考えると、ログ自体のアクセス頻度が頻繁に行われるような話ならRDBとかでも良いかもですが、基本的に本番環境に出ているアプリケーションログって障害発生時とか問い合わせ起点で調べることはありますが、1年前のログとかってまずアクセスしませんよね？
それなら低頻度アクセスに適したサービスを選択した方が良いという考えに至ってアーキテクチャを最適化していってもらえると良いかなと思っています。


# アプリケーションログの保存に関するアーキテクチャの例

一応公開する情報なので一般的な話に昇華していますが、先ほどのアプリログの話でいうと大体こんな感じのアーキテクチャ変更をしてあげると良いかなと思います。

変更したポイントとしては以下の通りです。

- アプリログをマネージドサービスの CloudWatch に送信するようにして ログ収集やアラート設定の運用の手間とかを省力化
- 一定期間経過したログは S3 に保存することで大量のログの長期保存コストを削減

なお、このアーキテクチャ図は結構端折っているので、踏み台とか静的ファイルは Cloudfront に置いとくようにしようとか Elasticache の話、CloudWatch Logs で収集して変なのあったら Alarms で発報するとかそういったものは描いてないです。

Before | After
--- | ---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/bd389896-52e6-7819-2cc6-fd889f62ae38.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/3fd1ba00-ec7f-c1be-3d5d-251a11afd104.png)


# データアーキテクチャ設計で考慮するべきこと

個人的にデータアーキテクチャを考えるにあたってよく考えていることは以下のような点。
たぶん過不足があったり、書いていることが間違っていることもあるかもしれないですが、基本的には参考になるのではないかなと思います。

### 1. ビジネス要件の明確化

- システムの目的: システムは何を実現したいのか？
- データの利用目的: データはどのように活用されるのか？
- データの量: どれくらいの量のデータを扱うのか？
- データの種類: 構造化データ、非構造化データ、時系列データなど、どのような種類のデータがあるのか？
- データの品質: データの精度、一貫性、信頼性など、どのような品質が求められるのか？
- パフォーマンス: どのくらいの処理速度が必要か？
- 可用性: システムの稼働率はどの程度必要か？
- スケーラビリティ: 将来的にデータ量が増加した場合に対応できるか？

### 2. データモデルの設計

- エンティティ: データベースに格納する対象（顧客、商品など）
- 属性: エンティティの特徴（顧客ID、商品名など）
- リレーションシップ: エンティティ間の関係（1対1、1対多、多対多など）
- 正規化: データの冗長性を排除し、データの一貫性を保つ
- デノーマライゼーション: クエリ性能向上のため、意図的に正規化を緩める

### 3. データストレージの選定

- RDS: リレーショナルデータベース、構造化データの保存に適している
- NoSQL: 非構造化データや大規模なデータの保存に適している
- S3: オブジェクトストレージ、静的なファイルやバックアップの保存に適している
- Redshift: データウェアハウス、大規模なデータの分析に適している
- Athena: S3上のデータをSQLで分析できるサービス
- その他いろんなサービス

### 4. データフローの設計
- データの収集: データはどこから収集されるのか？
- データの加工: データはどのように加工されるのか？
- データの保存: どのストレージに保存されるのか？
- データの分析: データはどのように分析されるのか？

### 5. セキュリティ
- アクセス制御: 権限管理、認証・認可
- データ暗号化: 敏感なデータを暗号化
- バックアップ: データのバックアップと復旧

### 6. パフォーマンス
- インデックス: クエリ性能向上のためのインデックス設計
- キャッシュ: 頻繁にアクセスされるデータをメモリにキャッシュ
- パーティショニング: 大量のデータを分割して管理

### 7. スケーラビリティ
- 水平スケーリング: サーバーを追加することで処理能力を向上させる
- 垂直スケーリング: サーバーのスペックを向上させる

### 8. コスト
- ハードウェアコスト: サーバー、ストレージなどの費用
- ソフトウェアコスト: データベースライセンス、ミドルウェアの費用
- 運用コスト: 人件費、保守費用

### 9. その他
- データのライフサイクル: データの作成、更新、削除、アーカイブ
- コンプライアンス: 法規制への対応
- 可用性: システムの稼働率
- 災害対策: 災害発生時の対策


# さいごに

いろいろ書いたものの、実際自分も勉強中の身なので結構知識無かったり構築経験は乏しかったりするので頑張っていかなきゃなと思います。反省。

まあでも個人でなんか小さいアプリ作るだけとかなら全部 MySQL とか PostgreSQL でいいやーってなったりすることも多いのですが、ちゃんと大きめのサービス作るならこういったことをちゃんと理解してアーキテクチャの設計はしたいですね。（単なる願望）