设计重点
HBase模式的重点有两个:Rowkey 和 Column Family
Rowkey的设计
Rowkey设计是HBase模式设计中最重要的事情
1、HBase数据基于Rowkey有序存储。Rowkey是HBase表的唯一索引,借助Rowkey对HBase表的访问能实现高效的二分查找,非Rowkey的访问只能通过全表扫描实现。
2、region根据有序的Rowkey进行划分
Rowkey的一个经典的设计是:id+时间戳,这种设计充分利用了HBase表中行键有序存储的特性。这种设计可以将id相关数据聚合在一起。
Rowkey要尽量均匀分布
要充分利用散列算法将Rowkey均匀分散开来,这样各个region存储的rowkey基本均衡,避免了个别region承担过多的读写负载
Rowkey的长度尽量短
1、时间尽量用long来表示,而不是字符串
2、尽量使用编码压缩
关于Join
HBase不支持表间连接!表间连接一般通过反范式设计,即冗余存储来实现。
列族设计
HBase数据表对行进行水平分片得到region。region单独完整地存储(HDFS冗余备份对上层的HBase不可见)在某台服务器上。region按列族进行垂直分片得到store,每一个列族对应一个store。store数据不断刷写得到HFile,最后HFile落实到HDFS中存储。
列族设计原则如下:
1、在满足业务需求的情况下,列族越少越好,这样可以将flush和compaction操作限制在一个region里面进行,这样可以减少不必要的I/O负载。
2、不同列族的数据要均衡
打个比方,T1表有两个列族F1、F2。F1有10w条数据,F2有1ww条数据。这样F1将会稀疏地分散到很多地region中,导致F1地扫描效率降低。这是数据条目地均衡
再打个比方,T1表有两个列族F1、F2。F1和F2在数据条目上是均衡的。可是F1每条数据的大小是1K,F2每条数据的大小是1G,那么F1依然会稀疏地分散到很多地region中,导致F1地扫描效率降低。
典型案例剖析:图书馆借书
核心业务需求:查询某同学在图书馆借了那些书,查询某本书是被谁借走了
RDBMS设计
学生表:
PK | stu_name | stu_num | stu_info |
图书表
PK | book_name | book_num | book_info |
借书关系
PK | FK:stu_PK | FK:book_PK |
1、某同学借了那些书
1.1、根据学生学号,查到行数据(遍历学生表,如果在学号上建立了索引可以提高查询效率),取出stu_PK
1.2、根据stu_PK,查出对应的数据集(遍历借书关系表,如果在FK:stu_PK上建立了索引可以提高查询效率)
1.3、根据1.2查出的数据集取出book_PK集,到图书表中匹配,图书行数据(双遍历,取出的book_PK集*图书表book_PK,由于图书表book_PK有索引,速度会加快)
2、某书被谁借走了
跟“某同学借了那些书”差不多
HBase设计
本文暂且采取宽表设计,也可采取高表设计
学生借书表
Rowkey=stu_num | borrow_info | |||||
stu_name | stu_info | book_num1 | book_num2 | ... | book_numN | |
1 | 0 | 1 | 0 |
图书借阅表
Rowkey=book_num | borrowed_info | |||||
book_name | book_info | stu_num1 | stu_num2 | ... | stu_numN | |
1 | 0 | 0 | 0 |
这种设计更为直接,借书关系实际上在两张表里面都有存储。这样的冗余存储解决了HBase不支持join的缺陷。这种冗余存储方式在还书的时候出现了麻烦。理想情况下,还书的时候,希望学生借书表里面borrow:book_num*里面的计数器要修改,同时图书借阅表中stu_num*中的计数器也要修改。坑爹的是HBase又不支持跨表/行事务。这样极容易导致数据库的不一致性!其实不一致性并不可怕,只要不一致性可以得到合理的解释,HBase仍然能在不一致的情况下正确工作。我们下面结合这个例子来具体分析下:
首先,我们在还书的时候肯定要发出两条修改命令。这两条命令各自是原子的,但是整体不是原子的。这两条命令在大多数时候是可以正确运行的。不一致情况如下:
1、两条命令都成功,但是时间间隔有点长,在此间隔时间内数据库状态时不一致的
2、其中一条命令失败,此后数据库状态都是不一致的
还书的意义在于
1、证明学生名下已经没有这本书了
2、看看此书是否被占用,即是否可以被借出
我们看看第一点,证明学生名下有无这本书。这个显然要通过学生借书表来体现。
我们看看第二点,看看此书是否可以被借出。当一个学生从图书馆的书架上拿着这本书来找管理员借阅的时候,其实已经证明了书是可以借阅的。何须查询数据库,然后告诉学生可否被借阅?
这样,我们就定义不一致数据的解释:是否还书,以学生借书表为准!这样,在还书的时候,虽然还是两条修改命令都发出,但是还书操作以学生借书表是否成功修改为准。判断是否还书也以学生借书表为准!如果出现不一致状态,以学生借书表为准!