Datastax Cassandra Driver Analyst (1)-Overral Introduce

最近项目中用到了Cassandra, 期间遇到不少问题,很多问题都是源于对driver本身的不了解,例如不知道有TTL就打算去写一个定时JOB做清理过期数据,不知道在多DC的情况下默认的loadbalance策略需要一个指定的DC Name,不知道默认Driver里面有性能监控的metrix。通过解决这些问题,翻看了不少driver的源码,深感有必要仔细阅读下cassandra driver, 毕竟对于应用程序开发者来说,更多可控的地方还是在driver本身。

同时Datastax Cassandra Driver含有150+的类,结构清晰,而且用了jetty/guava/metric等一些实用的jar(如下图所示), 奔着学习如何写client, 也是非常值得一读。

pom.xml - Eclipse

其中lz4/snappy用于传输时的压缩,netty用于通信,guava为常见工具类,如阻塞/异步处理消息。

对于一个client,无非包含5个要点:

(1)配置

(2)通信处理

(3)线程模型

(4)数据结构

(5)业务逻辑

首先来看下cassandra的配置有哪些?

Cluster含有一个Manager:

Manager有4个成员:

Cluster Name:   默认采用的是 “cluster” + CLUSTER_ID.incrementAndGet(),可不配。

ContactPoints:  配置的通信节点,可以有多个。区别于具体做业务的节点,这些节点负责建立通信,同步一些节点Up/Down等信息。

Configure: 核心配置,有N多配置,决定了Driver如何工作;

Listerners: 监听器,当有节点up/down时,触发监听器,默认无配置。

 

对于Configuration的设计,使用最多的是策略模式+工厂模式。其中配置有很多,比如有用来监控Driver性能的metrics Options, 有负载均衡的loadbancing policy.

基本上每个配置都有默认配置,例如默认会启用Jmx来report metrics.

所以如果不够了解driver就用默认配置为好,但是如果想最大化driver的性能,还是需要了解每个配置的含义,这也是唯一对于用户可见可改之地。

 

学习要点: 设计模式(策略模式+工厂模式)

 

how to do java application’s code coverage with emma?

本文主要讨论如何用emma给Java Application做代码覆盖,区别于java单元测试的code coverage, Java Application一直处于运行状态,所以不能暴力的强行kill进程来收集代码覆盖数据,所以本文梳理下网络上的相关文章,整理下过程,并记录下尝试过程中一些常见问题的解决:

基本步骤分为五步:

(1)修改编译选项:

将编译的选项设置为debug启用,同时要注意debug的level.例如maven compiler默认就启用了debug但是没有将debug的level都设置进去,所以这里注意设置启用和启用的级别。例如对于maven项目中的compile plugin: (如果使用了progard进行混淆,则去掉混淆)

<configuration>
<debug>true</debug>
<debuglevel>lines,source</debuglevel>
</configuration>

(2) 注入:
注入coverage信息,可以使用-ix来过滤指定包:
java emma instr -m overwrite -cp server.jar -ix +com.server* -Dmetadata.out.file=coverage.em

note:

2.1 其中在 “+” 符号后的文件为包含进的文件, “-” 后面的内容为排除在外的文件,例如

-ix +com.foo.*,-com.foo.test.*,-com.foo.*Test*

2.2 要支持EMMA,需要复制emma.jar到lib目录,记得修改权限,例如:jdk1.7.0_60/jre/lib/ext/emma.jar

2.3 有时候加上过滤条件导出并没有生效,显示过滤的文件少了,但是产生的coverage.em基本没有变,可以删掉原先的,估计有merge操作。

(3)修改应用启动的jvm参数并启动应用:

3.1 修改启动应用的jvm参数:
-Demma.rt.control=true

为什么要增加这项,可以查看代码:默认是不启动实时收集功能。

IProperties appProperties = getAppProperties();
if (appProperties != null) {
String property = appProperties.getProperty("rt.control", "false");
enableController = Property.toBoolean(property);
}

if (enableController) {
int port = 47653;

if (appProperties != null) {
String property = appProperties.getProperty("rt.control.port");
if (property != null) {
try {
port = Integer.parseInt(property);
} catch (NumberFormatException ignore) {
System.err
.println("ignoring malformed [rt.control.port] value: "
+ property);
}

ps: 还存在其他很多参数,例如-Demma.coverage.out.file=/var/coverage.ec控制输出文件,-Demma.rt.control.port=12345,用来控制端口

3.2 启动,并查看log来确认是否正常:

应该存在2行log:其中第二行对应3.1要解决的问题。

EMMA: collecting runtime coverage data ...
EMMA: runtime controller started on port [47653]

其中,如果启动失败并提示class format错误,这是应用是JDK1.7编译的,而之前注入使用的emma的注入方式应该是不兼容的,所以可以通过增加JVM启动参数来解决:
1.7使用-XX:-UseSplitVerifier  如果是1.8使用-Xverify:none

(4)执行测试用例,然后使用命令收集数据:

java emma ctl -connect localhost:47653 -command coverage.get,coverage.ec

假设需要合并之前的,执行命令:

java emma merge -input coverage1.ec,coverage2.ec -out coverage.ec

PS: 也可以支持em的Merge.

(5)结合(2)产生的em和(4)产生的ec文件以及源代码的路径产生html报告:

java emma report -r html -sp /xxxx/xxxx/src/main/java -in coverage.em,coverage.ec -Dreport.html.out.file=coverage.html

这里需要注意的是源代码要和产生的统计信息一致,否则假设源代码当中的一个文件已经重命名,那么在html报告中还是提示找不到源文件。

实际测试中,我们还会应用单元测试,产生覆盖率,然后可以与上述产生的覆盖率合并。-in 支持传多个ec,em.

对于单元测试如何产生覆盖数据,可以直接配置EMMA的maven插件,然后使用mvn emma:emma来产生在target目录:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:-UseSplitVerifier</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>emma-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
</plugin>

 

PS:

通过上面可知,对于Coverage数据的过滤只有在注入阶段,在报告阶段并没有,好在本人同事对emma.jar进行了二次开发(emma_rar),支持在上面的第五步Report阶段过滤Class/Package。

具体命令:

java emma report -r html  -props filter.txt   -sp /xxxx/xxxx/src/main/java -in coverage.em,coverage.ec -Dreport.html.out.file=coverage.html

filter.txt 文件内容的格式可以是report.html.filter.class或者report.html.filter.package,例如示例:

report.html.filter.class=com.Tp.java,com.Constants.java   //多个类用,分割。

这里一定要注意的是:

(1)如果是内部类的过滤,一定不要带上外部类的名字,比如不应该是outer.inner.java,而应该是inner.java.这个可以查看EM文件的内容获知。

(2)支持正则表达式。

Notes:

(1) debug log: -Dverbosity.level=trace1

以上即为整个过程的记录以备忘!