今天上班的路上在对比Tomcat和Jety的连接模型。Tomcat使用多线程处理请求,一个请求一个线程;Jetty则采用NIO。有文章说,对于逻辑复杂、处理时间较长的连接,Tomcat有优势,但是对于处理时间较短的连接,Jetty有优势。毫无疑问DNS的处理时间是很短的,看来把之前connector部分多线程的处理模型换成NIO的,应该性能会有一些提升。以后几天一个大的开发计划,就是调研Java NIO和Jetty里的实现,写一个完整的NIO connector。Cache机制开发延后。
上午在网上找了点资料,磕磕碰碰把基于NIO的服务器模型搭出来了。因为DNS使用的是UDP协议,同时数据量很小,所以NIO并没有起到理想中的效果。
主要服务器部分代码在https://github.com/flashsword20/blackhole/blob/nio/src/main/java/us/codecraft/blackhole/connector/UDPSocketMonitor.java。测试之后的效果让人失望,NIO效率比多线程+BIO更低,只有24000~28000qps,并且因为代码不熟悉,系统变得很不稳定。所以暂时保留到NIO分支了。
结论是这样的:
一个DNS query的包大小大约是几十byte,而response也不超过100 byte,如此小的传输量,同时因为UDP包也不涉及连接建立等东西,发送速度也很快,所以NIO发挥不了效率。
晚上回家,尝试加入cache机制:
使用了ehcache,但是死活都存在UDP包乱序的问题。后来发现
对于同一key,ehcache获取出来的对象总是同一个,这也是进程内缓存的特殊之处,不妨将其想想为一个Map
而我会尝试改变其ID值,结果就导致看起来ID变了,其实也改变了其他线程获取到的值,出现了不确定性!
后来改进了数据结构,尝试写一个CopyOnWriteMessage(Message是dnsjava中DNS报文的抽象类),结果因为其很多方法都是私有,所以失败了。后来构建了一个UDPPackage的对象,尝试将byte[]用CopyOnWrite和访问锁的方式解决并发问题,测试结果CopyOnWrite性能会好一点,这也是因为数据量较小,而且Arrays.copyOf是本地方法吧。
后来测试,值得高兴的是有缓存的情况下,转发模式效率达到了40000qps,可喜可贺!
家里连公司,benchmark里,UDP丢包率大概在10%,效果相当差,所以说网络才是第一要素!
来源:oschina
链接:https://my.oschina.net/u/190591/blog/97231