QPS是接口每秒处理成功的调用次数,RT是处理一次请求所需要的平均时间,并发量是系统能同时处理的请求数。公式:并发量 = QPS * 平均响应时间。
这3个是比较重要的性能指标,如何测试这几个指标呢,可以用工具jmeter,jmeter原生支持http,但像thrift这种rpc接口就需要自己写jmeter的扩展了,可以参考https://www.jianshu.com/p/455e57ab329a。下面不用工具,用java写了一个,主要思路是启动n个线程并发的不断的调用接口一段时间,然后统计计算成功次数,失败次数和平均响应时间,主要用了并发包里的以下几个工具类:
CyclicBarrier:n个线程都到达await时才开始调用接口,模拟并发的感觉。
CountDownLatch:n个线程都运行结束后,主线程才开始统计计算。
LongAdder:计数器,线程安全,AtomicLong的升级版本,类似HashMap和ConcurrentHashMap的区别。
package com.halloffame.thriftjsoa; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.LongAdder; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TFastFramedTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import thrift.test.ThriftTest; import thrift.test.User; public class TestQpsClient { private static LongAdder successCount = new LongAdder(); //成功次数 private static LongAdder failCount = new LongAdder(); //失败次数 private static LongAdder reponseTimeSum = new LongAdder(); //总响应时间,单位:ms private static int threadNum = 12; //线程数 private static int runTime = 60; //线程运行时间,单位:s //cyclicBarrier目的是让所有线程同时运行,模拟并发请求 private static CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum + 1); private static volatile boolean isFinish = false; //结束线程运行标志变量 //countDownLatch目的是所有线程都结束运行后,主线程才统计 private static CountDownLatch countDownLatch = new CountDownLatch(threadNum); public static void main(String[] args) throws Exception { for (int i = 0; i < threadNum; i++) { ReqThread reqThread = new ReqThread(i); reqThread.start(); } cyclicBarrier.await(); Thread.sleep(runTime * 1000); isFinish = true; countDownLatch.await(); long successLongCount = successCount.longValue(); long failLongCount = failCount.longValue(); long reponseTimeLongSum = reponseTimeSum.longValue(); long totalCount = successLongCount + failLongCount; double avgRepTime = reponseTimeLongSum / totalCount; double qps = successLongCount / runTime; double concurrency = qps * (avgRepTime / 1000); System.out.println("成功调用次数:" + successLongCount); System.out.println("失败调用次数:" + failLongCount); System.out.println("平均响应时间:" + avgRepTime + "毫秒"); System.out.println("QPS:" + qps); System.out.println("并发:" + concurrency); } static class ReqThread extends Thread { private int i; public ReqThread(int i){ this.i = i; } @Override public void run() { try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } while ( !isFinish ) { long startTime = System.currentTimeMillis(); User user = null; TTransport transport = null; try { TSocket socket = new TSocket("localhost", 4567); transport = new TFastFramedTransport(socket); transport.open(); TProtocol tProtocol = new TCompactProtocol(transport); ThriftTest.Client testClient = new ThriftTest.Client(tProtocol); user = testClient.getUser(2); } catch (Exception e) { user = null; e.printStackTrace(); } finally { if (transport != null && transport.isOpen()) { transport.close(); } } long endTime = System.currentTimeMillis(); System.out.println("线程" + i + "调用结果:" + user); reponseTimeSum.add(endTime - startTime); if (user != null) { successCount.increment(); } else { failCount.increment(); } } countDownLatch.countDown(); } } }
在我的机器运行的后阶段出现了异常:java.net.BindException: Address already in use: connect,原因是端口被消耗完,即使socket.close(),端口也不是立即关闭,而是TIME_WAIT状态。可以参考https://blog.csdn.net/ceo158/article/details/9311065增大可分配的tcp连接端口数,减小处于TIME_WAIT状态的连接的生存时间。
代码已经放在GitHub:https://github.com/halloffamezwx/thriftjsoa。
推荐一些文章:
线程安全实现与CLH队列:https://www.jianshu.com/p/0f6d3530d46b。
ThreadLocalMap里弱引用:https://blog.csdn.net/vicoqi/article/details/79743112。
感谢阅读!!!
相关推荐
NULL 博文链接:https://zhuwx.iteye.com/blog/2368356
NULL 博文链接:https://zhuwx.iteye.com/blog/2371657
NULL 博文链接:https://zhuwx.iteye.com/blog/2374326
Apache Thrift is an open source cross language serialization and RPC framework. With support for over 15 programming languages, Apache Thrift can play an important role in a range of distributed ...
NULL 博文链接:https://zhuwx.iteye.com/blog/2377030
NULL 博文链接:https://zhuwx.iteye.com/blog/2347581
Make applications cross-communicate using Apache Thrift! About This Book Leverage Apache Thrift to enable applications written in different programming languages (Java, C++, Python, PHP, Ruby, and so...
本例改编自Apache Thrift教程: http://mikecvet.wordpress.com/2010/05/13/apache-thrift-tutorial-the-sequel/ http://chanian.com/2010/05/13/thrift-tutorial-a-php-client/ 原教程使用的是c++ server和...
详细介绍了Apache Thrift在Ubuntu以及Windows下基于C++和Java语言的安装和运行。附有小例子,亲自测试通过。所述方法网上应该有教程,但大多零散不统一或者不完整,因此本人整理了一份,特来分享。
Learning Apache Thrift
第二部分-编程Apache Thrift 本部分深入研究Apache Thrift框架的每一层,详细检查传输,协议,类型,服务,服务器和Apache Thrift接口定义语言。 这些章节中的示例使用C ++,Java和Python作为演示语言。 C ++示例...
基于RPC技术的java开发,可用于分布式系统开发,高性能高可用。
Apache Thrift——可伸缩的跨语言服务开发框架
Apache Thrift Java实战源码,包含了客户端和服务端源码,客户端和服务端是分开的,如果需要放到一个工程,直接把Client.java文件复制到服务端运行即可。
FacebookThrift最初是紧跟Apache Thrift发行的,但现在朝着新的方向发展。 特别是,编译器是从头开始重写的,新的实现具有完全异步的Thrift服务器。 在了解有关这些改进的。 您还可以在原始的Facebook Code 了解...
使用Apache thrift通信框架编写的一个实例,以及提供开发中使用thrift所需的jar包
apache-thrift-amqp 支持 Apache Thrift 的 AMQP 传输层该项目为 Ruby 中的 Apache Thrift 实现了 AMQP 传输层,并扩展了 Apache Thrift 教程。 AMQP 传输层依赖 Ruby bunny gem 来连接到 RabbitMQ 代理。 本教程...
包含thrift五种模式下的例子;阻塞(2种), 非阻塞(3种);可做参考
spring-cloud-starter-thrift简介spring-cloud-starter-thrift提供Spring Cloud对可伸缩的跨语言服务调用框架Apache Thrift的封装和集成。spring-cloud-starter-thrift包括客户端spring-cloud-starter-thrift-client...