สรุป HBase จากหนังสือ Seven Databases in Seven Weeks (pt. 2)
สรุป HBase ทั้งบทไว้ที่บทความเดียว เพิ่มเติมคือแถมสอนติดตั้งและ walk though ไปพร้อมๆกันได้✌️
Intro
หนังสือ Seven Databases in Seven weeks เป็นหนังสือที่เล่าถึง modern databases ที่ถูกหยิบมา 7 ตัว โดยจะเล่า database ทีละ chapter นั่นคือ PostgreSQL, Apache HBase, MongoDB, Apache CouchDB, Neo4J, DynamoDB, และ Redis
โดยผู้เขียนจะแบ่ง chapter นั้นเป็นการอ่านแบบ 3 วัน เพื่อที่ว่า 1 week นั้นผู้อ่านจะได้มีเวลาอ่านและทำแบบฝึกหัดไปด้วย
เราจึงเห็นว่าเป็นหนังสือที่ทำการเล่าเรื่องได้น่าสนใจ เลยลองสรุปเนื้อหาที่อ่านภายใน week ที่ 2 ดู นั่นก็คือ HBase
HBase
HBase คือ column-oriented database ที่เก็บข้อมูลขนาดใหญ่ ที่ run on top of Hadoop และ HDFS
History of HBase
จุดเริ่มต้นของ HBase เกิดจาก BigTable ที่พัฒนาโดย Google หลังจากที่ Google ได้ปล่อย white paper ที่ชื่อ “Bigtable: A Distributed Storage System for Structured Data” ในปี 2006
ส่วน HBase นั้นก็ได้ถูก release มาราวๆในปี 2007~2008 โดยถูกสร้างสำหรับ natural language processing และเป็น package ภายใต้ส่วนหนึ่งของ Apache Hadoop และจากนั้นก็กลายเป็นตัวท็อปๆของ Apache project เรื่อยมา
จะเห็นได้ว่า HBase จะอยู่ในฝั่ง open source (ไม่เสียตัง) ในขณะที่ Bigtable เป็น service หนึ่งภายใต้ Google Cloud Platform (เสียตัง) ที่ถูกเปิดให้ชาวเราเริ่มใช้ได้ในปี 2015
ฟังดูเผินๆแล้ว ดู HBase = Bigtable แต่ถ้าลอง migrate HBase application ไป Bigtable ก็ไม่ 100% compatible ขนาดนั้น แต่มีความคล้ายคลึงกันมาก
และเพื่อให้เห็นภาพว่า HBase หน้าตายังไง เราจึงมาทำความเข้าใจกับ HBase table กันก่อน
HBase Table
ใน programming language มักมี concept เรื่อง key-value map อย่าง
- JavaScript ก็มี objects
- Ruby มี hashes
- Go มี maps
- Python มี dictionaries
- Java มี hashmaps
table ใน HBase นั้นก็มีเรื่อง map เหมือนกัน แต่เป็น map of maps อีกที !
ลองนึกภาพตามประมาณนี้
hbase_table = { #table
'row1': { #Row Key
'cf1:col1': 'value1', #Column Family, column, and value
'cf2:col2': 'value2',
}
'row2': {
## more data
}
}
1 row จะประกอบไปด้วย Column Family ซึ่งใน Column Family ก็จะมี column 1 และ column 2 และทุก row จะแบ่งด้วย Row Keys เป็นตัว identify
ลองมาทำความเข้าใจในรูปตัวอย่าง
Row แรกจะมี column family ชื่อ color และมี 3 columns ข้างใน โดยมี red, blue, yellow เป็น qualifiers และมีค่า value ณ first/color:red เป็น ‘#F00’
และก็มี column family อีกตัวชื่อ shapeโดยมี column ชื่อ ‘square’ และมีค่า value ณ ตรงนี้เป็น ‘4'
จะเห็นได้ว่า HBase เป็น NoSQL ชัดเจน แต่อยู่ในรูปแบบของ table และเมื่อเก็บข้อมูลขนาดใหญ่ จึงไม่น่าแปลกที่มีต้นกำเนิดชื่อ “Bigtable”
HBase and friends
HBase เป็นส่วนหนึ่งใน Hadoop ecosystem แบบเมื่อพูดถึง HBase ก็จะเจอ Hadoop เสมอ และเพื่อนๆใน Apache ของเขา ไม่ว่า Apache Hive (data warehouse tool) และ Apache Pig (parallel processing tool)
Widely Usage
HBase ถือเป็นตัวที่ถูกใช้งานเยอะมากในการเรื่อง Big data ยกตัวอย่างบริษัทใหญ่ๆ เช่น
- Facebook ใช้ในเรื่อง messages, search indexing, และ stream analysis
- Twitter ใช้ในเรื่อง people search, monitoring and performance data
- Airbnb ใช้ในเรื่อง realtime stream processing
- และ eBay, Meetup, Ning, Yahoo! และอื่นๆ
- ข้าม Apple ไป เพราะนางไม่เคยบอก
Architecture
HBase ถูก design เพื่อมาเป็น fault tolerant (คือ system ยังคงทำงานได้อยู่แม้มีบางอย่าง fail หรือ crash เช่น node, network, etc.) นั่นคือ Write-ahead logging (WAL) และ distributed configuration
- Write-ahead logging (WAL) จะ write data ใน in-memory log ก่อนที่ permanent write จริงๆ เมื่อระบบ crash ขึ้นมา จะทำให้ failed node จะวิ่งไปหา log นี้แล้ว recovery ตัวเองได้
- Distributed configuration คือ node จะ rely กันเองสำหรับ config มากกว่าจะวิ่งไปหา centralized config
- ทำให้ HBase เกิดมาเหมาะกับ data ที่ scale ใหญ่ ถามว่าใหญ่ประมาณไหน ก็ถ้า มี cluster นึงรันแค่ 2–3 node แสดงว่าใช้ HBase ผิดทางละ
Mode
ก่อนที่จะเริ่มลุยกัน เรามารู้จัก runnning mode ทั้งหมดกันก่อน
- Standalone mode: single machine alone
- Pseudo-distributed mode: single node pretending to be a cluster
- Fully distributed mode: cluster of nodes working together
โดยตัวอย่างในหนังสือจะใช้ standalone mode เป็นหลัก ดังนั้นเราจะเซ็ตเป็น standalone mode เช่นกัน
Install on local
เนื่องจากเขานิยามตัวเองว่าหนังสือเล่มนี้ไม่ใช่ installation guide ดังนั้นเราจะมาลุย install HBase ด้วยตัวเอง (ไม่มีในหนังสือ งั้นฉันจะสอนเองก็ได้) โดยเราจะใช้ Docker เป็นตัวช่วย (เพราะว่าลง local เปลือยๆแล้วพังทู้กที) ดังนั้นหากจะทำตาม ทุกคนต้องมี Docker เป็น prerequisite ก่อนนะคะ
โดยเราไปยืม Docker Compose จาก repo นี้ และเราก็ clone มาเลย
$ git clone git@github.com:big-data-europe/docker-hbase.git
และเราก็รัน docker compose ด้วยคำสั่ง
$ docker-compose -f docker-compose-standalone.yml up -d
เมื่อเรา docker ps มา จะเห็นว่ามี container ชื่อ historyserver, hbase, nodemanger, namenode, datanode และ resource manager
เราจะเข้าไปตัว hbase container กันด้วยคำสั่ง
$ docker exec -it hbase bash
และลองเข้าไปใน path ที่ HBase อยู่ แล้ว ls ดู
$ cd /opt/hbase-1.2.6/bin/
$ ls
เราจะเห็นว่ามีไฟล์ start-hbase.sh
อยู่ด้วย ซึ่งปกติถ้าเราใช้ HBase เราจะต้องรันไฟล์ start-hbase.sh
นี้เอง (เวลารัน $ {HBASE_HOME}/bin/start-hbase.sh
) และใช้วิธีปิดด้วยไฟล์ stop-hbase.sh
แต่ docker-compose ที่เราใช้ใส่ command นี้เมื่อเรา up มาให้แล้ว
เริ่มต้น เราต้องเข้า interactive shell ก่อนด้วยคำสั่ง
$ hbase shell
ใน HBase shell จะเป็น JRuby-based command-line โดยในนี้ เราสามารถเพิ่มหรือลบ table หรือเปลี่ยน table schema ก็ได้หรือคำสั่งอื่นๆ
จะสังเกตได้ว่า เมื่อเราเข้ามาแล้ว ด้านหน้าจะเปลี่ยนไป คราวนี้เรามาลอง status ดู
hbase(main):001:0> status
1 active master, 0 backup masters, 1 servers, 1 dead, 3.0000 average load
จะเห็นว่ามี master และ server ด้วย เราจะมาลงรายละเอียดตรงนี้กัน
Zookeeper and HBase
ซึ่งปกติแล้ว Hbase จะมีไฟล์ conf/hbase-site.xml
เป็นเหมือน configuration file หน้าตาแบบรูปด้านล่าง
config เช่น บอกว่า จะสร้าง connection ระหว่าง master server และ region server ยังไง หรือ config เกี่ยวกับ Zookeeper เองก็ตาม
Zookeeper จะเป็นคนที่ทำหน้าที่เป็น coordination service ให้กับ HBase โดยทำเรื่อง configuration management, naming, synchronization และ group services
หรือพูดง่ายๆ Zookeeper คอยประสานงานในการคุยกันระหว่าง Master และ Slave node (Region Servers) ให้นั่นเอง
CRUD
คราวนี้ เรามาลองสร้าง table กัน
เราจะมาทำตามตัวอย่างในหนังสือ คือสร้าง table ที่ชื่อ wiki และมี column family ชื่อ text
และมี qualifier เป็น empty string ("
)
เราก็เริ่มสร้าง table ที่ชื่อ wiki ด้วยคำสั่ง
hbase(main):002:0> create 'wiki', 'text'
0 row(s) in 2.4070 seconds=> Hbase::Table - wiki
วิธีการสร้างคือ เราแค่ต้องระบุชื่อ table
และ column family
ความพิเศษของตรงนี้คือ เราสามารถสร้าง table เปล่าได้เลยโดยไม่ต้องระบุชื่อ column หรือ row เลย (ไม่ต้อง predefine)
ถ้าเราเข้า localhost:16010 จะเห็นว่า มี table โผล่ขึ้นมาชื่อ wiki แล้ว
Insert table
เราเพิ่มข้อมูลหน้า Home ลงไป ด้วยคำสั่ง Put
hbase(main):003:0* put 'wiki', 'Home', 'text:', 'Welcome to the wiki!'0 row(s) in 0.1400 seconds
Retrieve table
ลองดึงข้อมูลดู โดยต้องระบุชื่อ table
, row key
และ column family:column
hbase(main):011:0> get 'wiki', 'Home', 'text:'
COLUMN CELL
text: timestamp=1646316227754, value=Welcome to the wiki!1 row(s) in 0.3120 seconds
เราจะเห็นว่าใน 1 Cell มีทั้ง value และ timestamp
timestamp
ใน HBase เป็น integer ที่มีค่าเป็น milliseconds since the epoch (00:00:00 UTC on Jan 1, 1970)
ซึ่งสิ่งนี้คือสิ่งมหัศจรรย์ที่ HBase ทำให้ และกลายมาเป็นการสร้าง versioning
Update table
โจทย์หลักของเราต่อจากนี้ จะทำการปรับ wiki ให้รองรับ revision โดยที่ในแต่ละรอบ revision จะมี author, comment, timestamp และ text
สังเกตว่า title จะเป็นตัวเดิมในทุกครั้ง ไม่สามารถเปลี่ยนได้เพราะเป็น row keys หากอยากเปลี่ยนจริงๆต้องสร้างเป็น row ใหม่เท่านั้น
กลับมาที่ UI หากเรากดเข้าไปดูภายใน wiki
table จะเจอกับ description
สังเกตว่าตอนนี้ VERSIONS
เป็น 1
ในการที่เราจะแก้ไขข้อมูลใน table นั้น เราจำเป็นต้องให้ table นั้น offline ก่อน ด้วยคำสั่ง disable
hbase(main):012:0> disable 'wiki'
0 row(s) in 2.5040 seconds
เราจะปรับให้ value ของ VERSIONS
เป็นค่า Constant Field Value ที่ชื่อ ALL_VERSIONS
(variable ที่เปลี่ยนค่าไม่ได้ once ถูก assigned)
hbase(main):014:0> alter 'wiki', {NAME => 'text',
hbase* VERSIONS => org.apache.hadoop.hbase.HConstants::ALL_VERSIONS }Updating all regions with the new schema...
1/1 regions updated.
Done.
0 row(s) in 3.1040 seconds
เมื่อรันเสร็จแล้ว กลับมา refresh หน้า UI อีกครั้ง จะพบว่า value ใน VERSIONS
เปลี่ยนแล้ว
คราวนี้เราจะลองปรับข้อมูลด้วยการเพิ่ม revision
เข้ามาเป็นอีก column ใน column family ตัว text
hbase(main):015:0> alter 'wiki', {NAME => 'revision',
hbase* VERSIONS =>
org.apache.hadoop.hbase.HConstants::ALL_VERSIONS}Updating all regions with the new schema...
1/1 regions updated.
Done.
0 row(s) in 3.1300 seconds
เมื่อเราแก้ไขข้อมูล จะเห็นว่าใน UI มีอีกแถวเพิ่มเข้ามา (สังเกตคำว่า revision)
หลังจากแก้ไขแล้ว เราต้องปรับให้ table มา online ปกติด้วยคำสั่ง enable
hbase(main):016:0> enable 'wiki'
0 row(s) in 2.5680 seconds
เมื่อเราเข้าไปดูในหน้ารวม จะเห็นว่า table ถูก enable จาก false
→ true
แล้ว
Scripting
การพิมพ์ทีละ line ใน shell ดูไม่สะดวกเท่าไร มีอีกวิธีที่ทำได้คือเราจะสร้าง scripting ขึ้น ซึ่งจะรัน script นี้ผ่าน HBase shell ที่เป็น JRuby interpreter อีกที
เนื่องจากเราจะ coding ให้สะดวกขึ้น โดยจะแก้ code จาก vscode ภายในเครื่องเรา ดังนั้นเราจะแก้ Docker compose ให้ mount folder ที่เก็บ code เราเข้าไป เพื่อให้สามารถรัน HBase shell จากข้างใน container ได้
เราจะ down docker compose ก่อน
docker-compose -f docker-compose-standalone.yml down
เราเพิ่ม folder mils_script
ขึ้นมา แล้วแก้ไฟล์ docker-compose-standalone.yml
##docker-compose-standalone.yml
hbase:
image: bde2020/hbase-standalone:1.0.0-hbase1.2.6
container_name: hbase
volumes:
- hbase_data:/hbase-data
- hbase_zookeeper_data:/zookeeper-data
- ./mils_script:/opt/mils_script ### <--mount เข้าไปใน container
แล้ว up ใหม่
docker-compose -f docker-compose-standalone.yml up -d
แต่ก่อนอื่น เรามา recap โจทย์กันอีกที
เราจะสร้างไฟล์ put_multiple_columns.rb
(อย่าลืม วางใน folder mils_script
)
require 'java'
import 'org.apache.hadoop.hbase.client.HTable'
import 'org.apache.hadoop.hbase.client.Put'table = HTable.new(@hbase.configuration, "wiki")def jbytes(*args)
args.map {|arg| arg.to_s.to_java_bytes}
endp = Put.new(*jbytes("Home"))p.add(*jbytes("text", "", "Hello world"))
p.add(*jbytes("revision", "author", "mils"))
p.add(*jbytes("revision", "comment", "my first edit"))table.put(p)
คราวนี้เรากลับเข้าไป เพื่อรันไฟล์นี้ด้วย HBase shell
root@1fe15ab95bbd:# cd /opt/hbase-1.2.6/binroot@1fe15ab95bbd:/opt/hbase-1.2.6/bin# hbase shell ../../mils_script/put_multiple_columns.rb
หากเราเข้า interpreter เข้ามาดู table อีกครั้ง
hbase(main):001:0> get 'wiki', 'Home'
COLUMN CELL
revision:author timestamp=1646453248931, value=mils
revision:comment timestamp=1646453248931, value=I love this wiki
text: timestamp=1646453248931, value=Hello world3 row(s) in 0.8210 seconds
จะเห็นว่า มี author และ comment เข้ามาแล้ว และ text ก็เปลี่ยนไป เย้
Why Column Families?
ทำไมเราไม่เก็บข้อมูลทั้ง row ไว้ใน column family เดียวเลยล่ะ ? คำตอบคือได้ และได้ผลเรื่อง performance ด้วย เนื่องจากแต่ละ column family จะเก็บ directories แยกกัน ทำให้เวลาอ่านเป็น row ก็หลีกเลี่ยงในการ read ข้าม region ได้
ตัว official document เองก็แนะนำว่า อย่าพยายามมา column families มากกว่า 2–3 ตัว พยายามมีน้อยๆเข้าไว้
Compression & Bloom Filter
HBase support 2 compression algorithms คือ Gzip (GZ) และ Lempel-Ziv-Oberhumer (LZO)
แต่เนื่องจาก LZO ติด license ฝั่ง GPL-licensed (ขณะที่ HBase เป็น Apache-licensed) เขาจึงแนะนำให้ใช้ GZ แทน
เพิ่มเติมคือในปัจจุบัน HBase support compression algorithms อื่นๆแล้ว เช่น SNAPPY, LZ4, BZIP2 , etc แล้ว
ส่วน Bloom filter เป็น data structure อันนึงที่ popular มากใน data storage application เพราะมันเข้ามาช่วยในเรื่องของการ check หา key ว่า exist อยู่ไหม และช่วยลดเรื่อง expensive query ได้
Strength of HBase
- ความสามารถในการ scale out
- ดังนั้นจึงเหมาะกับเคสที่มีข้อมูลขนาดใหญ่ เช่น ขนาด terabytes หรือใหญ่กว่า
- มี build-in versioning
Weakness of HBase
- Scale out but not scale down เพราะถูก design มาให้รับงาน scaleใหญ่
- HBase จะไม่ถูก deployed alone เพราะต้องมีผองเพื่อนอย่าง ZooKeeper และ Hadoop พ่วงไปด้วยเป็น ecosystem
- HBase ไม่ provide เรื่อง sorting หรือ indexing นอกจากด้วยตัว row keys ได้ ถ้าเราอยากจะหา row ด้วยอย่างอื่นเช่น column เราอาจจะต้อง scan ทั้ง table
- ใน HBase ไม่มี data type พวก integer, float, string หรือ date แต่ทุกอย่างจะถูก treat เป็น byte array หมด
Reader’s comment
สิ่งที่ไม่ชอบในบท HBase คือ หนังสือไม่เน้นอธิบายเรื่อง Zookeeper, Master Node, Region server, HDFS หรือ การทำงานแบบ distributed ให้เท่าไร (ซึ่งเราก็ไปหาอธิบายเอาเอง)
แต่ไปเน้น AWS EMR แทน ซึ่ง dedicate day 3 ทั้งวัน (ถ้ายังจำได้ หนังสือจะแบ่งเนื้อหาเป็น 3 วันอ่าน) แต่หลักจะเป็นการ setup ด้วย command line เมื่อเซ็ตเสร็จก็รัน HBase shell แล้วก็ปิด.. terminate.. จบ..
ส่วนตัวคิดว่า ถ้าเน้นเนื้อหาไปอธิบายองค์ประกอบของ HBase น่าจะสำคัญกว่าวิธี setup service ที่รันผ่าน command รัวๆโดยเน้นแค่ practice อย่างเดียว อาจจะมีประโยชน์มากกว่า ขณะเดียวกัน ก็เข้าใจว่าผู้เขียนคงอยากให้หนังสือทันสมัย จึง dedicate วันนี้เป็นการใช้ service บน cloud
Wrap Up
ในบทของ HBase เราได้เรียนรู้ว่า HBase เหมาะกับงาน Big Data ขนานแท้ และเป็นส่วนหนึ่งที่สำคัญใน Hadoop ecosystem ที่มีผองเพื่อนมากมายในแก๊ง Apache และผองเพื่อนฝั่ง architecture อย่าง Zookeeper, Master node, Region node
เรายังได้ติดตั้ง HBase เพื่อเล่นบน local ผ่าน Docker, ลอง CRUD กับข้อมูล และจัดการข้อมูลผ่าน script แทนที่จะรันทีละคำสั่งผ่าน hbase shell
ที่สำคัญเรายังรู้ว่า HBase เป็น NoSQL ที่ในร่างของ table ซึ่งซับซ้อนกว่า relational database เยอะเลย