HBase数据写入测试

来源:互联网 发布:软件架构总结 二 编辑:程序博客网 时间:2024/05/11 04:02

测试环境

测试硬件:4核i5处理器,8G内存,1T硬盘,千兆网络

测试软件:ubuntu12.10 64位,hadoop版本:0.20.205,hbase版本:0.90.5

测试设置:一个master(namenode)和三台resigonServer(datanode),向HBase集群写入1千万个数据(一个数据15K左右)

测试结果




  • 上图第一列和最后一列分别是插入相同数据再HBase中和HDFS中,可以看见差距很大,HBase上数据的插入时间是HDFS的10倍左右
  • 向HBase中插入数据比HDFS性能差这么多,笔者就研究一下是什么原因让HBase写性能这么不好。向HBase中插入数据的过程大致是这样:client插入数据时先向master请求,master回复哪个resigionserver的哪个region可以给插入数据,然后client直接和resigionserver通信插入数据,resigionserver判断该数据插入到哪个datablock里(resigion是由datablock组成的),然后以HFile的形式存储在HDFS中(数据不一定在resigionserver本地)。具体过程如下可以参考博客http://jiajun.iteye.com/blog/899632
  • 影响HBase写入性能的一个因素就是用put类插入数据的缓存区问题。用put类插入数据时,默认的情况是写入一次数据由clinet和resigionserver进行一次RPC来插入数据。由于是1千万个数据,多次进行进程间通信势必会影响时间。HBase给客户端提供了写缓冲区,当缓冲区填满之后才执行写入操作,这样就减少了写入的测次数。
    • 首先取消自动写入,setAutoFlush(false)
    • 然后设置写缓冲区大小(默认是2MB)setWriteBufferSize()或者更改hbase-site.xml的hbase.client.write.buffer的属性
    • 上面列表可以看出把缓冲区设为20M还是对写入时间有改进,但是改成200M写入时间更长(为什么?)
  • 另一个因素就是WAL(write ahead log),因为每一个resigion都有一个memstore用内存来暂时存放数据,进行排序,最后再吸入HFile里面去,这样做为了减少磁盘寻道而节省时间,但是为了灾难恢复,所以会把内存中的数据进行记录。所以笔者把WAL关闭之后,又测了下性能,还是有一点帮助的,但是帮助不是太大,可见WAL不是写入的瓶颈。(setWriteToWal(false))
  • 因为HBase对查询方便,能够快速的读取数据,写入时必然会采取一些措施进行排序,这就是HBase的合并和分裂机制。HBase官方为了提升写入性能,给出一种方案就是预分配resigion,也就是池的概念,你先分配一些resigion,用的时候直接用就行了。本来这1千万个数据要存储900个resigion,所以笔者预先分配了150个resigion(分配900个resigion,建表时间太长,出现异常,还没有解决),结果写入时间提升了很多,基本是原来的一半,如果能预先分配900个resigion,应该更能节省时间。

ps: 写入时,设置缓冲区越大,写数据(比如8字节)的时间越短

pps:写入buffer不宜设成过大 M级就可以。最近写入测试又做了一些实验,除了预先分配region之外,用多线程写效率还是很高的,笔者测试40个线程比单线程快了8倍左右

测试程序

[java] view plaincopyprint?
  1. package GIS.Update;  
  2.   
  3. import java.io.IOException;  
  4. import java.math.BigInteger;  
  5.   
  6. import org.apache.hadoop.conf.Configuration;  
  7. import org.apache.hadoop.fs.FSDataOutputStream;  
  8. import org.apache.hadoop.fs.FileSystem;  
  9. import org.apache.hadoop.fs.Path;  
  10. import org.apache.hadoop.hbase.HBaseConfiguration;  
  11. import org.apache.hadoop.hbase.HColumnDescriptor;  
  12. import org.apache.hadoop.hbase.HTableDescriptor;  
  13. import org.apache.hadoop.hbase.MasterNotRunningException;  
  14. import org.apache.hadoop.hbase.ZooKeeperConnectionException;  
  15. import org.apache.hadoop.hbase.client.HBaseAdmin;  
  16. import org.apache.hadoop.hbase.client.HTable;  
  17. import org.apache.hadoop.hbase.client.Put;  
  18. import org.apache.hadoop.hbase.util.Bytes;  
  19.   
  20. public class TestUpdate {  
  21.       
  22.     public static void testHDFS() throws IOException{  
  23.         String str="hdfs://cloudgis4:9000/usr/tmp/";  
  24.         Path path=new Path(str);  
  25.         Configuration conf=new Configuration();  
  26.         conf.addResource(new Path("/usr/local/hadoop/conf/hdfs-site.xml"));  
  27.         FileSystem hdfs=path.getFileSystem(conf);  
  28.         hdfs.setReplication(path, (short)4);  
  29.         FSDataOutputStream fsDataOut=hdfs.create(new Path(str+"zzz"));  
  30.         long begin=System.currentTimeMillis();  
  31.         for(int i=0;i<10000000;i++){  
  32.             //byte [] kkk=new byte[10000+i/1000];  
  33.             byte [] kkk=new byte[12];   
  34.             fsDataOut.write(kkk);  
  35.             //fsDataOut.close();  
  36.             //hdfs.close();  
  37.         }  
  38.         fsDataOut.close();  
  39.         long end=System.currentTimeMillis();  
  40.         System.out.println("hdfs:"+(end-begin));  
  41.     }  
  42.       
  43.     public static void testHBase() throws IOException{  
  44.         Configuration conf=HBaseConfiguration.create();  
  45.         conf.addResource(new Path("/usr/local/hbase/conf/hbase-site.xml"));  
  46.         //conf.addResource("/usr/local/hbase/conf/hdfs-site.xml");  
  47.         HBaseAdmin admin=new HBaseAdmin(conf);  
  48.         String tableName="qq";  
  49.         String familyName="imageFamily";  
  50.         String columnName="imageColumn";  
  51.         HTableDescriptor htd=new HTableDescriptor (tableName);  
  52.         HColumnDescriptor hdc=new HColumnDescriptor(familyName);  
  53.         htd.addFamily(hdc);  
  54.         long before=System.currentTimeMillis();  
  55.         //admin.createTable(htd,splits);  
  56.         admin.createTable(htd,Bytes.toBytes("0000000"),Bytes.toBytes("9999999"),150);  
  57.         long after=System.currentTimeMillis();  
  58.         System.out.println(after-before);  
  59.         HTable table=new HTable(conf,htd.getName());  
  60.         table.setAutoFlush(false);  
  61.         //table.setWriteBufferSize(209715200);   
  62.         System.out.println(table.getWriteBufferSize());  
  63.         long begin=System.currentTimeMillis();       
  64.         for(int i=0;i<10000000;i++){  
  65.             byte [] kkk=new byte[10000+i/1000];     
  66.             //byte [] kkk=new byte[12];   
  67.             Put p1=new Put(Bytes.toBytes(intToString(i)));  
  68.             p1.setWriteToWAL(false);  
  69.             p1.add(Bytes.toBytes(familyName),Bytes.toBytes(columnName),kkk);   
  70.             table.put(p1);  
  71.         }  
  72.         long end=System.currentTimeMillis();  
  73.         table.flushCommits();  
  74.         System.out.println("HBase:"+(end-begin));  
  75.     }  
  76.       
  77.     static public String intToString(int x){  
  78.         String result=String.valueOf(x);  
  79.         int size=result.length();  
  80.         while(size<7){  
  81.             size++;  
  82.             result="0"+result;  
  83.         }  
  84.         return result;  
  85.     }  
  86.   
  87.        
  88.     public static void main(String []args) throws IOException{  
  89.         testHBase();  
  90.     }  
  91. }  
0 0
原创粉丝点击