hbaseを用いたグラフdb「hornet」の設計と運用
DESCRIPTION
Hadoop Conference Japan 2014で発表した資料。TRANSCRIPT
HBaseを用いた グラフDB「Hornet」の設計と運用
株式会社サイバーエージェント Ameba Technology Laboratory
鈴木 俊裕 梅田 永介
2 株式会社サイバーエージェント
自己紹介• 鈴木俊裕(すずき としひろ)• ソフトウェアエンジニア
• Ameba Technology Laboratory
• Hadoopログ解析基盤• HBaseを用いた基盤システム
• 近の興味:Scala, Go, NewSQL
• Twitter @brfrn169
3 株式会社サイバーエージェント
自己紹介• 梅田永介(うめだ えいすけ)• ソフトウェアエンジニア
• Ameba Technology Laboratory
• HBaseを用いた基盤システム
• 趣味:料理
4 株式会社サイバーエージェント
今日話すこと• 前半(鈴木)
• Hornetについて• HBaseについて• HBaseアプリケーション設計のセオリー• Hornetの設計
• 後半(梅田)• Hornetの運用• Zookeeperを用いたロック
Hornetについて
6 株式会社サイバーエージェント
Hornetとは• HBaseをバックエンドDBとしたグラフ構造を格納するデータベース
• 弊社のHBaseチームで開発
• 現在、公開はしていないが、OSS化に向けて動いているところ
7
Hornetのデータモデル
株式会社サイバーエージェント
• プロパティグラフ
A
B
C
ノードリレーションシップ(方向がある)
follow
follow
name Toshihiro
age 30
ノードのプロパティ
name Ichiro
age 30
name Masahiro
age 28
date 2014-07-08
favorite true
date 2013-11-10
favorite false
リレーションシップのプロパティ
ノードIDリレーションシップのtype
8 株式会社サイバーエージェント
なぜHBaseを選択したか• 弊社では、MySQL + Sharding (+ MHA)の構成がスタンダード
• シャードの管理が大変• 初から分散を考慮したデータベース
• 既にログ解析基盤にHadoop/HBaseを使っていた
• 可用性や、パフォーマンスの検証をしてみて十分な性能を示した
9 株式会社サイバーエージェント
現在のHornet• 「Ameba」のスマートフォン向けプラットフォーム内のグラフ構造を保持している
10 株式会社サイバーエージェント
現在のHornetの規模感• データ規模
• 約100億 ノード• 約600億 リレーションシップ
• アクセス規模• ピーク帯で分間6Mアクセス• 平均レイテンシは10ms以下
HBaseについて
12 株式会社サイバーエージェント
HBaseとは• Googleの分散データストアである「Bigtable」のオープンソースクローン
• HDFS(Hadoop Distributed File System)上で動作
• 高可用性• 高パフォーマンス(特に書き込み)• スケーラブル
13 株式会社サイバーエージェント
HBaseのシステム構成• マスタ型(<=> P2P型)
• MasterとRegionServerの2種類のプロセスが存在する• Master
• RegionServerの管理やRegionのアサインなど• RegionServer
• クライアントと実際にデータのやり取り• 障害検知や各プロセス間のコーディネーションをZookeeper
Master
RegionServer RegionServer
Zookeeper
HDFS
・・・RegionServer
14 株式会社サイバーエージェント
HBaseのシステム構成• HDFS(Hadoop Distributed File System)上に構築されている
• (デフォルトで)レプリカを3つ持つので信頼性が高い• HBaseの信頼性はHDFSに依存している
Master
RegionServer RegionServer
Zookeeper
HDFS
・・・RegionServer
15
• 部分的にRDBに似ている
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5 aaa bbb NULL ccc ddd
row6
row7
row8
RowKey(主キー、辞書順でソートされている)
Column ValueTable
16
• でも、ちょっと違う
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5 aaa bbb NULL ccc ddd
row6
row7
row8
ColumnはColumnFamilyによってグルーピング
▼ ▼ ▼ ▼
fffggg
hhh iiijjj
Valueは複数バージョンを持つ
17
• でも、ちょっと違う
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5 aaa bbb ccc ddd eee
row6
row7
row8
ColumnFamilyは定義する必要がある
18
• でも、ちょっと違う
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5 aaa bbb ccc ddd eee
row6
row7
row8
19
• でも、ちょっと違う
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5 Column6
row1
row2
row3
row4
row5 aaa bbb ccc ddd eee fff
row6
row7
row8
Columnは後からいくらでも増やすことができる
20
• でも、ちょっと違う
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5 Column6 Column7
row1
row2
row3
row4
row5 aaa bbb ccc ddd eee fff ggg
row6
row7
row8
Columnは後からいくらでも増やすことができる
21
• データの分割について
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5
row6
row7
row8
22
• データの分割について
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1 ColumnFamily2
Column1 Column2 Column3 Column4 Column5
row1
row2
row3
row4
row5
row6
row7
row8
RowKeyの範囲でRegionに分割される
Region1
Region2
23
• Regionは各RegionServerに配置される• 1つのRegionが複数のRegionServerに配置されることはない• Regionをデータ量や負荷が均等になるようにRegionServerに配置することで、ロードバランスが可能
• Rowの更新処理はアトミックに行われる• ColumnFamily間の処理もアトミックになる• CASやIncrementが可能
株式会社サイバーエージェント
HBaseのデータモデル
RegionServer 1 RegionServer 2
Region 1 Region 3 Region 5Region 6
RegionServer 3
Region 2
Region 8
Region 4
Region 7
24
• ColumunFamilyとデータファイル
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1
Column1 Column2
row1
row2
row3
row4
ColumnFamily2
Column3 Column4 Column5
25
• ColumunFamilyとデータファイル
株式会社サイバーエージェント
HBaseのデータモデル
ColumnFamily1
Column1 Column2
row1
row2
row3
row4
ColumnFamily2
Column3 Column4 Column5
ファイル1 ファイル2
ColumnFamily毎にデータファイルが分かれる
Column(ColumnFamily)指向データフォーマット
26 株式会社サイバーエージェント
HBaseのデータモデル• 各データファイルの実際の構造
row1 ColumnFamily1 Column1 100 aaa
RowKey ColumnFamily Column Timestamp value
row1 ColumnFamily1 Column2 200 bbb
row2 ColumnFamily1 Column1 140 111
row2 ColumnFamily1 Column2 300 rrr
row3 ColumnFamily1 Column1 400 fff
row5 ColumnFamily1 Column1 500 333
row5 ColumnFamily1 Column1 130 uuu
row5 ColumnFamily1 Column2 300 555
RowKey + ColumnFamily + Column + Timestamp(降順)でソートされている
1つのエントリをKeyValueと呼ぶ
27 株式会社サイバーエージェント
HBaseのデータモデル• 各データファイルの実際の構造
row1 ColumnFamily1 Column1 100 aaa
RowKey ColumnFamily Column Timestamp value
row1 ColumnFamily1 Column2 200 bbb
row2 ColumnFamily1 Column1 140 111
row2 ColumnFamily1 Column2 300 rrr
row3 ColumnFamily1 Column1 400 fff
row5 ColumnFamily1 Column1 500 333
row5 ColumnFamily1 Column1 130 uuu
row5 ColumnFamily1 Column2 300 555
複数Columnを持っているRowは、複数KeyValueになる
28 株式会社サイバーエージェント
HBaseのデータモデル• 各データファイルの実際の構造
row1 ColumnFamily1 Column1 100 aaa
RowKey ColumnFamily Column Timestamp value
row1 ColumnFamily1 Column2 200 bbb
row2 ColumnFamily1 Column1 140 111
row2 ColumnFamily1 Column2 300 rrr
row3 ColumnFamily1 Column1 400 fff
row5 ColumnFamily1 Column1 500 333
row5 ColumnFamily1 Column1 130 uuu
row5 ColumnFamily1 Column2 300 555
ValueがNULLの場合は、KeyValueが保存されない
29 株式会社サイバーエージェント
HBaseのデータモデル• 各データファイルの実際の構造
row1 ColumnFamily1 Column1 100 aaa
RowKey ColumnFamily Column Timestamp value
row1 ColumnFamily1 Column2 200 bbb
row2 ColumnFamily1 Column1 140 111
row2 ColumnFamily1 Column2 300 rrr
row3 ColumnFamily1 Column1 400 fff
row5 ColumnFamily1 Column1 500 333
row5 ColumnFamily1 Column1 130 uuu
row5 ColumnFamily1 Column2 300 555
複数バージョンを持っている場合は、Timestampが違うKeyValueになる
30 株式会社サイバーエージェント
HBaseのAPI• 更新系
• Put• Row、Columnの追加・更新• バージョン(Timestamp)を指定してPutすることもできる
• Delete• Row全体、指定のColumn、バージョンを削除
• Increment• Valueをインクリメント
• Append• Valueに末尾にデータを追加する
• Row内に閉じた更新系の処理はアトミックに処理することができる
31 株式会社サイバーエージェント
HBaseのAPI• 参照系
• Get• 単一のRowを取得
• Scan• 複数RowをRowKeyの範囲を指定してスキャン
• 取得するColumnFamilyやColumnの指定やバージョンの指定ができる• より細かい条件を指定するためのフィルタも指定することができる
32 株式会社サイバーエージェント
HBaseのAPI• その他
• CAS(Compare And Swap)系• 期待する現在のValueを指定し、その値と一致した場合にPut, Delete• Row内に閉じたもののみ
• Batch• 複数のGetやPut、DeleteやIncrementなどを一度に投げることができる
HBaseアプリケーション設計のセオリー
34 株式会社サイバーエージェント
HBaseアプリケーション設計の考え方• RDBの設計は、対象世界を分析してER図を書いて(概念設計)、それをもとにリレーショナルモデルを作成し(論理設計)、クエリなどを考慮してインデックスを定義したりモデルを修正する(物理設計)
• HBaseの設計においても、論理設計まではほぼ同じ• 物理設計をどうするかっていうところが、かなり違う
35 株式会社サイバーエージェント
HBaseアプリケーション設計の考え方• HBaseの場合、インデックスが限られている
• RowKey, ColumnFamily+Column, Timestamp(降順)でソート• スキーマの工夫が必要
• 検索条件にしたい• ソートしたい
• Joinもない• 非正規化を前提に考えないといけない
• RDBが自動的にやってくれていたことを、マニュアルにやる必要があるイメージ
• すこし手間がかかるが、スケーラビリティとのトレードオフ
⇒ クエリを中心に設計する必要がある
36 株式会社サイバーエージェント
HBaseアプリケーション設計の考え方• クエリを中心にデータを設計する
• 同じデータでも、検索条件によってスキーマが変わる• クエリを設計当初にちゃんと考えることが重要
• 同じデータでも、検索条件がいくつかある場合、別のスキーマで重複して持つ必要がある場合がある
• インデックスをマニュアルに• データ不整合に気をつけなければならない
• クエリによって非正規化を考えていく• 非正規化は前提• データ不整合に気をつけなければならない
37 株式会社サイバーエージェント
HBaseのデータモデリング• Tall-narrow Table と Flat-wide Table
• Tall-narrow Table• Rowが多く、Columnが少ないテーブル• Scanで取得
• Flat-wide Table• Rowが少なく、Columnが多いテーブル• Getで取得
Tall-narrow
Flat-wide
38 株式会社サイバーエージェント
HBaseのデータモデリング• Tall-narrow Table と Flat-wide Table
• 例) メールボックス
RowKey fam:
user1-message1 aaa
user1-message2 bbb
user1-message3 ccc
user1-message4 ddd
RowKey fam:message1 fam:message2 fam:message3 fam:message4
user1 aaa bbb ccc ddd
Tall-narrow
Flat-wide
39 株式会社サイバーエージェント
HBaseのデータモデリング• どこにどのデータをマッピングしても、データ量は変わらない
• 例)下のどちらもデータ量が変わらない• Rowkey=user1-message1, CoumunFamily=fam, Column=, value=aaa• Rowkey=user1, CoumunFamily=fam, Column=message1, value=aaa
user1 fam message1 100 aaa
user1-message1 fam 100 aaa
KeyValueのイメージ
Tall-narrow Table
Flat-wide Table
データ量は変わらない
40 株式会社サイバーエージェント
HBaseのデータモデリング• Tall-narrow Table と Flat-wide Table はどちらのほうが良いのか?
• 基本的には Tall-narrow Table が良い• Regionの分割はRowKeyの範囲で行われるので、Rowが巨大になったら分割することができなくなってしまう
• Flat-wide Tableはいつ使うのか?• Row内の処理はアトミックに行われるので、それを利用したい場合(簡単なトランザクション)
41 株式会社サイバーエージェント
その他• ロードバランスという視点
• RowKeyの設計によっては、データや負荷がかたよる可能性がある• 例えば、RowKeyにシーケンシャルIDをマッピングして、順に書き込んでいくと、1つのRegionに書き込みが集中してしまう可能性がある
• ランダムIDにするか、RowKeyの頭にハッシュを付与するというテクニックもある
• ColumnFamilyをどう使えば良いのか• ColumnFamily毎にデータファイルが分かれる• 同時に参照されないColumnを別のColumnFamilyに入れておくことで、無駄なI/Oやフィルタリング処理を削減することができる
42 株式会社サイバーエージェント
HBaseアプリケーション設計のセオリー• 時間が限られているのでここまで、、
• 参考までに• Codezine 連載「初めてのHBase」
• http://codezine.jp/article/corner/473
• 馬本(オライリージャパン「HBase」)
Hornetの設計
44 株式会社サイバーエージェント
Hornetの機能(簡略版)• ノードの作成• ノードのプロパティの追加
• リレーションシップの作成• リレーションシップのプロパティの追加
• 隣接ノードの取得• 2種類のクエリ
• Outgoing• Incoming
• セカンダリインデックス• 隣接ノードをプロパティの値でソートして取得する
A
B
C
follow
follow
follow
name Taro
age 30
time 100
45 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• RowKey
• hash(nodeId) + nodeId
• ColumnFamily• “h”
• Column• “”(空のバイト配列)
• Value• シリアライズされたプロパティ
46 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• ポイント
• RowKeyの先頭にノードIDのハッシュ値をつけることで、データや負荷の偏りを防ぐことができる
• Valueにはシリアライズしたプロパティを入れている• Columnにプロパティ名、Valueにプロパティ値を入れる設計も考えられる• KeyValue数を減らすことでデータ容量を節約している
• このケースでは特に、ColumnFamilyを使う必要がないので、固定で”h”にしている
47 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードの作成
• API
• グラフ
g.addNode("A"); g.addNode("B");g.addNode("C");
A
B
C
48 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードの作成
RowKey ColumnFamily Column value
49 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードの作成
RowKey ColumnFamily Column value
hash(“A”) + “A” “h” {}
hash(“B”) + “B” “h” {}
hash(“C”) + “C” “h” {}
ノードIDのハッシュ値 ノードID
50 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードのプロパティ
• API
• グラフ
g.node("A").setProperty("name", "Taro"); g.node("A").setProperty("age", "30");
A
B
C
name Taro
age 30
51 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードのプロパティ
RowKey ColumnFamily Column value
hash(“A”) + “A” “h” {}
hash(“B”) + “B” “h” {}
hash(“C”) + “C” “h” {}
52 株式会社サイバーエージェント
Hornetのスキーマ(ノード)• 例) ノードのプロパティ
RowKey ColumnFamily Column value
hash(“A”) + “A” “h” {name:Taro, age:30}
hash(“B”) + “B” “h” {}
hash(“C”) + “C” “h” {}
シリアライズされたプロパティ
53 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• RowKey
• hash(inNodeId) + inNodeId + “out”+ type + outNodeId• hash(outNodeId) + outNodeId + “in”+ type + inNodeId
• ColumnFamily• “h”
• Column• “”(空のバイト配列)
• Value• シリアライズされたプロパティ
54 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• ポイント
• Outgoing, Incomingの2種類の検索条件があるので、1つのリレーションシップにつき2本のRowを持つ(非正規化)
• それぞれにシリアライズされたプロパティを入れる
• Tall-narrow Table
55 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップの作成
• API
• グラフ
g.node("A").addRelationship("follow", "B"); g.node("A").addRelationship("follow", "C"); g.node("B").addRelationship("follow", "C");
A
B
C
follow
follow
follow
56 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• AがBをフォロー
RowKey ColumnFamily
Column value
57 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• AがBをフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
ノードIDのハッシュ値
始点ノードID
タイプ 方向終点ノードID
58 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• AがCをフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
59 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• AがCをフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
60 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• BがCをフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
61 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) リレーションシップのプロパティ
• BがCをフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“B”) + “B” + “follow” + “out” + “C” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “B” “h” {}
62 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)• 例) 隣接ノードの取得
• API
• グラフ
g.node("A").out("follow"); g.node("C").in("follow");
A
B
C
follow
follow
follow
63 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)
• 例)隣接ノードの取得• Aのフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“B”) + “B” + “follow” + “out” + “C” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “B” “h” {}
64 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)
• 例)隣接ノードの取得• Aのフォロー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“B”) + “B” + “follow” + “out” + “C” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “B” “h” {}「hash(“A”) + “A” + “follow” + “out”」で
プレフィックススキャン
フォローの”B”と”C”が取れる
65 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)
• 例)隣接ノードの取得• Cのフォロワー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“B”) + “B” + “follow” + “out” + “C” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “B” “h” {}
66 株式会社サイバーエージェント
Hornetのスキーマ(リレーションシップ)
• 例)隣接ノードの取得• Cのフォロワー
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + “B” “h” {}
hash(“A”) + “A” + “follow” + “out” + “C” “h” {}
hash(“B”) + “B” + “follow” + “in” + “A” “h” {}
hash(“B”) + “B” + “follow” + “out” + “C” “h” {}
hash(“C”) + “C” + “follow” + “in” + “A” “h” {}
hash(“C”) + “C” + “follow” + “in” + “B” “h” {}
「hash(“C”) + “C” + “follow” + “in”」でプレフィックススキャン
フォロワーの”A”と”B”が取れる
67 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)• RowKey
• hash(inNodeId) + inNodeId + “out”+ type + <indexed property value> + outNodeId
• hash(outNodeId) + outNodeId + “in”+ type + <indexed property value> + inNodeId
• ColumnFamily• “h”
• Column• “”(空のバイト配列)
• Value• シリアライズされたプロパティ
68 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)• ポイント
• リレーションシップの作成時に、リレーションシップのRowとは別にセカンダリインデックスRowを作成する(非正規化)
• 基本的にはリレーションシップのスキーマと同じだが、RowKeyの一部にプロパティの値を入れることで、そのプロパティ値でソートされた状態で格納される
69 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)• 例) 隣接ノードの取得(ソート)
• API
• グラフ
g.node("A").out("follow") .sort(asc("time"));
A
B
C
follow
follow
follow
time 200
time 100
time 300
70 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)
• 例)隣接ノードの取得(ソート)
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + 100 + “C” “h” {time:100}
hash(“A”) + “A” + “follow” + “out” + 200 + “B” “h” {time:200}
hash(“B”) + “B” + “follow” + “in” + 100 + “A” “h” {time:200}
hash(“B”) + “B” + “follow” + “out” + 300 + “C” “h” {time:300}
hash(“C”) + “C” + “follow” + “in” + 200 + “A” “h” {time:100}
hash(“C”) + “C” + “follow” + “in” + 300 + “B” “h” {time:300}
セカンダリインデックスのプロパティの値
71 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)
• 例)隣接ノードの取得(ソート)• Aのフォローをtimeの昇順でソート
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + 100 + “C” “h” {time:100}
hash(“A”) + “A” + “follow” + “out” + 200 + “B” “h” {time:200}
hash(“B”) + “B” + “follow” + “in” + 100 + “A” “h” {time:200}
hash(“B”) + “B” + “follow” + “out” + 300 + “C” “h” {time:300}
hash(“C”) + “C” + “follow” + “in” + 200 + “A” “h” {time:100}
hash(“C”) + “C” + “follow” + “in” + 300 + “B” “h” {time:300}
72 株式会社サイバーエージェント
Hornetのスキーマ(セカンダリインデックス)
• 例)隣接ノードの取得(ソート)• Aのフォローをtimeの昇順でソート
RowKey ColumnFamily
Column value
hash(“A”) + “A” + “follow” + “out” + 100 + “C” “h” {time:100}
hash(“A”) + “A” + “follow” + “out” + 200 + “B” “h” {time:200}
hash(“B”) + “B” + “follow” + “in” + 100 + “A” “h” {time:200}
hash(“B”) + “B” + “follow” + “out” + 300 + “C” “h” {time:300}
hash(“C”) + “C” + “follow” + “in” + 200 + “A” “h” {time:100}
hash(“C”) + “C” + “follow” + “in” + 300 + “B” “h” {time:300}「hash(“A”) + “A” + “follow” + “out”」で
プレフィックススキャン
フォローの”C”と”B”が取れる(ソートされている)
Hornetの運用
74
Hornetの運用• システム構成• クラスタの管理• バックアップ• 障害事例
75
• HBase Clusterシステム構成
NameNode8Core CPU50GB RAM
hornet
Zookeeper24Core CPU64GB RAM
ZookeeperMasterJobTracker24Core CPU64GB RAM
DataNode, TaskTracker, RegionServer12Core CPU32GB RAM
ZookeeperMaster24Core CPU64GB RAM
Cluster構築当時はHAがなかったため、FTサーバを使っている
76
• HBase Clusterシステム構成
NameNode
hornet×25台
Zookeeper ZookeeperMasterJobTracker
DataNode, TaskTracker, RegionServer×約50台
ZookeeperMaster
77
• HBase Cluster
NameNode
hornet
DataNode, TaskTracker, RegionServer
Zookeeper ZookeeperMasterJobTracker
ZookeeperMaster
CDH4b1※HBase0.92.0
システム構成
性能が出ない!
78
• HBase Cluster
NameNode
hornet
DataNode, TaskTracker, RegionServer
Zookeeper ZookeeperMasterJobTracker
ZookeeperMaster
CDH4b1※HBase0.92.0
CDH3u3
システム構成
Hadoopのコンポーネントを
CDH3u3に差し替えたところ、性能が改善
79
• HBase Cluster
NameNode
hornet
DataNode, TaskTracker, RegionServer
Zookeeper ZookeeperMasterJobTracker
ZookeeperHMaster
CDH4b1※HBase0.92.0
CDH3u3
システム構成
Master, RegionServerについては、そのままでは動かなかったのでリコ
ンパイルしている
80
クラスタの管理• メジャーコンパクションの管理• Regionサイズの管理• バランシングの管理• ノードの管理• モニタリング
81
メジャーコンパクションの管理• メジャーコンパクションの概要
• HBaseは書き込み処理を繰り返すとKeyValueが溜まっていく(データファイルが増えていく)
• Scan時にKeyValueを大量に読み込むことになり、Scan性能が劣化する
• HBaseでは、メジャーコンパクションと呼ばれる処理を行うことでRegionの全てのデータファイルをマージすることができる。
• データファイルをマージすることにより、読み込み対象のKeyValueが減るため、読み込み性能が回復する
• 24h+20%毎に実行される(デフォルト)
• ただし、高負荷な処理であり、処理中はレスポンスタイムが悪化する
82
メジャーコンパクションの管理• メジャーコンパクションの自動実行を無効にし、オフピーク帯にメジャーコンパクションを定期実行
• HBaseの設定• hbase.hregion.majorcompaction = false
83
Regionサイズの管理• 特定のRegionのデータ量が増えていくと、Region間でのデータ量やアクセスの偏りが発生する可能性がある
• この偏りを防ぐために、HBaseはRegionの 大ファイルサイズより大きくなったRegionの分割(※)を自動で行う
• HBaseの設定値• hbase.hregion.max.filesize (デフォルト:1GB ※0.94では10GB)
• ただし、Regionを分割するとメジャーコンパクションが実行されるため、計画的に分割しないとピーク帯にメジャーコンパクションが動いてしまう恐れがある
※0.94からはIncreasingToUpperBoundRegionSplitPolicyがデフォルトとなった
84
Regionサイズの管理• 自動分割を無効にし、オフピーク帯に一定のサイズをこえたRegionを分割
• HBaseの設定• hbase.hregion.max.filesize = 107374182400 (100GB)
85
バランシングの管理• HBaseでは特定のRegionにアクセスが集中してしまう状態を「Hot Region(Hot Spot)」と呼ぶ
• Hot Regionが発生すると、そのRegionが配置されているRegionServerの負荷が増大するため、同じRegionServerに同居しているRegionにも悪影響を与える
86
バランシングの管理• 通常のバランサだと各Regionに均等に分散される(※)
※0.96以降では、StochasticLoadBalancerがデフォルトになっており、負荷に応じて分散されるようになった。
TableA TableA
TableB TableB TableB
TableC TableC TableC
TableA
RegionServerA RegionServerB RegionServerC
87
バランシングの管理• Hot Regionができてしまった場合、Hot Regionと同居するRegionにも影響が出てしまうRegionServerA RegionServerB RegionServerC
TableA TableA
TableB TableB TableB
TableC TableC TableC
TableA
同居しているTableBとTableCへのアクセスにも影響が出てしま
う
Hot Region
88
バランシングの管理• 重要なテーブルのRegionについては、ほかのテーブルのRegionの影響を避けるため、別のRegionServerに割り当てている
TableA TableA
TableB
TableB
TableB
TableC
TableC
TableC
TableA
RegionServerA RegionServerB RegionServerC
89
バランシングの管理• Hot Regionができてしまった場合、Hot Regionと同居するRegionが限定されるので、影響を 小限にすることができるRegionServerA RegionServerB RegionServerC
TableA TableA
TableB
TableB
TableB
TableC
TableC
TableC
TableA
Hot Region
TableBに影響が出る
TableCには影響が出ない
90
ノードの管理• ノードのデコミッション
• デコミッション対象のノードが持っているブロックのコピーがクラスタ全体で発生するため、ディスクIOやNWリソースがコピー作業に多く使われて本来のリクエストの処理がスローダウンする可能性がある
• デコミッションの影響を 小限にするには、以下の設定値を適切に設定する必要がある
• CDH3u3の場合• dfs.max-repl-streams(デフォルト:2)replicationで転送する 大のブロック数
• dfs.replication.interval(デフォルト:3)replication間隔(sec)
91
ノードの管理• ノードのデコミッション
• CDH4以降の場合• dfs.namenode.replication.work.multiplier.per.iteration(デフォルト:2)replicatoinの並列転送数
• dfs.namenode.replication.max-streams(デフォルト:2) )replicationで転送する 大のブロック数(replicationの優先度が)
• dfs.namenode.replication.max-streams-hard-limit(デフォルト:4)replicationで転送する 大のブロック数
• dfs.namenode.replication.interval(デフォルト:3)replication間隔(sec)
92
ノードの管理dfs.replication.interval = 3 (デフォルト)でデコミッションした場合
1.9GByte/sec
93
ノードの管理dfs.replication.interval = 6 でデコミッションした場合
1.1GByte/sec
94
モニタリング• Ganglia
• cpu_reportCPU使用率、IOWAITの確認。
Hot Regionが発生するとCPU使用率が跳ね上がる
• network_reportNW I/Oの確認
95
モニタリング• Ganglia
• rpc.metrics.RpcProcessingTime_avg_timeサーバサイドでRPCの処理に要した時間
• rpc.metrics.RpcQueueTime_avg_timeRPC呼び出しがキューイングされている時間
96
モニタリング• Ganglia
• hbase.regionserver.fsReadLatency_avg_timeストレージファイルからデータをロードするのに要した平均時間
• hbase.regionserver.fsWriteLatency_avg_timeストレージファイルにデータを書き込むのに要した平均時間
97
モニタリング• Ganglia
• hbase.regionserver.fsSyncLatency_avg_timeWALのレコードをファイルシステムに同期する際の平均時間
• hbase.regionserver.requestsリクエスト数
98
モニタリング• Ganglia
• hbase.regionserver.blockCacheHitRatioブロックキャッシュのヒット率の確認
• hbase.regionserver.blockCacheHitCachingRatioブロックキャッシュのヒット率(setCacheBlocks指定の場合)の確認
99
モニタリング• Ganglia
• hbase.regionserver.flushQueueSize普段は低い。I/O負荷が高くなると増大する
• hbase.regionserver.compactionQueueSize普段は低い。I/O負荷が高くなると増大する
100
モニタリング• zabbix
• ログ監視• Hot Regionを早期に発見するため、RegionServerのログ監視を実施以下のログがRegionServerのログに出力されたら通知
• responseTooSlow• responseTooLarge• operationTooSlow
101
モニタリング• Regionに対するヘルスチェック
• すべてのRegionに対して15秒に1回Scanを実行• 応答を返さない、または何れかのRegionでエラーになった場合異常を通知する
hornet
RegionServerA RegionServerB
TableA TableA
TableB
TableB
TableB
TableC
TableC
TableC
TableA
RegionServerC
102
モニタリング• 各種ログの収集
• flumeで以下のログをオペレーション用サーバに集約RegionServerのログ
DataNodeのログ
gcログ
syslog
HBase Cluster
オペレーション用サーバ
flumeによる転送
103
バックアップ• HBase0.92.0のレプリケーション機能にはバグが有るため、使えない
• 1時間ごとのバックアップ• 1日ごとのスナップショット取得
104
バックアップ1時間ごとのバックアップ
1. HBase ClusterからBackup ClusterにWAL(Write Ahead Log)を転送
HBase Cluster Backup Cluster
WAL
WAL転送
WALWALWAL
ストレージ
105
バックアップ1時間ごとのバックアップ
1. HBase ClusterからBackup ClusterにWAL(Write Ahead Log)を転送2. Backup ClusterにWALの内容を反映
HBase Cluster Backup Cluster
WAL
WAL転送
WAL
WAL反映
WALWALWAL
ストレージ
106
バックアップ1時間ごとのバックアップ
1. HBase ClusterからBackup ClusterにWAL(Write Ahead Log)を転送2. Backup ClusterにWALの内容を反映3. ストレージにWALを転送
HBase Cluster Backup Cluster
WAL WALWALWAL
WAL転送
WAL
WAL反映
WAL転送ストレージ
107
バックアップ1日ごとのスナップショット取得
• 1日1回、Backup ClusterのHBaseのデータファイルをスナップショットとしてストレージにコピー
Backup Clusterスナップショット
スナップショット転送ストレージ
108
障害事例• FullGCによるRegionServerダウン• アプリケーションバグによるHot Regionの発生• Deleteを入れたことによるHot Regionの発生
109
FullGCによるRegionServerダウン• 事象
• RegionServerで数十秒のFullGCが発生し、ZookeeperとのセッションがタイムアウトになってしまったためRegionServerがダウン
• 一部サービスがスローダウン
• 原因• GC(CMS)でpromotion failedとconcurrent mode failureが発生• old領域でフラグメンテーションが発生し、old領域にオブジェクトが移動できず、GCのコンパクションにより数十秒のFullGCとなった
• 対応• 自動的なfailoverにより回復。• FullGCが発生したRegionServerプロセスの再起動• G1GCを検討中
110
アプリケーションバグによるHot Regionの発生• 事象
• 特定のRegionServerに対するアクセスがスローダウン
• 原因• アプリケーション側のバグにより、特定のRowに書き込み・読み込みが集中• KeyValueが増え過ぎたため、ScanのCPU負荷が上がった
• 対応• 緊急対応としてメジャーコンパクションを実施したところ、CPU負荷が低下• アプリケーションのバグフィックスを実施
111
Deleteを入れたことによるHot Regionの発生• 事象
• Columnの多いRowをDeleteしたところ、複数のRegionServerが応答しなくなった
• 原因• Columnの多いRowを削除した結果、削除したRowを含むScanに時間がかかるようになっていた
112
Deleteを入れたことによるHot Regionの発生
RowKey ColumnFamiy Column KeyType Timestamp value
key1 family col Put 100 1
key2 family col1 Put 100 1
key2 family col2 Put 300 2
key2 family col3 Put 200 3
key2 family colxxxxx Put 400 xxxxx
数十億件のColumn
␡␡␡
RegionServer
113
Deleteを入れたことによるHot Regionの発生
DeleteRowKey ColumnFamiy Column KeyType Timestamp value
key1 family col Put 100 1
key2 family DeleteFamily 1000
key2 family col1 Put 100 1
key2 family col2 Put 300 2
key2 family col3 Put 200 3
key2 family colxxxxx Put 400 xxxxx
␡␡␡
RegionServer
114
Deleteを入れたことによるHot Regionの発生
削除されたRowを含むScan
RowKey ColumnFamiy Column KeyType Timestamp value
key1 family col Put 100 1
key2 family DeleteFamily 1000
key2 family col1 Put 100 1
key2 family col2 Put 300 2
key2 family col3 Put 200 3
key2 family colxxxxx Put 400 xxxxx
␡␡␡
RegionServer
115
Deleteを入れたことによるHot Regionの発生
削除されたRowを含むScan
数十億件のColumnに対して削除されているかの判定が必要となる
RowKey ColumnFamiy Column KeyType Timestamp value
key1 family col Put 100 1
key2 family DeleteFamily 1000
key2 family col1 Put 100 1
key2 family col2 Put 300 2
key2 family col3 Put 200 3
key2 family colxxxxx Put 400 xxxxx
␡␡␡
RegionServer
116
Deleteを入れたことによるHot Regionの発生• 対応
• メジャーコンパクションを実施• Columnの多いRowを作る場合は注意する(なるべく作らない)
RowKey ColumnFamiy Column KeyType Timestamp value
key1 family col Put 100 1
数十億件のColumnを参照する必要がなくなったのでScan速度が改善
RegionServer
Zookeeperを用いたロック機能
118
Zookeeperとは分散アプリケーションのためのコーディネーションサービス
一般的な用途としては以下が挙げられる
• ロック• バリア• キュー• 2相コミット• リーダー選挙
119
Zookeeperについてアンサンブル
• アンサンブルと呼ばれるクラスタ上で動作する• アンサンブルの過半数が動作している限り、サービスは利用可能• データはレプリケートされる• アンサンブル中のメンバからリーダーと呼ばれるメンバを選出する• リーダーはメンバ間の協調動作をコントロールする
Server Server Server Server Server
リーダー
120
ZookeeperについてデータモデルUNIXのファイルシステムと同様に/でパスを区切る
/
/app1
/app1/p_1
/app2
/app1/p_2 /app1/p_3
121
Hornetにおけるロック機能についてHBaseにはトランザクションがないため、代替機能としてロック機能が必要となった。HornetではZookeeperを用いてロック機能を実現している
122
システム構成
hornet
Zookeeper×7台
123
ロックの規模
• 4万件/分(ピーク時)
124
Zookeeperの運用トピック• Gangliaでモニタリング
• 主にcpu_report、network_reportを確認。
• 定期的なトランザクションログとスナップショットの削除• Zookeeperに付属しているzkCleanup.shをオフピーク帯に実行。
125
障害事例• サーバ増設の手順ミス• リーダが決まらない• リーダのプロセスでFullGC発生
126
サーバ増設の手順ミス• 事象サーバ3台でアンサンブルを組んでいたZookeeperクラスタ(01,02,03)に、サーバ2台(04,05)を次の手順で追加しようとしたところ、Zookeeperがサービス不能になった
1. すべてのサーバの設定ファイルを更新(5台でアンサンブルを組む設定)2. 03がリーダーの状態で、01, 02, 03を一台ずつ再起動。3. 04, 05を起動
• 原因02の再起動時にアンサンブルが過半数割れを起こしたと見なされ、Zookeeperがサービス不能状態になった
• 対応3台構成だとオンラインでは増設できないので、 初から5台構成にしておくべき
127
リーダが決まらない• 事象
• ZookeeperのJVMのメモリの設定を変更するために、Zookeeperを一台ずつ再起動を実施
• リーダーの再起動時にZookeeperがサービス不能になり、ロック機能がダウン
• 原因• ログを確認したところ、リーダーを停止時に、リーダーエレクションが何度も繰り返されていた
• スナップショットの容量が大きく、各メンバに転送されるのに時間がかかったためタイムアウトが起こり、リーダーエレクションが何度も繰り返されていたと思われる。
• 対応• データを削除して、全Zookeeperプロセスの再起動
128
リーダのプロセスでFullGC発生• 事象Zookeeperへのアクセスが一時的にスローダウン。
一部のZookeeperプロセスでエラーが出続ける。
• 原因ZookeeperのトランザクションIDがあふれてしまっていた。
(ZOOKEEPER-1277, Fixバージョン:3.3.3, 3.4.4, 3.5.0, の事象に酷似)
リーダーエレクションがおこり、別のサーバがリーダになるが、ヒープをどんどん食いつぶしていき、やがてFullGCが発生する。
• 対応リーダーになっているZookeeperプロセスを定期的に再起動し、トランザクションIDをリセットする必要がある。
129
まとめ• 前半
• HBaseの概要・モデリングやアプリケーション設計のセオリーについて• Hornetではどのように設計していったか
• 後半• HBaesを運用し、得られたノウハウや知見について• Zookeeperを用いたロック機能を運用し、得られたノウハウや知見について
130
今後の展望• HornetのOSS化• 現在HornetはCDH4b1で運用しているが、CDH5へのアップグレードを検討中
131
余談ですが
• 弊社HBaseチームで、HBaseの書籍を執筆中です。• タイトルは「HBase徹底入門(仮)」• 翔泳社から出版予定• 乞うご期待!!!!!
132
後に
• Ameba Technology Lab ではエンジニアを 募集しています!
http://www.cyberagent.co.jp/recruit/career/
• Hadoop / HBase/ データマイニング / 機械学習/ 検索 などに 興味がある人はお声がけください。
ご清聴ありがとうございました。