HBase预分区解决写热点问题。

        介绍的两种预分区方法生产环境中用过第二种,确实好用,解决了写热点的问题。

       HBase中,表会被划分为1...n个Region,被托管在RegionServer中。Region二个重要的属性:StartKey与 EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-end key范围内,那么就会定位到目标region并且读/写到相关的数据。简单地说,有那么一点点类似人群划分,1-15岁为小朋友,16-39岁为年轻 人,40-64为中年人,65岁以上为老年人。(这些数值都是拍脑袋出来的,只是举例,非真实),然后某人找队伍,然后根据年龄,处于哪个范围,就找到它 所属的队伍。 : ( 有点废话了。。。。

    然后,默认地,当我们只是通过HBaseAdmin指定TableDescriptor来创建一张表时,只有一个region,正处于混沌时 期,start-end key无边界,可谓海纳百川。啥样的rowKey都可以接受,都往这个region里装,然而,当数据越来越多,region的size越来越大时,大到 一定的阀值,hbase认为再往这个region里塞数据已经不合适了,就会找到一个midKey将region一分为二,成为2个region,这个过 程称为分裂(region-split).而midKey则为这二个region的临界,左为N无下界,右为M无上界。< midKey则为阴被塞到N区,> midKey则会被塞到M区。

    如何找到midKey?涉及的内容比较多,暂且不去讨论,最简单的可以认为是region的总行数 / 2 的那一行数据的rowKey.虽然实际上比它会稍复杂点。
    如果我们就这样默认地,建表,表里不断地Put数据,更严重的是我们的rowkey还是顺序增大的,是比较可怕的。存在的缺点比较明显。


    首先是热点写,我们总是会往最大的start-key所在的region写东西,因为我们的rowkey总是会比之前的大,并且hbase的是按升序方式排序的。所以写操作总是被定位到无上界的那个region中。
    其次,由于写热点,我们总是往最大start-key的region写记录,之前分裂出来的region不会再被写数据,有点被打进冷宫的赶脚,它们都处于半满状态,这样的分布也是不利的。
    如果在写比较频率的场景下,数据增长快,split的次数也会增多,由于split是比较耗时耗资源的,所以我们并不希望这种事情经常发生。
    ............


    看到这些缺点,我们知道,在集群的环境中,为了得到更好的并行性,我们希望有好的load blance,让每个节点提供的请求处理都是均等的。我们也希望,region不要经常split,因为split会使server有一段时间的停顿,如何能做到呢?
随机散列与预分区。二者结合起来,是比较完美的,预分区一开始就预建好了一部分region,这些region都维护着自已的start-end keys,再配合上随机散列,写数据能均等地命中这些预建的region,就能解决上面的那些缺点,大大地提高了性能。

提供2种思路: hash 与 partition.
    一、hash就是rowkey前面由一串随机字符串组成,随机字符串生成方式可以由SHA或者MD5等方式生成,只要region所管理的start-end keys范围比较随机,那么就可以解决写热点问题。

long currentId = 1L;
byte [] rowkey = Bytes.add(MD5Hash.getMD5AsHex(Bytes.toBytes(currentId)).substring(0, 8).getBytes(),
                    Bytes.toBytes(currentId));

 

假设rowKey原本是自增长的long型,可以将rowkey转为hash再转为bytes,加上本身id 转为bytes,组成rowkey,这样就生成随便的rowkey。那么对于这种方式的rowkey设计,如何去进行预分区呢?
    1.取样,先随机生成一定数量的rowkey,将取样数据按升序排序放到一个集合里
    2.根据预分区的region个数,对整个集合平均分割,即是相关的splitKeys.
    3.HBaseAdmin.createTable(HTableDescriptor tableDescriptor,byte[][] splitkeys)可以指定预分区的splitKey,即是指定region间的rowkey临界值.

 

 1.创建split计算器,用于从抽样数据中生成一个比较合适的splitKeys

Java代码   收藏代码
  1. public class HashChoreWoker implements SplitKeysCalculator{  
  2.     //随机取机数目  
  3.     private int baseRecord;  
  4.     //rowkey生成器  
  5.     private RowKeyGenerator rkGen;  
  6.     //取样时,由取样数目及region数相除所得的数量.  
  7.     private int splitKeysBase;  
  8.     //splitkeys个数  
  9.     private int splitKeysNumber;  
  10.     //由抽样计算出来的splitkeys结果  
  11.     private byte[][] splitKeys;  
  12.   
  13.     public HashChoreWoker(int baseRecord, int prepareRegions) {  
  14.         this.baseRecord = baseRecord;  
  15.         //实例化rowkey生成器  
  16.         rkGen = new HashRowKeyGenerator();  
  17.         splitKeysNumber = prepareRegions - 1;  
  18.         splitKeysBase = baseRecord / prepareRegions;  
  19.     }  
  20.   
  21.     public byte[][] calcSplitKeys() {  
  22.         splitKeys = new byte[splitKeysNumber][];  
  23.         //使用treeset保存抽样数据,已排序过  
  24.         TreeSet<byte[]> rows = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);  
  25.         for (int i = 0; i < baseRecord; i++) {  
  26.             rows.add(rkGen.nextId());  
  27.         }  
  28.         int pointer = 0;  
  29.         Iterator<byte[]> rowKeyIter = rows.iterator();  
  30.         int index = 0;  
  31.         while (rowKeyIter.hasNext()) {  
  32.             byte[] tempRow = rowKeyIter.next();  
  33.             rowKeyIter.remove();  
  34.             if ((pointer != 0) && (pointer % splitKeysBase == 0)) {  
  35.                 if (index < splitKeysNumber) {  
  36.                     splitKeys[index] = tempRow;  
  37.                     index ++;  
  38.                 }  
  39.             }  
  40.             pointer ++;  
  41.         }  
  42.         rows.clear();  
  43.         rows = null;  
  44.         return splitKeys;  
  45.     }  
  46. }  

 

