Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2011-10-25) 证券转发程序的程序调优记录

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

这些天一直在想办法优化证券转发程序的性能。

终于跑起了Simulator和MDF程序,并使用jvisualvm检查了一下线程的运行情况,发现一切都挺正常的。

这可找不到下手的地方了。于是决定从头开始,一点点猜测一点点验证。

首先是我的电脑配置:

我一步步地猜想和测试:

一、单机使用Socket来发送和接收数据,最大速度能达到多少呢?


我用socket写了一个最简单的Server和Client程序。Server不断向Client发送,每次10K。Client收到后直接丢弃,只计算收到的字节的数据,打印出来。

代码如下:

Server.java

public class SimpleServer {

public static void main(String[] args) throws Exception {       
    ServerSocket server = new ServerSocket(6666);       
    Socket socket = server.accept();       
    OutputStream output = socket.getOutputStream(); 

    byte[] bytes = new byte[32 * 1024]; // 32K      
    while (true) {       
        output.write(bytes);       
    }       
}       

}

Client.java

public class SimpleClient {

public static void main(String[] args) throws Exception {       
    Socket socket = new Socket("127.0.0.1", 6666);       
    InputStream input = socket.getInputStream();       
    long total = 0;       
    long start = System.currentTimeMillis(); 

    byte[] bytes = new byte[32 * 1024]; // 32K      
    for (int i = 1;; i++) {       
        total += input.read(bytes);       
        if (i % 1000000 == 0) {       
            long cost = System.currentTimeMillis() - start;       
            System.out.printf("Read %,d bytes, speed: %,d MB/s%n", total, total / cost / 1000);       
        }       
    }       
}       

}

运行之后,发现速度稳定在170MBytes/s。注意此处在计算时除以1000而不是1024来简化,对结果影响不大。

由于在本机运行,数据不经过网卡,都是直接在内存中复制的,所以速度很快。因为此时没有网卡和网络的影响,cpu与内存占了主要因素,所以可见我的电脑的处理能力极限是这么多。

二、两台电脑间用百兆网卡连接,之间最大传输速度是多少

我用一根专用的网线将两台电脑连接起来。两台电脑的网卡都是100Mbits,没有路由器的损耗,可以认为两台电脑间的速度就是100Mbits/s。

然后在一台电脑上运行Server,另一台运行Client,实际速度为10.xMbytes/s。这个结果可认为完全用满了带宽。

三、在公司生产环境中进行以上两个测试,结果如何

服务器1(8核Cpu,2.2GHz; 8G内存,146G硬盘(15000转)),速度:2800MB/s

服务器2(双核Cpu,2.4GHz;4G内存,73G硬盘(10000转)),速度:1800MB/s

从服务器1到服务器2,速度:55MB/s,千兆网卡

看来公司的服务器,配置还不错。

四、Simulator的最大发送速度是多少

我使用“一”中的Client在本机接收Simulator的数据(不经过网卡),以测试其性能,大约22MB/s。因为Simulator的数据是实时从文件中读取的,而硬盘的读取速度差不多20多M,所以Simulator的性能应该还是不错的。如果预先把数据都放在内存中,可能速度会更高一些。

五、测试MDF的接收性能

MDF分为两个部分,一是接收,把数据保存在内存中,二是发送,把数据转发给客户端。这里先测试接收。

我在一台电脑上放simulator,另一个放MDF,测试结果还不错,能达到10MB/s。看来接收端没有性能问题。(注:测试时一定要把log4j的Console去掉,不去的话,只有3M多)

六、测试MDF的发送性能

MDF的发送有点不太好测,这跟其内部实现有关。MDF接收的数据,并不是完全保存在内存中,而是只保存最近的5000条。之所以这样,一是因为当时开发时使用的是32位机,jvm中的Xmx最大只能设不到1G,如果把数据都放在内存中,可能不够。所以默认情况下,MDF只保存最近的5000条以快速发送(大多数时候够用),如果中途有新机加入取数据,则会从数据库中读取。

但在测试时发现,很难把握好时间让MDF刚好用到内存中的数据。这是因为,如果开了simulator,会对MDF有影响。但不开simulator,则发送时只能从数据库中取数据。怎么测都得读数据库。测试结果为6MB/s,没有用完带宽。使用jvisualvm进行监测,发现占用时间最多的函数是从数据库中读取数据。

如果修改MDF的设置,让它保存最近400000条呢?这样就不需要从数据库中读了(因为当时信息总量为30多万条)。

测试结果为7MB/s左右。虽然比读数据库好一些,但还是没有用完带宽,为什么?

使用jvisualvm监测,发现的确没有从数据库读取数据。另外,发现在发送信息的过程中,很多与Message类相关的方法被调用了很多次,如下图:

image

这些方法是否可以简化?直接把信息简化为二进制数组放在内存中,而不要使用一些InnerBytes之类给它套上?

另外,在线程图页面,也发现了不少“阻塞”的线程:

image

虽然可以相信图中这么多红色是因为jvisualvm的Profiler抽样监测加大了阻塞的机率,但可以推测,在高并发状态下阻塞情况也会比较容易发生。可能正是因为它而导致发送速度变慢。现在从内存列表中取数据时,的确有一些synchronized操作。

我们需要先修改代码,把所有数据放入内存之后,再优化这里的synchronized。

至此,需要对MDF进行比较大的修改,才能继续测,一时半会儿改不完。改天再继续测。

comments powered by Disqus