原文鏈接:hbase源碼系列(四)數據模型-表定義和列族定義的具體含義
hbase是一個KeyValue型的數據庫,在《hbase實戰》描述它的邏輯模型【行鍵,列族,列限定符,時間版本】,物理模型是基於列族的。但實際情況是啥?還是上點代碼吧。
HTableDescriptor tableDesc = new HTableDescriptor("test"); //日志flush的時候是同步寫,還是異步寫 tableDesc.setDurability(Durability.SYNC_WAL); //MemStore大小 tableDesc.setMemStoreFlushSize(256*1024*1024); HColumnDescriptor colDesc = new HColumnDescriptor("f"); //塊緩存,保存着每個HFile數據塊的startKey colDesc.setBlockCacheEnabled(true); //塊的大小,默認值是65536 //加載到內存當中的數據塊越小,隨機查找性能更好,越大,連續讀性能更好 colDesc.setBlocksize(64*1024); //bloom過濾器,有ROW和ROWCOL,ROWCOL除了過濾ROW還要過濾列族 colDesc.setBloomFilterType(BloomType.ROW); //寫的時候緩存bloom colDesc.setCacheBloomsOnWrite(true); //寫的時候緩存索引 colDesc.setCacheIndexesOnWrite(true);
//存儲的時候使用壓縮算法
colDesc.setCompressionType(Algorithm.SNAPPY); //進行compaction的時候使用壓縮算法 colDesc.setCompactionCompressionType(Algorithm.SNAPPY); //壓縮內存和存儲的數據,區別於Snappy colDesc.setDataBlockEncoding(DataBlockEncoding.PREFIX); //寫入硬盤的時候是否進行編碼 colDesc.setEncodeOnDisk(true); //關閉的時候,是否剔除緩存的塊 colDesc.setEvictBlocksOnClose(true); //是否保存那些已經刪除掉的kv colDesc.setKeepDeletedCells(false); //讓數據塊緩存在LRU緩存里面有更高的優先級 colDesc.setInMemory(true); //最大最小版本 colDesc.setMaxVersions(3); colDesc.setMinVersions(1); //集群間復制的時候,如果被設置成REPLICATION_SCOPE_LOCAL就不能被復制了 colDesc.setScope(HConstants.REPLICATION_SCOPE_GLOBAL); //生存時間 colDesc.setTimeToLive(18000); tableDesc.addFamily(colDesc);
在上面列出來表定義和列族定義的所有參數,含義也標上去了,我們經常需要設置的可能就是下面的這些。
//bloom過濾器,過濾加速
colDesc.setBloomFilterType(BloomType.ROW); //壓縮內存和存儲中的數據,內存緊張的時候設置 colDesc.setDataBlockEncoding(DataBlockEncoding.PREFIX);
//讓數據塊緩存在LRU緩存里面有更高的優先級 colDesc.setInMemory(true); //最大版本,沒必要的話,就設置成1個 colDesc.setMaxVersions(1); //集群間復制的時候,如果被設置成REPLICATION_SCOPE_LOCAL就不能被復制了 colDesc.setScope(HConstants.REPLICATION_SCOPE_GLOBAL);
//存儲的時候使用壓縮算法,這個基本是必備的,hbase的存儲大得驚人
colDesc.setCompressionType(Algorithm.SNAPPY);
//進行compaction的時候使用壓縮算法
colDesc.setCompactionCompressionType(Algorithm.SNAPPY);
hbase的表在hdfs上面的是這么存儲的,/hbase-root/tableName/regionName/familyName /HFile, 在tableName這一級目錄會有一個名.tabledesc的文件,在region這一級目錄有一個名為.regioninfo的文件,都是明文的。
了解完表和列族的定義之后,我們看看KeyValue是怎么存儲的吧,引用一下代碼,可能大家一看就都懂了。
@Override
public void write(Cell cell) throws IOException { checkFlushed(); // Row rowkey,起始位置,長度 write(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); // Column family 列族,起始位置,長度 write(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); // Qualifier 列名,起始位置,長度 write(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); // Version 時間戳 this.out.write(Bytes.toBytes(cell.getTimestamp())); // Type Put或者Delete this.out.write(cell.getTypeByte()); // Value 值,起始位置,長度 write(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); }
好吧,列存儲的話存儲的時候每個列都會重復前面的rowkey、列族這些信息,在列很多的情況下,rowkey和列族越長,消耗的內存和列族都會很大,所以它們都要盡量的短。
可以考慮用colDesc.setDataBlockEncoding(DataBlockEncoding.PREFIX_TREE)來壓縮一下內存中的大小,這個后面后面會講到。