Java代码   收藏代码
  1. KeyGenerator及实现  
  2. //interface  
  3. public interface RowKeyGenerator {  
  4.     byte [] nextId();  
  5. }  
  6. //implements  
  7. public class HashRowKeyGenerator implements RowKeyGenerator {  
  8.     private long currentId = 1;  
  9.     private long currentTime = System.currentTimeMillis();  
  10.     private Random random = new Random();  
  11.     public byte[] nextId() {  
  12.         try {  
  13.             currentTime += random.nextInt(1000);  
  14.             byte[] lowT = Bytes.copy(Bytes.toBytes(currentTime), 44);  
  15.             byte[] lowU = Bytes.copy(Bytes.toBytes(currentId), 44);  
  16.             return Bytes.add(MD5Hash.getMD5AsHex(Bytes.add(lowU, lowT)).substring(08).getBytes(),  
  17.                     Bytes.toBytes(currentId));  
  18.         } finally {  
  19.             currentId++;  
  20.         }  
  21.     }  
  22. }  

 

 

Java代码   收藏代码
  1. @Test  
  2. public void testHashAndCreateTable() throws Exception{  
  3.         HashChoreWoker worker = new HashChoreWoker(1000000,10);  
  4.         byte [][] splitKeys = worker.calcSplitKeys();  
  5.           
  6.         HBaseAdmin admin = new HBaseAdmin(HBaseConfiguration.create());  
  7.         TableName tableName = TableName.valueOf("hash_split_table");  
  8.           
  9.         if (admin.tableExists(tableName)) {  
  10.             try {  
  11.                 admin.disableTable(tableName);  
  12.             } catch (Exception e) {  
  13.             }  
  14.             admin.deleteTable(tableName);  
  15.         }  
  16.   
  17.         HTableDescriptor tableDesc = new HTableDescriptor(tableName);  
  18.         HColumnDescriptor columnDesc = new HColumnDescriptor(Bytes.toBytes("info"));  
  19.         columnDesc.setMaxVersions(1);  
  20.         tableDesc.addFamily(columnDesc);  
  21.   
  22.         admin.createTable(tableDesc ,splitKeys);  
  23.   
  24.         admin.close();  
  25.     }  

 

       以上,就已经按hash方式,预建好了分区,以后在插入数据的时候,也要按照此rowkeyGenerator的方式生成rowkey,有兴趣的话,也可以做些试验,插入些数据,看看数据的分布。

 

 

 

       二、partition故名思义,就是分区式,这种分区有点类似于mapreduce中的partitioner,将区域用长整数(Long)作为分区号,每 个region管理着相应的区域数据,在rowKey生成时,将id取模后,然后拼上id整体作为rowKey.这个比较简单,不需要取 样,splitKeys也非常简单,直接是分区号即可。直接上代码吧:

 

