สรุป HBase จากหนังสือ Seven Databases in Seven Weeks (pt. 2)

Burasakorn Sabyeying
Mils’ Blog
Published in
8 min readMar 6, 2022

สรุป 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 ตัวเองได้
cr. https://nag-9-s.gitbook.io/hbase/hbase-write
  • 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) ให้นั่นเอง

cr. https://www.guru99.com/hbase-architecture-data-flow-usecases.html

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 จาก falsetrue แล้ว

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 โจทย์กันอีกที

ลองแปลงโจทย์เมื่อกี้เป็น HBase table ดู

เราจะสร้างไฟล์ 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}
end
p = 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 world
3 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

Bloom Filter and Compression

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 เยอะเลย

--

--

Burasakorn Sabyeying
Mils’ Blog

Data engineer at CJ Express. GDE in Cloud. Women Techmakers Ambassador. Co-lead GDG Cloud Bangkok. Other channel > Mesodiar.com