22
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PLAIDAdvent Calendar 2018

Day 11

Google Bigtableでのキー設計の指針について

Last updated at Posted at 2018-12-11

こんにちは、PLAIDでSREをやっている @tarr1124 です。この記事は、自分の所属しているPLAIDのアドベントカレンダーの記事になります。
https://qiita.com/advent-calendar/2018/plaid

KARTEでは、クライアントのサイトから、ユーザーの行動をeventという形でデータを送信してもらっています。
そのevent一つ一つに対して、解析処理をし、ユーザーのこれまでのeventから解析されたデータにマージされて、その結果を元に適切なresponseを返すようになっています。

このeventや解析されたデータは様々なデータベースに格納されますが、今回は、その中からBigTableに焦点を当てて、KARTEのデータ特性からどのようにBigtableのキーを設計すれば良いのかを書きます。

そもそもBigtableってなに

image.png
https://cloud.google.com/bigtable/docs/overview

Bigtableは下記のような特徴をもったKVSです。

  • 大量のデータを保持できる(node数を増やすことで線形にデータ容量が増える)
  • 大量のアクセスをさばくことができる(node数を増やすことで線形に処理能力が伸びる)
  • 列指向であるので、一つのkeyに大量のcloumnを持たせることができる。(それらを特定のcolumnのみでfilterして取り出すことも可能)

このように、nodeを増やせば増やすほど、BigTableでは大量のデータを扱えるように、大量のリクエストをさばけるようになります。
しかし、そのためには、うまくリクエストやデータが分散されるように、キーを設計する必要があります。

どのようにキーを設計すれば良いのか

BigTableのデータは以下の特徴で扱えます。
image.png
https://cloud.google.com/bigtable/docs/overview

  • keyの辞書順にソートされた状態で格納される。
  • keyをrange指定で複数のrowで取得できる
  • 一つのnodeにread/writeが集中しないように分散させたほうが良い。
  • そのkeyが何を表しているのか、人間があとから追えるようにする必要がある。(key visualizerというツールでパフォーマンスを追うときに必要です)

つまり、どのようにデータを利用したいのか、read/writeのどちら側に寄せるのか、などを考慮した上でkeyを設計する必要があります。

KARTEのキー設計

KARTEがBigTableに格納しているデータは大きく2種類あります。
それぞれのデータ特性にあったキーの設計を紹介します。

解析済みuserデータ

  • eventを解析した結果をmergeしていくデータ
  • userごとに持っている。
  • eventが来るたびにread/writeが走る。
  • 管理画面からユーザーの詳細を見るときなどにreadが走る。

このような特徴のデータのkeyを設計してみます。
まず、userごとのkey-valueなので、user_idをkeyにするのはどうでしょうか?

{user_id}

この状態だと、user_idに偏りがあったときに特定のnodeに負荷が集中してしまって、BigTableのパフォーマンスが落ちてしまいます。
それでは、hashにするとどうでしょう。

{user_idのhash値}

こうすれば、user_idによる偏りは防げますが、あとから問題が起こったときに人が追いづらいですね。
特にBigTableでは、Googleが提供しているkey visualizerというツールをつかって、keyに偏りがないか、パフォーマンスを確認することがあります。
その際に、keyがhash値などだと、何が原因でパフォーマンスが悪いのか追いづらいため、Googleも推奨していません。

そこで、KARTEでは、user_idから作るhash値をprefixにつける設計にしています。

{user_idのhash値}_{user_id}

これで、BigTable内で適切に負荷が分散されます。これは、keyがデータとして独立していて、他のデータと関連していないためにできる設計です。

eventデータ

  • すべてのユーザーから送られたeventが格納されているデータ
  • 管理画面からユーザーごとにeventのhistoryを見たいときに使われる。
  • eventの詳細を見たいときに使われる。

eventデータは、上記のような特徴を持っており、これはupdateがなく、読み込みがメインとなる時系列データです。
また、このデータはユーザーごとで読み込んで使われるため、ユーザーのデータがBigTable内でまとまっている必要があります。
一方で、新しいuserなどのほうが書き込みが多いという特徴もありそうです。よって、userのデータ自体はnodeで分散させる必要があります。

そこで、KARTEでは下記のようにBigTableのkeyを設計しています。

{user_idからのhash値}_{user_id}_{timestampを反転したもの}

この設計であれば、下記のように、Bigtableと我々のKARTEの要望、両方に適したものになります。

  • hash値をprefixにつけているので、user_idの偏りによって、特定のnodeにリクエストが集中することがない
  • user_idのhash値user_idを prefixとして持っているので、辞書順に並んだ際に、一人のuserのrowをまとめてとってくることができる
  • user_id自体もkeyに含まれているので、問題が起こった際に人間が追いやすい
  • timestampを反転したものをpostfixとして持っているので、新しいrowが先にくるようにソートされる

このような形でBigtableのキーを設計することで、read/writeのパフォーマンスに加えて、node数を抑えることができ、コスト面にも効果がでます。
Bigtableを使う際に参考にしてみてください。

22
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?