Java代码   收藏代码
  1. public class PartitionRowKeyManager implements RowKeyGenerator,  
  2.         SplitKeysCalculator {  
  3.   
  4.     public static final int DEFAULT_PARTITION_AMOUNT = 20;  
  5.     private long currentId = 1;  
  6.     private int partition = DEFAULT_PARTITION_AMOUNT;  
  7.     public void setPartition(int partition) {  
  8.         this.partition = partition;  
  9.     }  
  10.   
  11.     public byte[] nextId() {  
  12.         try {  
  13.             long partitionId = currentId % partition;  
  14.             return Bytes.add(Bytes.toBytes(partitionId),  
  15.                     Bytes.toBytes(currentId));  
  16.         } finally {  
  17.             currentId++;  
  18.         }  
  19.     }  
  20.   
  21.     public byte[][] calcSplitKeys() {  
  22.         byte[][] splitKeys = new byte[partition - 1][];  
  23.         for(int i = 1; i < partition ; i ++) {  
  24.             splitKeys[i-1] = Bytes.toBytes((long)i);  
  25.         }  
  26.         return splitKeys;  
  27.     }  
  28. }  

 

 calcSplitKeys方法比较单纯,splitKey就是partition的编号,我们看看测试类:

Java代码   收藏代码
  1. @Test  
  2.     public void testPartitionAndCreateTable() throws Exception{  
  3.           
  4.         PartitionRowKeyManager rkManager = new PartitionRowKeyManager();  
  5.         //只预建10个分区  
  6.         rkManager.setPartition(10);  
  7.           
  8.         byte [][] splitKeys = rkManager.calcSplitKeys();  
  9.           
  10.         HBaseAdmin admin = new HBaseAdmin(HBaseConfiguration.create());  
  11.         TableName tableName = TableName.valueOf("partition_split_table");  
  12.           
  13.         if (admin.tableExists(tableName)) {  
  14.             try {  
  15.                 admin.disableTable(tableName);  
  16.   
  17.             } catch (Exception e) {  
  18.             }  
  19.             admin.deleteTable(tableName);  
  20.         }  
  21.   
  22.         HTableDescriptor tableDesc = new HTableDescriptor(tableName);  
  23.         HColumnDescriptor columnDesc = new HColumnDescriptor(Bytes.toBytes("info"));  
  24.         columnDesc.setMaxVersions(1);  
  25.         tableDesc.addFamily(columnDesc);  
  26.   
  27.         admin.createTable(tableDesc ,splitKeys);  
  28.   
  29.         admin.close();  
  30.     }  

 

       通过partition实现的loadblance写的话,当然生成rowkey方式也要结合当前的region数目取模而求得,大家同样也可以做些实验,看看数据插入后的分布。
在这里也顺提一下,如果是顺序的增长型原id,可以将id保存到一个数据库,传统的也好,redis的也好,每次取的时候,将数值设大1000左右,以后 id可以在内存内增长,当内存数量已经超过1000的话,再去load下一个,有点类似于oracle中的sqeuence.

 

        随机分布加预分区也不是一劳永逸的。因为数据是不断地增长的,随着时间不断地推移,已经分好的区域,或许已经装不住更多的数据,当然就要进一步进行 split了,同样也会出现性能损耗问题,所以我们还是要规划好数据增长速率,观察好数据定期维护,按需分析是否要进一步分行手工将分区再分好,也或者是 更严重的是新建表,做好更大的预分区然后进行数据迁移。






