160 likes | 332 Views
Seven Databases in Seven Weeks. HBase. ふつかめ. Hbase とは何か. 復習. Google の 内部システム (発表した論文より). Hadoop プロジェクト ( Google クローン). バッチ処理. リアルタイム応答. MapReduce. BigTable. MapReduce. HBase. Google File Sytem (GFS). Hadoop Distributed File Sytem (HDFS). BigTable ( ソート済列志向 データベース ). 復習.
E N D
Seven Databases in Seven Weeks HBase ふつかめ
Hbaseとは何か 復習 Googleの 内部システム (発表した論文より) Hadoopプロジェクト(Googleクローン) バッチ処理 リアルタイム応答 MapReduce BigTable MapReduce HBase Google File Sytem (GFS) Hadoop Distributed File Sytem (HDFS)
BigTable(ソート済列志向データベース) 復習 スキーマで定義する スキーマレス(自由に追加できる) 必須 ソート済 あるColumn timestamp 5 #F00 timestamp 4 #00F timestamp 3 タイムスタンプでバージョニングされる #0F0 timestamp 2 #000 timestamp 1 #FFF
リージョン分割・自動シャーディング 復習 リージョン リージョン リージョン リージョン リージョン リージョン • テーブルはリージョンで物理的に分割(シャーディング)される • リージョンはクラスタ中のリージョンサーバが担当する • リージョンは ColumnFamily毎に作られる • リージョンは ソート済のRowKeyを適当なサイズで分割する
HBaseの特徴 復習 自動シャーディング・自動フェールオーバー テーブルサイズが大きくなった時、自動的に分割する 分割されたシャードは、ノード障害時に自動的にフェールオーバーする データの一貫性 (CAP:Consistency) データの更新は反映された瞬間から読出可能 結果的に同じ値が読めるようになる(結果整合性)条件緩和を取らない Hadoop/HDFS 統合 Hadoopの HDFS 上 に展開できる Hadoop/MapReduceでAPIを挟まず HBaseを入出力の対象にできる
7つのデータベース7つの世界 での構成 1日目:CRUDとテーブル管理 スタンドアロンでHbaseを動かす テーブルを作る データの出し入れをする 2日目:ビッグデータを扱う Wikipedia ダンプを投入する スクリプト (Not Shell) での操作に慣れる 3日目:クラウドに持っていく Thrift を使って操作する 今回は扱いません 今回は扱いません Whirr を使って EC2 にデプロイする
サンプルデータ <mediawikixmlns=http://www.mediawiki.org/xml/export-0.8/ xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://www.mediawiki.org/xml/export-0.8/ http://www.mediawiki.org/xml/export-0.8.xsd version="0.8"xml:lang="ja"> <siteinfo> <sitename>Wikipedia</sitename> <base>http://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8</base> <generator>MediaWiki 1.22wmf2</generator> <case>first-letter</case> <namespaces> <namespacekey="-2"case="first-letter">メディア</namespace> <namespacekey="-1"case="first-letter">特別</namespace> <namespacekey="0"case="first-letter"/> </namespaces> </siteinfo> <page> <title>アンパサンド</title> <ns>0</ns> <id>5</id> <revision> <id>46524710</id> <parentid>44911376</parentid> <timestamp>2013-03-06T22:31:33Z</timestamp> <contributor> <username>Addbot</username> <id>712937</id> </contributor> <minor/> <comment>ボット: 言語間リンク 31 件を[[d:|ウィキデータ]]上の [[d:q11213]] に転記</comment> <textxml:space="preserve">{{記号文字|&amp;}} [[Image:Trebuchet MS ampersand.svg|right|thumb|100px|[[Trebuchet MS]] フォント]] [[Category:ラテン語の語句]]</text> <sha1>4duebxtzaadjddpy3036cey6451d992</sha1> <model>wikitext</model> <format>text/x-wiki</format> </revision> </page> <page> …
サンプルデータ <mediawikixmlns=http://www.mediawiki.org/xml/export-0.8/ xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://www.mediawiki.org/xml/export-0.8/ http://www.mediawiki.org/xml/export-0.8.xsd version="0.8"xml:lang="ja"> <siteinfo> <sitename>Wikipedia</sitename> <base>http://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8</base> <generator>MediaWiki 1.22wmf2</generator> <case>first-letter</case> <namespaces> <namespacekey="-2"case="first-letter">メディア</namespace> <namespacekey="-1"case="first-letter">特別</namespace> <namespacekey="0"case="first-letter"/> </namespaces> </siteinfo> <page> <title>アンパサンド</title> <ns>0</ns> <id>5</id> <revision> <id>46524710</id> <parentid>44911376</parentid> <timestamp>2013-03-06T22:31:33Z</timestamp> <contributor> <username>Addbot</username> <id>712937</id> </contributor> <minor/> <comment>ボット: 言語間リンク 31 件を[[d:|ウィキデータ]]上の [[d:q11213]] に転記</comment> <textxml:space="preserve">{{記号文字|&amp;}} [[Image:Trebuchet MS ampersand.svg|right|thumb|100px|[[Trebuchet MS]] フォント]] [[Category:ラテン語の語句]]</text> <sha1>4duebxtzaadjddpy3036cey6451d992</sha1> <model>wikitext</model> <format>text/x-wiki</format> </revision> </page> <page> …
スキーマ作成 hbase(main):004:0> create'wiki', 'id', 'text', 'revision' 0row(s) in2.4180 seconds hbase(main):005:0> disable 'wiki' 0row(s) in2.3650 seconds hbase(main):006:0> alter'wiki', {NAME=>'text', COMPRESSION=>'GZ', BLOOMFILTER=>'ROW'} Updating all regions with the new schema... 1/1 regions updated. Done. 0row(s) in1.2860 seconds hbase(main):007:0> enable 'wiki' 0row(s) in2.7430 seconds スキーマ定義 ColumnFamily:Textの 圧縮・BloomFilter有効 BloomFilter リージョン中の RowKey/ColmnFamily リージョン中に指定した RowKey/ColumnFamily がないことを高速に検知する • ‘ROW’ : RowKeyのみ • 'ROWCOL' : RowKey/ColumnFamily クエリ
データ投入用コード include Java import org.apache.hadoop.hbase.client.HTable import org.apache.hadoop.hbase.client.Put import org.apache.hadoop.hbase.HBaseConfiguration import javax.xml.stream.XMLStreamConstants require "time" defjbytes(*args) args.map { |arg| arg.to_s.to_java_bytes } end factory = javax.xml.stream.XMLInputFactory.newInstance reader = factory.createXMLStreamReader(java.lang.System.in) table = HTable.new( HBaseConfiguration.new, "wiki" ) document = nil buffer = nil count = 0 while reader.has_next type = reader.next if type == XMLStreamConstants::START_ELEMENT tag = reader.local_name case tag when'page'then document = {} when/title|id|parentid|timestamp|text/then buffer = [] end elsif type == XMLStreamConstants::CHARACTERS text = reader.text buffer << text unless buffer.nil? elsif type == XMLStreamConstants::END_ELEMENT tag = reader.local_name case tag when/title|id|parentid|timestamp|text/then document[tag] = buffer.join when'revision' key = document['title'].to_java_bytes ts = (Time.parse document['timestamp']).to_i p = Put.new(key , ts) p.add( *jbytes("text", "", document['text']) ) p.add( *jbytes("id", "", document['id']) ) p.add( *jbytes("revision", "parendid", document['parentid']) ) table.put(p) count += 1 table.flushCommits() if count % 50 == 0 puts "#{count} records inserted (#{document['title']})"if count % 1000 == 0 end end end table.flushCommits() puts "#{count}" exit 実行例 [root@HBase01 opt]# cat jawiki-latest-pages-meta-current.xml | time hbase-0.94.7/bin/hbase org.jruby.Main hoge.rb 2362613 860.30user 172.80system 28:29.00elapsed 60%CPU (0avgtext+0avgdata 696352maxresident)k 304inputs+4072outputs (0major+91296minor)pagefaults 0swaps
データ投入用コード document = nil buffer = nil count = 0 while reader.has_next type = reader.next if type == XMLStreamConstants::START_ELEMENT tag = reader.local_name case tag when'page'then document = {} when/title|id|parentid|timestamp|text/then buffer = [] end elsif type == XMLStreamConstants::CHARACTERS text = reader.text buffer << text unlessbuffer.nil? elsif type == XMLStreamConstants::END_ELEMENT tag = reader.local_name case tag when/title|id|parentid|timestamp|text/ document[tag] = buffer.join when'revision' key = document['title'].to_java_bytes ts = (Time.parse document['timestamp']).to_i p = Put.new(key , ts) p.add( *jbytes("text", "", document['text']) ) p.add( *jbytes("id", "", document['id']) ) p.add( *jbytes("revision", "parendid", document['parentid']) ) table.put(p) count += 1 table.flushCommits() if count % 50 == 0 • if count % 1000 == 0 puts "#{count} records inserted (#{document['title']})“ • end end end end table.flushCommits() puts "#{count}" exit 開始タグ タグ内要素 終了タグ <page> <title>アンパサンド</title> <ns>0</ns> <id>5</id> <revision> <id>46524710</id> <parentid>44911376</parentid> <timestamp>2013-03-06T22:31:33Z</timestamp> <contributor> <username>Addbot</username> <id>712937</id> </contributor> <minor/> <comment>…</comment> <textxml:space="preserve">…</text> <sha1>4duebxtzaadjddpy3036cey6451d992</sha1> <model>wikitext</model> <format>text/x-wiki</format> </revision> </page> <page> … 投入
実験 投入時 Q: text領域のGZ圧縮により高速化するのか? A: 46min -> 26min(70%高速化) Q: text領域のGZ圧縮によりデータ領域は節約されるのか? A: 8.1GB -> 2.6GB (32%のサイズに圧縮) 取出し時 Q: text領域のGZ圧縮によりgetは高速化するのか? A: 有意な差がない Q: 全体 scan と部分 scan での速度差は? A: 0.136[s] (開始RowKey指定,10件) vs119.738[s](全体,Column値条件検索) Q: text領域のGZ圧縮によりscanは高速化するのか? A: 条件による(次ページ)
GZ圧縮とText(大きなColumnFamily)とscan リージョン リージョン リージョン リージョン リージョン リージョン • hbase(main):001:0> scan 'wiki' , {COLUMN=>['id','revision'], FILTER => "SingleColumnValueFilter('revision','parendid',=,'binary:46628036')"} • hbase(main):001:0> scan 'wiki' , {FILTER => "SingleColumnValueFilter('revision','parendid',=,'binary:46628036')"} hbase(main):001:0> scan 'wiki' , {FILTER => "SingleColumnValueFilter('text','',=,'substring:ぱんだねこ')"}