Chiến lược thiết kế RowKey để tối ưu hiệu năng phân tán
RowKey là yếu tố quyết định cách dữ liệu được phân phối và truy vấn trong HBase. Thiết kế sai RowKey sẽ dẫn đến hiện tượng "Hotspot", khiến một RegionServer chịu tải quá lớn trong khi các node khác rảnh rỗi.
Tránh sử dụng timestamp đơn thuần hoặc số tự tăng liên tục (Auto-increment) làm RowKey trực tiếp. Dữ liệu sẽ dồn về Region cuối cùng, gây nghẽn cổ chai.
Sử dụng kỹ thuật "Salting" hoặc "Hashing" để phân tán dữ liệu đều khắp các Region. Ví dụ: thêm một tiền tố ngẫu nhiên hoặc băm (hash) một phần của ID để đảo lộn thứ tự sắp xếp tự nhiên.
Thực hiện kiểm tra phân bố dữ liệu bằng lệnh sau trong HBase Shell để đảm bảo dữ liệu không tập trung vào một Region duy nhất.
hbase shell -e "scan 'users' | grep 'ROW' | cut -d'=' -f2 | sort | uniq -c | sort -rn | head -10"
Kết quả mong đợi: Số lượng dòng dữ liệu cho mỗi RowKey đầu tiên (prefix) phải tương đối đồng đều, không có giá trị nào vượt trội gấp 5-10 lần so với mức trung bình.
Tạo Table với Column Family và thuộc tính lưu trữ nâng cao
HBase cho phép định nghĩa các thuộc tính lưu trữ tại thời điểm tạo Table để tối ưu hiệu năng đọc/ghi và quản lý vòng đời dữ liệu.
Sử dụng lệnh create trong HBase Shell để tạo bảng với các tham số: BLOCKSIZE để điều chỉnh kích thước block đọc từ HDFS, và TTL (Time To Live) để tự động xóa dữ liệu cũ.
Tạo bảng sensor_data với 2 Column Family: readings (lưu dữ liệu cảm biến, TTL 30 ngày) và meta (lưu thông tin thiết bị, TTL vĩnh viễn, BlockSize 64KB).
create 'sensor_data', {NAME => 'readings', VERSIONS => 1, TTL => 30 * 24 * 60 * 60, BLOCKSIZE => 65536}, {NAME => 'meta', VERSIONS => 5, TTL => 0, BLOCKSIZE => 65536}
Kết quả mong đợi: HBase trả về thông báo "Table 'sensor_data' created" và hiển thị danh sách các Column Family cùng thuộc tính cấu hình của chúng.
Để xem chi tiết cấu hình của bảng vừa tạo và xác nhận các thuộc tính đã được áp dụng đúng, sử dụng lệnh describe.
describe 'sensor_data'
Kết quả mong đợi: Hiển thị thông tin chi tiết về bảng, bao gồm số lượng Region, các Column Family, và các giá trị TTL/BLOCKSIZE tương ứng với từng family.
Thực hiện các thao tác dữ liệu cơ bản và nâng cao trong HBase Shell
Sử dụng HBase Shell để thực hiện các thao tác CRUD (Create, Read, Update, Delete) trực tiếp lên dữ liệu trong bảng sensor_data.
Thực hiện lệnh put để ghi dữ liệu vào bảng. Cú pháp: put 'table', 'rowkey', 'columnFamily:qualifier', 'value', 'timestamp'.
put 'sensor_data', 'sensor_001#2023-10-27T10:00:00', 'readings:temperature', '25.5', '1698369600000'
Kết quả mong đợi: Không có đầu ra (hoặc thông báo thành công tùy phiên bản), dữ liệu đã được ghi vào Region tương ứng với RowKey.
Thực hiện lệnh get để lấy dữ liệu theo RowKey cụ thể. Có thể chỉ định lấy một Column Family hoặc toàn bộ.
get 'sensor_data', 'sensor_001#2023-10-27T10:00:00', {COLUMN => 'readings:temperature'}
Kết quả mong đợi: Hiển thị 1 dòng dữ liệu với giá trị '25.5' và timestamp tương ứng.
Sử dụng lệnh scan với các bộ lọc (Filter) để truy vấn dữ liệu phức tạp. Ví dụ: quét tất cả dữ liệu trong Column Family 'readings' có giá trị lớn hơn 20.
scan 'sensor_data', {FILTER => "SingleColumnValueFilter('readings', 'temperature', COMPARATOR => '>', '20')"
Kết quả mong đợi: Danh sách các RowKey chứa dữ liệu nhiệt độ lớn hơn 20, giúp kiểm tra hiệu quả của bộ lọc.
Thực hiện lệnh delete để xóa dữ liệu. Lưu ý: Có thể xóa một cell cụ thể, một column qualifier, hoặc toàn bộ row.
delete 'sensor_data', 'sensor_001#2023-10-27T10:00:00', 'readings:temperature'
Kết quả mong đợi: Cell được xóa, khi chạy lại lệnh get sẽ không còn trả về giá trị của cell đó (nhưng RowKey vẫn tồn tại nếu còn cell khác).
Sử dụng HBase REST API để thao tác dữ liệu từ ứng dụng
HBase REST Server cho phép ứng dụng bên ngoài (Java, Python, Go) tương tác với HBase qua giao thức HTTP/JSON mà không cần client library Java.
Bắt đầu dịch vụ REST Server nếu chưa chạy. Đảm bảo biến môi trường HBASE_HOME đã được set đúng.
HBASE_HOME/bin/hbase-daemon.sh start rest
Kết quả mong đợi: REST Server khởi động và lắng nghe trên cổng 8080 (mặc định). Kiểm tra bằng lệnh ps aux | grep hbase-rest.
Thực hiện lệnh PUT qua HTTP để thêm dữ liệu mới vào bảng. Định dạng payload là JSON, RowKey được đặt trong trường row.
curl -X PUT -H "Content-Type: application/json" -d '{"row": "sensor_002", "family": "readings", "qualifier": "humidity", "value": "80"}' http://localhost:8080/sensor_data/sensor_002
Kết quả mong đợi: Trả về mã trạng thái 200 (OK) hoặc 201 (Created) với body JSON xác nhận thao tác thành công.
Thực hiện lệnh GET để lấy dữ liệu của một RowKey cụ thể qua HTTP.
curl -v http://localhost:8080/sensor_data/sensor_002
Kết quả mong đợi: Trả về mã trạng thái 200 và nội dung JSON chứa dữ liệu của RowKey đó, bao gồm Column Family và các giá trị.
Thực hiện lệnh DELETE để xóa một RowKey hoặc cell cụ thể.
curl -X DELETE http://localhost:8080/sensor_data/sensor_002
Kết quả mong đợi: Trả về mã trạng thái 200 (OK) hoặc 204 (No Content), xác nhận Row đã được xóa khỏi HBase.
Verify kết quả bằng cách scan toàn bộ bảng qua REST API để đảm bảo dữ liệu đã được cập nhật đúng.
curl http://localhost:8080/sensor_data/
Kết quả mong đợi: Trả về danh sách JSON của tất cả các Row hiện có trong bảng (có thể cần thêm tham số ?limit=10 nếu dữ liệu lớn).
Cấu hình Compaction và Split để quản lý file HFile
Compaction là quá trình hợp nhất nhiều HFile nhỏ thành HFile lớn hơn để tối ưu hiệu năng đọc. Split là quá trình chia Region khi kích thước vượt ngưỡng để cân bằng tải.
Thay đổi ngưỡng kích thước để kích hoạt Split Region mặc định từ 10GB xuống 1GB để test trên môi trường demo, giúp Region chia nhỏ nhanh hơn.
alter 'sensor_data', {NAME => 'hbase.regionserver.hfile.split.size', VALUE => '1073741824'}
Kết quả mong đợi: Bảng được cập nhật cấu hình. Khi dữ liệu trong một Region vượt quá 1GB, HBase sẽ tự động chia Region đó thành 2.
Cấu hình Compaction thông qua file
hbase-site.xml để điều chỉnh hành vi của Major Compaction và Minor Compaction.
Tạo file cấu hình tại /etc/hbase/conf/hbase-site.xml (hoặc đường dẫn tương ứng trên hệ thống của bạn) với nội dung sau để tăng số lượng file HFile tối đa trước khi kích hoạt Minor Compaction.
<configuration>
<property>
<name>hbase.regionserver.compaction.threshold</name>
<value>20</value>
<description>Số lượng HFile tối đa trước khi kích hoạt compaction</description>
</property>
<property>
<name>hbase.regionserver.compaction.max.size</name>
<value>2147483648</value>
<description>Kích thước tối đa của HFile sau khi compaction (2GB)</description>
</property>
<property>
<name>hbase.regionserver.compaction.period</name>
<value>3600</value>
<description>Chu kỳ kiểm tra compaction (60 phút)</description>
</property>
</configuration>
Kết quả mong đợi: Sau khi khởi động lại HBase, các Region sẽ thực hiện compaction khi số lượng HFile đạt 20, giúp giảm độ trễ khi đọc.
Thực hiện lệnh compact thủ công trên một Region cụ thể để ép buộc quá trình hợp nhất file ngay lập tức (thường dùng khi cần dọn dẹp sau bulk load).
compact 'sensor_data'
Kết quả mong đợi: HBase thực hiện compaction trên tất cả các Region của bảng. Có thể theo dõi tiến trình bằng hbase status hoặc logs.
Verify kết quả bằng cách kiểm tra số lượng HFile trên HDFS trong thư mục lưu trữ của bảng.
hdfs dfs -ls /hbase/data/sensor_data | grep .hfile | wc -l
Kết quả mong đợi: Số lượng file HFile giảm đi đáng kể sau khi thực hiện compaction so với trước đó, chứng tỏ các file nhỏ đã được hợp nhất.
Để kiểm tra trạng thái Split, sử dụng lệnh status trong HBase Shell để xem số lượng Region hiện tại của bảng.
status 'sensor_data'
Kết quả mong đợi: Nếu dữ liệu đã vượt ngưỡng 1GB (theo cấu hình ở trên), số lượng Region sẽ tăng lên, chứng tỏ Split đã diễn ra.
Điều hướng series:
Mục lục: Series: Triển khai Database phân tán với Apache HBase trên Ubuntu 24.04
« Phần 4: Triển khai HBase Distributed Mode trên cụm đa node
Phần 6: Tích hợp HBase với Ecosystem: Phoenix và Spark »