HBase在设计时需要注意以下几个方面。
1、Pre-Creating Regions的设计。默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大才进行分割。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群中做数据的负载均衡。
2、Row key的设计。HBase中row key用来检索表中的记录,支持一下三种方式:通过单个row key访问:即按照某个row key键值进行get 操作。通过row key的range进行scan即通过设置startRowKey和endRowKey,在这个范围内扫描。全表扫描:即直接扫描整张表内的所有行记录。在HBase中,row key可以是任意字符串,最大是64KB,实际应用中一般为10-100bytes,存储为byte[]字节数组,一般设计为定长的。Row key是按字典序存储的,因此在设计row key时,要充分利用这个排序特点,将经常一起读写的数据存储在一起,将最近可能会被访问的数据放在一起。如果最近写入HBase表中的数据时最可能被访问的,可以考虑将时间戳作为row key的一部分,由于是字典序排序,所以可以将Long.MAX_VAlUE - timestamp作为row key,这样能保证新写入的数据在读取时可以是被快速命中的。
3、Column Family的设计。不要在一张表中定义太对的column family。最好不要超过2-3个。因为某个column family在flush的时候,它临近的column family也会因关联效应被触发flush,导致系统产生更多的IO。
4、In Memory的设计。在创建表的时候,通过HColumnDescriptor.setInMemory(true)将表放在RegionServer的缓存中,保证在读取的时候被cache命中。
5、MaxVersion的设计。在创建表的时候,通过HColumnDescriptor.setMaxVersion(int maxVersion)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersion(1)。
6、Time To Live的设计。通过HColumnDescriptor.setTimeToLive(int timeToLive)设置表中数据的存储生命期,过期数据会被自动删除,如果只需要存储最近两天的数据,可以设置setTimeToLive(2*24*60*60)。
7、Compact Split的设计。在HBase中,数据在更新时首先写入WAL日志(HLog)和内存(MemStore)中,MemStore中数据时排序的,当MemStore累积到一定的阀值时,就会创建一个新的MemStore,并且将老的MemStore添加到flush队列,由单独的现场flush到磁盘上,成为一个StoreFile。于此同时,系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了。StoreFile是只读的,一旦创建就不能修改了。因此HBase的更新其实是不断追加的过程,当一个Store中的StoreFile达到一定的阀值后,就会进行一次合并。将对同一个key的修改合并到一起,形成一个大的StoreFile,当StoreFile的大小达到一定的阀值后,又会对StoreFile进行分割,等分成两个StoreFile。
结合本系统的需求和HBase表设计准则,我们设计了表4-1来显示告警信息。
表4-1 告警信息设计
RowKey (时间) | ColumnFamily alter:level | ColumnFamily alter:content | ColumnFamily alter:read |
2014-5-12 | 1 | 磁盘出现错误 | TRUE |
2014-5-13 | 2 | 网络中断 | FALSE |
2014-5-14 | 3 | 数据库down了 | TRUE |
表的RowKey是时间,因为不能设计太多的列族,所以这里只设计了一个列族即info,这个列族中有四个列,分别是data,level、content、read。这样做的好处是既能保证信息正确存储又能保证HBase的性能。