请先阅读 REFER: http://blog.youkuaiyun.com/tenebaul/article/details/17144059
涉及的类: ConcurrentPerformanceBenchmarkFactory.java ConcurrentPerformanceBenchmark.java和ConcurrentPerformanceBenchmarkMBean.java 和 JmxMBeanManager.java
public interface ConcurrentPerformanceBenchmarkMBean {
public String getName();
/** 执行的开始时间 yyyy-MM-dd HH:mm:ss*/
public String getInitActionTime();
/** 执行的结束时间 yyyy-MM-dd HH:mm:ss */
public String getLastActionTime();
/** 总共处理了多少个 */
public int getCountTotal();
/** 模拟引擎平均时延 */
public double getLatencyAvgMS();
/** 模拟引擎吞吐量*/
public int getThroughputQPS();
/**
* 模拟引擎平均时延的倒数,只是为给平均时延代表的数量级变换成处理能力。
* getThroughputQPS()与getLatencyFlipQPS()的差距体现的是并发带来的好处。
* */
public int getLatencyFlipQPS();
}
import java.sql.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import com.sohu.video.ad.adfront.util.DateUtil;
/** 性能测试 */
public class ConcurrentPerformanceBenchmark implements ConcurrentPerformanceBenchmarkMBean {
private final AtomicInteger totalCount = new AtomicInteger(0);
private final AtomicLong totalLatency = new AtomicLong(0);
private final String name;
public ConcurrentPerformanceBenchmark(String name) {
super();
this.name = name;
JmxMBeanManager.getInstance().appendMBean(this, name);
}
public void benchmarkAction(int actionIncrValue, long actionStartTime, long actionEndedTime) {
initIfAbsent(actionStartTime);
lastEndedTime(actionEndedTime);
incrCountAndLatency(actionIncrValue, actionEndedTime-actionStartTime);
}
private volatile long initActionStartTime = 0;//只写一次
private final AtomicLong lastActionEndedTime = new AtomicLong();
protected void initIfAbsent(long initExecTime) {
if (initActionStartTime <= 0) {
initActionStartTime = initExecTime;
}
}
protected void lastEndedTime(long lastExecTime) {
lastActionEndedTime.set(lastExecTime);
}
public void incrCountAndLatency(int incrValue, long timeCost) {
totalCount.addAndGet(incrValue);
totalLatency.addAndGet(timeCost);
}
@Override
public String getName() {
return name;
}
@Override
public int getCountTotal() {
return totalCount.get();
}
@Override
public double getLatencyAvgMS() {
int num = totalCount.get();
if (num <=0) {
return 0;
}
return (totalLatency.get()+0.0) / totalCount.get();
}
@Override
public int getLatencyFlipQPS() {
long time = totalLatency.get();
if (time <=0) {
return 0;
}
return (int) ((totalCount.get()/(totalLatency.get()+0.0))*1000);
}
@Override
public String getInitActionTime() {
if (initActionStartTime <= 0) {
return "";
}
return DateUtil.format(new Date(initActionStartTime), "yyyy-MM-dd HH:mm:ss");
}
@Override
public String getLastActionTime() {
if (lastActionEndedTime.get() <= 0) {
return "";
}
return DateUtil.format(new Date(lastActionEndedTime.get()), "yyyy-MM-dd HH:mm:ss");
}
@Override
public int getThroughputQPS() {
if (initActionStartTime <= 0 || lastActionEndedTime.get() <= 0) {
return 0;
}
return (int) (totalCount.get() / ((lastActionEndedTime.get()-initActionStartTime) / 1000.0) );
}
}
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentPerformanceBenchmarkFactory {
private static final ConcurrentHashMap<String, ConcurrentPerformanceBenchmark> container = new ConcurrentHashMap<String, ConcurrentPerformanceBenchmark>();
@SuppressWarnings("rawtypes")
public static ConcurrentPerformanceBenchmark getBenchmark(Class className) {
return getBenchmark(className, true);
}
@SuppressWarnings("rawtypes")
public static ConcurrentPerformanceBenchmark getBenchmark(Class className, boolean bySimpleName) {
return getBenchmark(bySimpleName ? className.getSimpleName() : className.getName());
}
public static ConcurrentPerformanceBenchmark getBenchmark(String name) {
ConcurrentPerformanceBenchmark cpb = container.get(name);
if (cpb != null) {
return cpb;
}
/* ConcurrentPerformanceBenchmark 会加入JMX,属于昂贵对象,引入替身 */
ReentrantLock stuntman = getStuntmanInstanceByName(name);
try {
stuntman.lock();
cpb = container.get(name);
if (cpb == null) {//Double-check
ConcurrentPerformanceBenchmark cpbNew = new ConcurrentPerformanceBenchmark(name);
ConcurrentPerformanceBenchmark cpbPre = container.putIfAbsent(name, cpbNew);
if (cpbPre != null) {//不可能发生的,因为有锁
throw new IllegalStateException("Concurrent Error ConcurrentPerformanceBenchmark");
} else {
cpb = cpbNew;
}
}
return cpb;
} finally {
stuntman.unlock();
}
}
private static final ConcurrentHashMap<String, ReentrantLock> stuntmanContainer = new ConcurrentHashMap<String,ReentrantLock>();
private static ReentrantLock getStuntmanInstanceByName(String name) {
ReentrantLock stuntman = stuntmanContainer.get(name);
if (stuntman == null) {
ReentrantLock newStuntman = new ReentrantLock();
ReentrantLock preStuntman = stuntmanContainer.putIfAbsent(name, newStuntman);
stuntman = (preStuntman!=null ? preStuntman : newStuntman);
}
return stuntman;
}
}
import java.lang.management.ManagementFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class JmxMBeanManager {
private static final Object mbsCreateMonitor = new Object();
private static JmxMBeanManager thisObj;
private final MBeanServer mbs;
public JmxMBeanManager() {
mbs = ManagementFactory.getPlatformMBeanServer();
}
public static JmxMBeanManager getInstance() {
synchronized (mbsCreateMonitor) {
if (null == thisObj) {
thisObj = new JmxMBeanManager();
}
}
return thisObj;
}
public boolean isRegistered(String name) {
try {
ObjectName objName = new ObjectName(name);
return mbs.isRegistered(objName);
}
catch (Exception e) {
throw new RuntimeException("exception while checking if MBean is registered, " + name, e);
}
}
/** 记录每个类产生的实例的个数 */
@SuppressWarnings("rawtypes")
private final ConcurrentHashMap<Class, AtomicInteger> classInstanceCounter = new ConcurrentHashMap<Class, AtomicInteger>();
@SuppressWarnings("rawtypes")
private int incrAndGet(Class Key) {
return incrAndGet(Key, 1);
}
@SuppressWarnings("rawtypes")
private int incrAndGet(Class key, final int incrValue) {
AtomicInteger bookIdCount = classInstanceCounter.get(key);
if (bookIdCount == null) {
AtomicInteger bookIdPrev = classInstanceCounter.putIfAbsent(key, new AtomicInteger(incrValue));
if (bookIdPrev != null) {
return bookIdPrev.addAndGet(incrValue);
} else {
return incrValue;
}
} else {
return bookIdCount.addAndGet(incrValue);
}
}
public void appendMBean(Object theBean) {
appendMBean(theBean, null, 5);
}
/**
* @param simpleName NULL的时,系统自动提取类名简称。
* */
public void appendMBean(Object theBean, String simpleName) {
if (simpleName == null || simpleName.length() > 15) {
throw new IllegalArgumentException();
}
appendMBean(theBean,simpleName, -1);
}
public void appendMBean(Object theBean, String simpleName, int prefix) {
String beanName = genBeanName(theBean, simpleName, prefix);
if (JmxMBeanManager.getInstance().isRegistered(beanName)) {
JmxMBeanManager.getInstance().unregisterMBean(beanName);
}
JmxMBeanManager.getInstance().registerMBean(theBean, beanName);
}
@SuppressWarnings("rawtypes")
protected String genBeanName(Object theBean, String simpleName, int prefix) {
Class beanClass = theBean.getClass();
String prefixName = (prefix < 0 ? beanClass.getName() : packagePrefix(beanClass, prefix));
String typeName = (simpleName==null ? beanClass.getSimpleName() : simpleName );
// String prefixName = beanClass.getName();
// String typeName = beanClass.getSimpleName();
int instanceNum = incrAndGet(beanClass);
String beanName = prefixName+":type="+typeName+ "-" + instanceNum;;
return beanName;
}
private static String packagePrefix(String className, int maxDot) {
int fromIndex = -1;
int lastIndex = 0;
int iteration = 0;
do {
lastIndex = fromIndex;
fromIndex = className.indexOf(".", fromIndex+1);
iteration ++;
} while (iteration < maxDot && fromIndex!=-1);
if (lastIndex <= 0) {
return className;
}
return className.substring(0,lastIndex);
}
@SuppressWarnings("rawtypes")
private static String packagePrefix(Class classArg, int maxDot) {
return packagePrefix(classArg.getName(), maxDot);
}
private void registerMBean(Object theBean, String name) {
try {
ObjectName objName = new ObjectName(name);
mbs.registerMBean(theBean, objName);
}
catch (Exception e) {
throw new RuntimeException("exception while registering MBean, " + name, e);
}
}
private void unregisterMBean(String name) {
try {
ObjectName objName = new ObjectName(name);
mbs.unregisterMBean(objName);
}
catch (Exception e) {
throw new RuntimeException("exception while unregistering MBean, " + name, e);
}
}
public Object getAttribute(String objName, String attrName) {
try {
ObjectName on = new ObjectName(objName);
return mbs.getAttribute(on, attrName);
}
catch (Exception e) {
throw new RuntimeException("exception while getting MBean attribute, " + objName + ", " + attrName, e);
}
}
public Integer getIntAttribute(String objName, String attrName) {
return (Integer) getAttribute(objName, attrName);
}
public String getStringAttribute(String objName, String attrName) {
return (String) getAttribute(objName, attrName);
}
}
使用DEMO:
ConcurrentPerformanceBenchmark benchmarkParse = ConcurrentPerformanceBenchmarkFactory.getBenchmark("RDBLoaderParse");
ConcurrentPerformanceBenchmark benchmarkStore = ConcurrentPerformanceBenchmarkFactory.getBenchmark("RDBLoaderStore");
try {
Entry entry = rdb.next();
while (entry != null) {
long st = SystemClock.systemCurrentTimeMillis();
if (entry.value != null) {//过滤机制的存在,可能VALUE为空
freqCtrl.set(entry.key, (ConcurrentHashMap<String,FreqCtrlPeriod>)entry.value);
}
long mt = SystemClock.systemCurrentTimeMillis();
entry = rdb.next();
long et = SystemClock.systemCurrentTimeMillis();
benchmarkStore.benchmarkAction(1, st, mt);
benchmarkParse.benchmarkAction(1, mt, et);
}
} finally {
if ( rdb!= null) {
rdb.close();
}
LOG.info("loaded rdb named {} in {}", rdbFile.getName(), Thread.currentThread().getName());
}
JMX查看性能效果: