这次开发功能是OEM统计报表。统计报表的数据由大数据平台部的同事收集,数据的展示由我们部门开发。
大数据那边使用 Kylin 分布式分析引擎(kylin官方文档)。
Kylin 虽比较偏向大数据相关,但最终大佬们决定把访问 Kylin 的 Dubbo 接口也由我们开发,比较坑。
解决方案一:Mybatis
首先我们搭建一个 shop-mod-bigdata (+ shop-mod-bigdata-interface) 模块用于访问 Kylin,暴露 Dubbo 服务。
Kylin 官方文档提供了 JDBC 的方式访问Kylin。
为了长期考虑,是否可以用上连接池?
Kylin 有提供 JDBC 的方式访问,那就应该会遵循 JDBC 的规范,
参考 Mysql 的连接池配置进行配置
destroy-method="close">
加上连接池配置后,下面就要验证和测试了。
1:调试,跟源码。
2:为便于观察运行细节是否正常,修改 log4j 日志配置
log4j.logger.org.apache.tomcat.jdbc=DEBUG
log4j.logger.org.springframework.jdbc=DEBUG
log4j.logger.org.apache.kylin.jdbc=DEBUG
log4j.logger.org.apache.ibatis=DEBUG
log4j.logger.org.mybatis.spring=DEBUG
3:测试有没有内存泄漏,长时间运行时是否有问题:CPU 是否异常,线程数是否异常,连接池是否异常,JVM垃圾回收是否异常,
刚好用用学到的 JVM 相关的东东,这里我就直接使用 JDK 自带的工具(jvisualvm),
入口的话就直接用单元测试+线程池来跑
/**
* Kylin 访问压测
*
* @author zhangjl
* @date 2018年3月9日
*/
public class KylinPressureTest extends TestBase {
@Resource
private PersonFacade personFacade;
@Test
public void pressureTest() {
ExecutorService threadPool = Executors.newFixedThreadPool(10);
final AtomicInteger counter = new AtomicInteger();
final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
// 生成垃圾
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
int index = generateGarbage();
LOGGER.info("index={}", index);
}
}, 5, 5, TimeUnit.SECONDS);
// 访问 Kylin
for (int i = 0; i < 10000; i++) {
LOGGER.info("第" + (i + 1) + "轮开始");
for (int j = 0; j < 10; j++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
int currNum = counter.addAndGet(1);
try {
PageInfo page = new PageInfo();
page.setPagination(true);
PersonDto condition = new PersonDto();
condition.setGender(counter.get());
ApiResult> result = personFacade.page(condition, page);
LOGGER.info("Kylin访问结果, result={}", result);
} catch (Exception e) {
LOGGER.error("Kylin访问异常", e);
}
LOGGER.info("Kylin访问,当前为第{}个,time={}", currNum, sdf.format(new Date()));
}
});
}
try {
Thread.sleep(1L * 60L * 1000L);
} catch (InterruptedException e) {
LOGGER.error("线程中断", e);
}
}
// 等待
waitingUserInputExit();
}
private void waitingUserInputExit() {
Scanner scanner = null;
try {
scanner = new Scanner(System.in);
while (true) {
String input = scanner.next();
if ("exit".equals(input)) {
break;
}
}
} catch (Exception e) {
LOGGER.error("输出异常", e);
} finally {
if (null != scanner) {
scanner.close();
}
}
}
private int generateGarbage() {
int index = 0;
byte[] array1 = new byte[100 * 1024 * 1024]; // 100M
// byte[] array2 = new byte[100 * 1024 * 1024]; // 100M
array1[index++] = new Byte("1");
// array2[index++] = new Byte("2");
return index;
}
}
修改 VM arguments 参数:
-Xmx1024m -Xms1024m -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintHe