测试简介

底层数据库采用Hbase,可视化工具使用的是Phoenix。
作业由来:甲方想通过jmete对hbase进行压测,但是上线的两个接口并没有封装成http协议,没办法直接调用,百度的dubbo-jmeter-plugin添加之后也没有连接成功,一番挣扎之后放弃了,所以就准备自己写个并发程序去测试一下。
测试主要是看查询的QPS(每秒查询效率),计算公式:总请求数/总执行时间(总请求数是为测试数据量)。废话不多说直接上测试代码。

代码

程序入口:

/**
 * 自己编写Java高并发对dubbo服务接口的查询功能进行压力测试
 * @author Lenovo
 *
 */
public class MainApplication {
	private static ClassPathXmlApplicationContext context;
	private static AtomicInteger atomicInteger;
	
	//dubbo消费者的启动入口
    public static void main( String[] args )
    {
         context = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
         //此处为自己的接口
         Test test = context.getBean("Test");
         context.start();
         
         //读取测试数据文件
         File file = new File("F:\\test_data\\book\\data.txt");
         BufferedReader bufferedReader;
         LineNumberReader lineNumberReader;
         List<String> list;
         try {
        	 bufferedReader = new BufferedReader(new FileReader(file));
        	 lineNumberReader = new LineNumberReader(bufferedReader);
        	 String str = "";
        	 list = new ArrayList<String>();
        	 while((str = lineNumberReader.readLine()) != null) {
        		 list.add(str);
        	 }
		} finally {
			bufferedReader.close();
			lineNumberReader.close();
		}
         //将读取进来的数据打乱
         Collections.shuffle(list);
         
         //初始化线程池
         ExecutorService executorService = Executors.newFixedThreadPool(32);
         //开始记录调用接口到所有数据查询完毕的时间
         Long currentTime = System.currentTimeMillis();
         for(int i = 0; i<list.size();i++) {
        	 Runnable runnable = execute(test,list.get(i).split(","));
        	 executorService.execute(runnable);
         }
         //关闭线程池
         executorService.shutdown();
         //等待线程池中的所有线程执行完再执行主函数
         while(!executorService.isTerminated()) {}
         
         Long stillTime = System.currentTimeMillis()-currentTime;
         System.out.println("总执行时间(ms):"+stillTime);
         System.out.println("总数据量"+atomicInteger);
         System.out.println("QPS为:"+(atomicInteger.longValue())/stillTime);
    }

	private static Runnable execute(Test test,String[] value) {
		Runnable runnable = new Runnable() {
			
			@Override
			public void run() {
				test.get(value[0],value[1],value[2]);
				atomicInteger.addAndGet(1);
			}
		};
		return runnable;
	}
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
    <!-- 消费方的应用名,用于计算依赖关系,不是匹配条件,不要与消费方一致 -->
    <dubbo:application name="test"></dubbo:application>
    <!-- 走的zk注册中心,即dubbo服务注册的zk地址 -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1"/>

    <dubbo:annotation package="com.bigdata.test"/>
    <dubbo:reference id="TestSearch" interface="com.bigdata.test.api.TestSearch" />

</beans>

测试结果分析

最终的测试结果QPS只有几十,并没有达到我们的预期,所以接下来就开始找到底是哪里有问题了。
1.首先将关联查询的sql单独拆开,也就是单表查询。内层的单表速度非常快,因为查询的条件是走的row_key精准查询,QPS在2000以上。接下来就开始找外层的sql,果不其然,QPS非常的低。
2.外层的查询条件走了row_key联合索引的第一个,那我们就考虑可不可以直接将row_key改为,直接否定了,因为这样会导致部分数据丢失,那我们又开始考虑是不是对表加盐加多了,导致数据过于散列。
3.我们试着将分区从100改为了10,QPS一下就上去了,提升了大概有百倍。

总结

导致QPS低的原因有很多,常见的有:
1.数据库表从建表的时候考虑不周到,没有很好的建立row_key;
2.设置分区不合理,导致数据过于散列;
3.服务器的性能比较差;
由于本人经验不足,可能分析的比较浅显,如果表达有不对的地方,希望各位大佬可以指教。