読者です 読者をやめる 読者になる 読者になる

キュレーションサービスにおけるRDBとNoSQLの使い分けを紹介

SpeeeKaigi

こんにちは!リードエンジニアのid:eva-hashimotoです。

先日行われた SpeeeKaigi で「キュレーションメディアにおけるMongoDB事例」を発表しました。

technica-blog.jp

これは、あるキュレーションサービスを2年ほど運用してきた中で、大きなトラブルやアーキテクチャ変更が発生することなく稼働しているので参考として見ていただければと思います。

キュレーション記事のデータ

みなさん1度はキュレーションサービスの記事を見たことがあると思います。しかしデータ構造まで考えて見る人は少ないと思うのでまず説明します。

f:id:eva-hashimoto:20160824163737p:plain

記事のデータとしては大きく二つ分類できます。

  • タイトルやディスクリプションなどの共通データ

  • 記事自体を構成するためのオリジナル文章や引用、画像、動画などの様々なパーツ

このデータをRDBを用いて管理する場合の正規化は雑に考えると二つあるかなと。

パターン1

記事テーブルと各パーツの種類ごとに正規化する

記事テーブル

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

見出しパーツテーブル

記事ID 表示場所ID 見出し
1 1 PV伸ばすための方法
1 4 Analyticsで分析しよう
2 1 なぜRubyなのか?
2 5 エンジニア文化の作り方

画像パーツテーブル

記事ID 表示場所ID 画像タイトル ファイル名
1 3 エンジニア全員 eng.png
3 4 ロゴ logo.png

引用パーツ、youtubeパーツ・・・・and more

パターン2

記事テーブルとパーツを1テーブルで管理

記事テーブル

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

パーツテーブル

記事ID 表示場所ID type text url パーツの種類分・・
1 1 見出し PV伸ばすための方法
1 2 説明文 読むユーザを意識する
1 3 画像 エンジニア全員 eng.png
2 1 見出し なぜRubyなのか?

私の所感ではパターン1を選ぶ方が多いイメージです。

記事を表現するパーツの種類が増えたり変わったりすることで連携するテーブルが多くなるしカラム変更も増えるデメリットがあるがRDBだけならこっちかなと。

パターン2はパーツテーブルという概念がまとめられているが、パーツの種類によって扱うデータが違うため非正規化されておりカラム構成がぐちゃぐちゃになる。

私たちのサービスではパターン2でデータ部分をスキーマレスにする設計にしました。そこでスキーマレス部分のデータを扱うミドルウェアとしてMongoDBを利用しています。

MongoDBを利用したパターン

記事テーブル (RDB)

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

パーツテーブル (RDB)

記事ID 表示場所ID type obj_id
1 1 見出し obj_001
1 2 画像 obj_002
1 3 twitter obj_003

パーツデータ (MongoDB)

{ Obj_id:”obj_001”, text : ”見出しです” }
{ Obj_id:”obj_002”, title : ”エンジニア”,  url : ”eng.png” }
{ Obj_id:”obj_003”, id : ”@hs”  tweet_id : 1234 }

スキーマレスの利点を生かして各データが持つべきプロパティを適切に表現できます。 こうすることで今までパーツの追加、変更でRDB側のメンテナンスコストは少なく設計とプログラミングで悩むことが少ないです。

デメリットとしてはデータ領域のミドルウェアが増えることによる学習コスト、運用コストが増えることとRDBのリレーショナル性を捨てることになります。この辺はトレードオフなので仕方ないですが十分なメリットだったと感じています。

なぜMongoDBだったのか

当サービスではMongoDBの利用方法として本来はページ単位のキャッシュデータ先として検討していました。

  • 記事のデータ
  • アクセスランキング
  • レコメンド など

それぞれのキャッシュデータ先として利用するだけではなくスキーマレスという性質と先ほど説明した非正規データの格納先に最適ではないか?という発想になった次第です。

キャッシュ先として候補に上がったKVSは幾つかありますが、データの格納、検索性とサーバのクラスタ構成の仕組みと障害時のクライアント動作としてMongoDBが一番理想に近い形だったので選定になりました。

選定内容、検証をくわしく!・・・説明するとこの記事では長くなるため、私に直接聞いてくださいw

エンジニアとしてどんなサービスも手を抜かず適切に技術を選択することでより良いサービス価値を追求していきたいと思います。