下面是从另外一片博文转的一些代码,本人的工作环境是内网环境,完全与互联网物理隔绝的,所以没法贴本人代码。用的是第二种方法,大家可以参考以下:

API 操作:

  1. import java.io.IOException;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4.   
  5. import org.apache.hadoop.conf.Configuration;  
  6. import org.apache.hadoop.hbase.HBaseConfiguration;  
  7. import org.apache.hadoop.hbase.HColumnDescriptor;  
  8. import org.apache.hadoop.hbase.HTableDescriptor;  
  9. import org.apache.hadoop.hbase.KeyValue;  
  10. import org.apache.hadoop.hbase.MasterNotRunningException;  
  11. import org.apache.hadoop.hbase.TableName;  
  12. import org.apache.hadoop.hbase.ZooKeeperConnectionException;  
  13. import org.apache.hadoop.hbase.client.Get;  
  14. import org.apache.hadoop.hbase.client.HBaseAdmin;  
  15. import org.apache.hadoop.hbase.client.HTable;  
  16. import org.apache.hadoop.hbase.client.HTablePool;  
  17. import org.apache.hadoop.hbase.client.Put;  
  18. import org.apache.hadoop.hbase.client.Result;  
  19. import org.apache.hadoop.hbase.client.ResultScanner;  
  20. import org.apache.hadoop.hbase.client.Scan;  
  21. import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;  
  22. import org.apache.hadoop.hbase.filter.Filter;  
  23. import org.apache.hadoop.hbase.filter.FilterList;  
  24. import org.apache.hadoop.hbase.filter.PrefixFilter;  
  25. import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;  
  26. import org.apache.hadoop.hbase.util.Bytes;  
  27. import org.slf4j.Logger;  
  28. import org.slf4j.LoggerFactory;  
  29.   
  30. import com.kktest.hbase.HashChoreWoker;  
  31. import com.kktest.hbase.HashRowKeyGenerator;  
  32. import com.kktest.hbase.RowKeyGenerator;  
  33. import com.kktest.hbase.BitUtils;  
  34.   
  35. /** 
  36.  * hbase 客户端 
  37.  *  
  38.  * @author kuang hj 
  39.  *  
  40.  */  
  41. @SuppressWarnings("all")  
  42. public class HBaseClient {  
  43.   
  44.     private static Logger logger = LoggerFactory.getLogger(HBaseClient.class);  
  45.     private static Configuration config;  
  46.     static {  
  47.         config = HBaseConfiguration.create();  
  48.         config.set("hbase.zookeeper.quorum",  
  49.                 "192.168.1.100:2181,192.168.1.101:2181,192.168.1.103:2181");  
  50.     }  
  51.   
  52.     /** 
  53.      * 根据随机散列(hash)创建分区表 
  54.      *  
  55.      * @throws Exception 
  56.      *             hash_split_table 
  57.      */  
  58.     public static void testHashAndCreateTable(String tableNameTmp,  
  59.             String columnFamily) throws Exception {<p>        // 取随机散列 10 代表 10个分区  
  60.         HashChoreWoker worker = new HashChoreWoker(100000010);  
  61.         byte[][] splitKeys = worker.calcSplitKeys();  
  62.   
  63.         HBaseAdmin admin = new HBaseAdmin(config);  
  64.         TableName tableName = TableName.valueOf(tableNameTmp);  
  65.   
  66.         if (admin.tableExists(tableName)) {  
  67.             try {  
  68.                 admin.disableTable(tableName);  
  69.             } catch (Exception e) {  
  70.             }  
  71.             admin.deleteTable(tableName);  
  72.         }  
  73.   
  74.         HTableDescriptor tableDesc = new HTableDescriptor(tableName);  
  75.         HColumnDescriptor columnDesc = new HColumnDescriptor(  
  76.                 Bytes.toBytes(columnFamily));  
  77.         columnDesc.setMaxVersions(1);  
  78.         tableDesc.addFamily(columnDesc);  
  79.   
  80.         admin.createTable(tableDesc, splitKeys);  
  81.   
  82.         admin.close();  
  83.     }  
  84.   
  85.     /** 
  86.      * @Title: queryData 
  87.      * @Description: 从HBase查询出数据 
  88.      * @author kuang hj 
  89.      * @param tableName 
  90.      *            表名 
  91.      * @param rowkey 
  92.      *            rowkey 
  93.      * @return 返回用户信息的list 
  94.      * @throws Exception 
  95.      */  
  96.     @SuppressWarnings("all")  
  97.     public static ArrayList<String> queryData(String tableName, String rowkey)  
  98.             throws Exception {  
  99.         ArrayList<String> list = new ArrayList<String>();  
  100.         logger.info("开始时间");  
  101.         HTable table = new HTable(config, tableName);  
  102.   
  103.         Get get = new Get(rowkey.getBytes()); // 根据主键查询  
  104.         Result r = table.get(get);  
  105.         logger.info("结束时间");  
  106.         KeyValue[] kv = r.raw();  
  107.         for (int i = 0; i < kv.length; i++) {  
  108.             // 循环每一列  
  109.             String key = kv[i].getKeyString();  
  110.               
  111.             String value = kv[i].getValueArray().toString();  
  112.               
  113.             // 将查询到的结果写入List中  
  114.             list.add(key + ":"+ value);  
  115.               
  116.         }// end of 遍历每一列  
  117.           
  118.         return list;  
  119.     }  
  120.   
  121.     /** 
  122.      * 增加表数据 
  123.      *  
  124.      * @param tableName 
  125.      * @param rowkey 
  126.      */  
  127.     public static void insertData(String tableName, String rowkey) {  
  128.         HTable table = null;  
  129.         try {  
  130.             table = new HTable(config, tableName);  
  131.             // 一个PUT代表一行数据,再NEW一个PUT表示第二行数据,每行一个唯一的ROWKEY,此处rowkey为put构造方法中传入的值  
  132.             for (int i = 1; i < 100; i++) {  
  133.                 byte[] result = getNumRowkey(rowkey,i);  
  134.                 Put put = new Put(result);  
  135.                 // 本行数据的第一列  
  136.                 put.add(rowkey.getBytes(), "name".getBytes(),  
  137.                         ("aaa" + i).getBytes());  
  138.                 // 本行数据的第三列  
  139.                 put.add(rowkey.getBytes(), "age".getBytes(),  
  140.                         ("bbb" + i).getBytes());  
  141.                 // 本行数据的第三列  
  142.                 put.add(rowkey.getBytes(), "address".getBytes(),  
  143.                         ("ccc" + i).getBytes());  
  144.   
  145.                 table.put(put);  
  146.             }  
  147.   
  148.         } catch (Exception e1) {  
  149.             e1.printStackTrace();  
  150.         }  
  151.     }  
  152.   
  153.     private static byte[] getNewRowkey(String rowkey) {  
  154.         byte[] result = null;  
  155.   
  156.         RowKeyGenerator rkGen = new HashRowKeyGenerator();  
  157.         byte[] splitKeys = rkGen.nextId();  
  158.   
  159.         byte[] rowkeytmp = rowkey.getBytes();  
  160.   
  161.         result = new byte[splitKeys.length + rowkeytmp.length];  
  162.         System.arraycopy(splitKeys, 0, result, 0, splitKeys.length);  
  163.         System.arraycopy(rowkeytmp, 0, result, splitKeys.length,  
  164.                 rowkeytmp.length);  
  165.   
  166.         return result;  
  167.     }  
  168.       
  169.     public static void main(String[] args) {  
  170.         RowKeyGenerator rkGen = new HashRowKeyGenerator();  
  171.         byte[] splitKeys = rkGen.nextId();  
  172.         System.out.println(splitKeys);      
  173.     }  
  174.   
  175.     private static byte[] getNumRowkey(String rowkey, int i) {  
  176.         byte[] result = null;  
  177.   
  178.         RowKeyGenerator rkGen = new HashRowKeyGenerator();  
  179.         byte[] splitKeys = rkGen.nextId();  
  180.   
  181.         byte[] rowkeytmp = rowkey.getBytes();  
  182.   
  183.         byte[] intVal = BitUtils.getByteByInt(i);  
  184.         result = new byte[splitKeys.length + rowkeytmp.length + intVal.length];  
  185.         System.arraycopy(splitKeys, 0, result, 0, splitKeys.length);  
  186.         System.arraycopy(rowkeytmp, 0, result, splitKeys.length,  
  187.                 rowkeytmp.length);  
  188.         System.arraycopy(intVal, 0, result, splitKeys.length+rowkeytmp.length,  
  189.                 intVal.length);  
  190.   
  191.         return result;  
  192.     }  
  193.       
  194.       
  195.   
  196.     /** 
  197.      * 删除表 
  198.      *  
  199.      * @param tableName 
  200.      */  
  201.     public static void dropTable(String tableName) {  
  202.         try {  
  203.             HBaseAdmin admin = new HBaseAdmin(config);  
  204.             admin.disableTable(tableName);  
  205.             admin.deleteTable(tableName);  
  206.         } catch (MasterNotRunningException e) {  
  207.             e.printStackTrace();  
  208.         } catch (ZooKeeperConnectionException e) {  
  209.             e.printStackTrace();  
  210.         } catch (IOException e) {  
  211.             e.printStackTrace();  
  212.         }  
  213.     }  
  214.   
  215.     /** 
  216.      * 查询所有 
  217.      *  
  218.      * @param tableName 
  219.      */  
  220.     public static void QueryAll(String tableName) {  
  221.         HTable table  = null;  
  222.         try {  
  223.             table  = new HTable(config, tableName);  
  224.             ResultScanner rs = table.getScanner(new Scan());  
  225.             for (Result r : rs) {  
  226.                 System.out.println("获得到rowkey:" + new String(r.getRow()));  
  227.                 for (KeyValue keyValue : r.raw()) {  
  228.                     System.out.println("列:" + new String(keyValue.getFamily())  
  229.                             + "====值:" + new String(keyValue.getValue()));  
  230.                 }  
  231.             }  
  232.         } catch (IOException e) {  
  233.             e.printStackTrace();  
  234.         }  
  235.     }  
  236.   
  237.     /** 
  238.      * 查询所有 
  239.      *  
  240.      * @param tableName 
  241.      */  
  242.     public static void QueryByCondition1(String tableName) {  
  243.   
  244.         HTable table = null;  
  245.         try {  
  246.             table  = new HTable(config, tableName);  
  247.             Get scan = new Get("abcdef".getBytes());// 根据rowkey查询  
  248.             Result r = table.get(scan);  
  249.             System.out.println("获得到rowkey:" + new String(r.getRow()));  
  250.             for (KeyValue keyValue : r.raw()) {  
  251.                 System.out.println("列:" + new String(keyValue.getFamily())  
  252.                         + "====值:" + new String(keyValue.getValue()));  
  253.             }  
  254.         } catch (IOException e) {  
  255.             e.printStackTrace();  
  256.         }  
  257.     }  
  258.       
  259.     /** 
  260.      *  根据rowkwy前坠查询  
  261.      * @param tableName 
  262.      * @param rowkey 
  263.      */  
  264.     public static void queryByRowKey(String tableName,String rowkey)  
  265.     {  
  266.         try {  
  267.             HTable table = new HTable(config, tableName);  
  268.             Scan scan = new Scan();  
  269.             scan.setFilter(new PrefixFilter(rowkey.getBytes()));  
  270.             ResultScanner rs = table.getScanner(scan);  
  271.             KeyValue[] kvs = null;  
  272.             for (Result tmp : rs)  
  273.             {  
  274.                 kvs = tmp.raw();  
  275.                 for (KeyValue kv : kvs)  
  276.                 {  
  277.                     System.out.print(kv.getRow()+" ");  
  278.                     System.out.print(kv.getFamily()+" :");  
  279.                     System.out.print(kv.getQualifier()+" ");  
  280.                     System.out.print(kv.getTimestamp()+" ");  
  281.                     System.out.println(kv.getValue());  
  282.                 }  
  283.             }  
  284.         } catch (IOException e) {  
  285.             e.printStackTrace();  
  286.         }  
  287.           
  288.     }  
  289.     /** 
  290.      * 查询所有 
  291.      *  
  292.      * @param tableName 
  293.      */  
  294.     public static void QueryByCondition2(String tableName) {  
  295.   
  296.         try {  
  297.             HTable table = new HTable(config, tableName);  
  298.             // 当列column1的值为aaa时进行查询  
  299.             Filter filter = new SingleColumnValueFilter(  
  300.                     Bytes.toBytes("column1"), null, CompareOp.EQUAL,  
  301.                     Bytes.toBytes("aaa"));   
  302.             Scan s = new Scan();  
  303.             s.setFilter(filter);  
  304.             ResultScanner rs = table.getScanner(s);  
  305.             for (Result r : rs) {  
  306.                 System.out.println("获得到rowkey:" + new String(r.getRow()));  
  307.                 for (KeyValue keyValue : r.raw()) {  
  308.                     System.out.println("列:" + new String(keyValue.getFamily())  
  309.                             + "====值:" + new String(keyValue.getValue()));  
  310.                 }  
  311.             }  
  312.         } catch (Exception e) {  
  313.             e.printStackTrace();  
  314.         }  
  315.   
  316.     }  
  317.   
  318.     /** 
  319.      * 查询所有 
  320.      *  
  321.      * @param tableName 
  322.      */  
  323.     public static void QueryByCondition3(String tableName) {  
  324.   
  325.         try {  
  326.               
  327.             HTable table = new HTable(config, tableName);  
  328.   
  329.             List<Filter> filters = new ArrayList<Filter>();  
  330.   
  331.             Filter filter1 = new SingleColumnValueFilter(  
  332.                     Bytes.toBytes("column1"), null, CompareOp.EQUAL,  
  333.                     Bytes.toBytes("aaa"));  
  334.             filters.add(filter1);  
  335.   
  336.             Filter filter2 = new SingleColumnValueFilter(  
  337.                     Bytes.toBytes("column2"), null, CompareOp.EQUAL,  
  338.                     Bytes.toBytes("bbb"));  
  339.             filters.add(filter2);  
  340.   
  341.             Filter filter3 = new SingleColumnValueFilter(  
  342.                     Bytes.toBytes("column3"), null, CompareOp.EQUAL,  
  343.                     Bytes.toBytes("ccc"));  
  344.             filters.add(filter3);  
  345.   
  346.             FilterList filterList1 = new FilterList(filters);  
  347.   
  348.             Scan scan = new Scan();  
  349.             scan.setFilter(filterList1);  
  350.             ResultScanner rs = table.getScanner(scan);  
  351.             for (Result r : rs) {  
  352.                 System.out.println("获得到rowkey:" + new String(r.getRow()));  
  353.                 for (KeyValue keyValue : r.raw()) {  
  354.                     System.out.println("列:" + new String(keyValue.getFamily())  
  355.                             + "====值:" + new String(keyValue.getValue()));  
  356.                 }  
  357.             }  
  358.             rs.close();  
  359.   
  360.         } catch (Exception e) {  
  361.             e.printStackTrace();  
  362.         }  
  363.   
  364.     }  
  365. }</p>  
  1. HashChoreWoker:  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.TreeSet;  
  5.   
  6. import org.apache.hadoop.hbase.util.Bytes;  
  7.   
  8. /** 
  9.  *  
  10.  * @author kuang hj 
  11.  * 
  12.  */  
  13. public class HashChoreWoker{  
  14.     // 随机取机数目  
  15.     private int baseRecord;  
  16.     // rowkey生成器  
  17.     private RowKeyGenerator rkGen;  
  18.     // 取样时,由取样数目及region数相除所得的数量.  
  19.     private int splitKeysBase;  
  20.     // splitkeys个数  
  21.     private int splitKeysNumber;  
  22.     // 由抽样计算出来的splitkeys结果  
  23.     private byte[][] splitKeys;  
  24.   
  25.     public HashChoreWoker(int baseRecord, int prepareRegions) {  
  26.         this.baseRecord = baseRecord;  
  27.         // 实例化rowkey生成器  
  28.         rkGen = new HashRowKeyGenerator();  
  29.         splitKeysNumber = prepareRegions - 1;  
  30.         splitKeysBase = baseRecord / prepareRegions;  
  31.     }  
  32.   
  33.     public byte[][] calcSplitKeys() {  
  34.         splitKeys = new byte[splitKeysNumber][];  
  35.         // 使用treeset保存抽样数据,已排序过  
  36.         TreeSet<byte[]> rows = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);  
  37.         for (int i = 0; i < baseRecord; i++) {  
  38.             rows.add(rkGen.nextId());  
  39.         }  
  40.         int pointer = 0;  
  41.         Iterator<byte[]> rowKeyIter = rows.iterator();  
  42.         int index = 0;  
  43.         while (rowKeyIter.hasNext()) {  
  44.             byte[] tempRow = rowKeyIter.next();  
  45.             rowKeyIter.remove();  
  46.             if ((pointer != 0) && (pointer % splitKeysBase == 0)) {  
  47.                 if (index < splitKeysNumber) {  
  48.                     splitKeys[index] = tempRow;  
  49.                     index++;  
  50.                 }  
  51.             }  
  52.             pointer++;  
  53.         }  
  54.         rows.clear();  
  55.         rows = null;  
  56.         return splitKeys;  
  57.     }  
  58. }  

  1. HashRowKeyGenerator:  
  2. import org.apache.hadoop.hbase.util.Bytes;  
  3. import org.apache.hadoop.hbase.util.MD5Hash;  
  4.   
  5. import com.kktest.hbase.BitUtils;  
  6. /** 
  7. * 
  8. * 
  9. **/  
  10. public class HashRowKeyGenerator implements RowKeyGenerator {  
  11.     private static long currentId = 1;  
  12.     private static long currentTime = System.currentTimeMillis();  
  13.     //private static Random random = new Random();  
  14.   
  15.     public byte[] nextId()   
  16.     {  
  17.         try {  
  18.             currentTime = getRowKeyResult(Long.MAX_VALUE - currentTime);  
  19.             byte[] lowT = Bytes.copy(Bytes.toBytes(currentTime), 44);  
  20.             byte[] lowU = Bytes.copy(Bytes.toBytes(currentId), 44);  
  21.             byte[] result = Bytes.add(MD5Hash.getMD5AsHex(Bytes.add(lowT, lowU))  
  22.                     .substring(08).getBytes(), Bytes.toBytes(currentId));  
  23.             return result;  
  24.         } finally {  
  25.             currentId++;  
  26.         }  
  27.     }  
  28.       
  29.     /** 
  30.      *  getRowKeyResult 
  31.      * @param tmpData 
  32.      * @return 
  33.      */  
  34.     public static long getRowKeyResult(long tmpData)  
  35.     {  
  36.         String str = String.valueOf(tmpData);  
  37.         StringBuffer sb = new StringBuffer();  
  38.         char[] charStr = str.toCharArray();  
  39.         for (int i = charStr.length -1 ; i > 0; i--)  
  40.         {  
  41.             sb.append(charStr[i]);  
  42.         }  
  43.           
  44.         return Long.parseLong(sb.toString());  
  45.     }  





  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值