2012-04-18 53 views
0

我組合了netty的大部分例子HexdumpProxy(http://netty.io/docs/stable/xref/org/jboss/netty/example/proxy/)和SecureChat(http://netty.io/docs/ stable/xref/org/jboss/netty/example/securechat)組成一個支持SSL(和非SSL)的代理(到非SSL後端)。這似乎是一個好主意,被證明是很簡單的,而且正是我目前所需要的。如何解決代理示例trafficlock和ssl handshakelock的死鎖?

代理示例代碼使用trafficlock鎖作爲解決發生圍繞飽和頻道和設定輸入的可寫和可讀狀態在2010年報道的競爭條件(http://markmail.org/message/x7jc6mqx6ripynqf)和傳出頻道。

現在,在我的例子中,在更高的負載下,這會導致死鎖,因爲SSL代碼中的另一個鎖「handshakelock」是交織在一起的。請參閱下面的分析器診斷輸出。

我擔心即使在閱讀了原始討論之後,我也不明白交通鎖的問題足以找到解決這個僵局的簡單方法。

(這是與網狀3.2.6)

Java-level deadlock has been detected 

This means that some threads are blocked waiting to enter a synchronization block or 
waiting to reenter a synchronization block after an Object.wait() call, where each thread 
owns one monitor while trying to obtain another monitor already held by another thread. 

Deadlock: 


New I/O client worker #1-2 is waiting to lock [email protected] which is held by New I/O server worker #1-2 
New I/O server worker #1-2 is waiting to lock [email protected] which is held by New I/O client worker #1-2 




Thread stacks 


New I/O client worker #1-2 [BLOCKED; waiting to lock [email protected]] 
org.jboss.netty.handler.ssl.SslHandler.wrap(SslHandler.java:665) <== sync handshakelock 
org.jboss.netty.handler.ssl.SslHandler.handleDownstream(SslHandler.java:461) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:591) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendDownstream(DefaultChannelPipeline.java:776) 
org.jboss.netty.channel.Channels.write(Channels.java:632) 
org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream(OneToOneEncoder.java:70) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:591) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:582) 
org.jboss.netty.channel.Channels.write(Channels.java:611) 
org.jboss.netty.channel.Channels.write(Channels.java:578) 
org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:251) 
com.activevideo.frontend.ProxyInboundHandler$OutboundHandler.messageReceived(ProxyInboundHandler.java:162) <== sync trafficlock 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) 
org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:302) 
org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:317) 
org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:299) 
org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:216) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) 
org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) 
org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) 
org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351) 
org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282) 
org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202) 
org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) 
org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44) 
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(unknown source) 
java.util.concurrent.ThreadPoolExecutor$Worker.run(unknown source) 
java.lang.Thread.run(unknown source) 


New I/O server worker #1-2 [BLOCKED; waiting to lock [email protected]] 
com.activevideo.frontend.ProxyInboundHandler.channelInterestChanged(ProxyInboundHandler.java:138) <== sync trafficlock 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:116) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.channelInterestChanged(SimpleChannelUpstreamHandler.java:192) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:116) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.channelInterestChanged(SimpleChannelUpstreamHandler.java:192) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:116) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.channelInterestChanged(SimpleChannelUpstreamHandler.java:192) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:116) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) 
org.jboss.netty.channel.Channels.fireChannelInterestChanged(Channels.java:335) 
org.jboss.netty.channel.socket.nio.NioWorker.setInterestOps(NioWorker.java:728) 
org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handleAcceptedSocket(NioServerSocketPipelineSink.java:129) 
org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventSunk(NioServerSocketPipelineSink.java:76) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendDownstream(DefaultChannelPipeline.java:771) 
org.jboss.netty.handler.ssl.SslHandler.handleDownstream(SslHandler.java:430) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:591) 
org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendDownstream(DefaultChannelPipeline.java:776) 
org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream(OneToOneEncoder.java:60) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:591) 
org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:582) 
org.jboss.netty.channel.Channels.setInterestOps(Channels.java:652) 
org.jboss.netty.channel.AbstractChannel.setInterestOps(AbstractChannel.java:222) 
org.jboss.netty.channel.AbstractChannel.setReadable(AbstractChannel.java:244) 
com.activevideo.frontend.SSLProxyInboundHandler$BackendConnector$1.operationComplete(SSLProxyInboundHandler.java:92) 
org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultChannelFuture.java:381) 
org.jboss.netty.channel.DefaultChannelFuture.addListener(DefaultChannelFuture.java:148) 
com.activevideo.frontend.SSLProxyInboundHandler$BackendConnector.operationComplete(SSLProxyInboundHandler.java:87) 
org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultChannelFuture.java:381) 
org.jboss.netty.channel.DefaultChannelFuture.notifyListeners(DefaultChannelFuture.java:367) 
org.jboss.netty.channel.DefaultChannelFuture.setSuccess(DefaultChannelFuture.java:316) 
org.jboss.netty.handler.ssl.SslHandler.setHandshakeSuccess(SslHandler.java:1040) 
org.jboss.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:838) 
org.jboss.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:907) <=== sync handshakelock 
org.jboss.netty.handler.ssl.SslHandler.decode(SslHandler.java:620) 
org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:282) 
org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:214) 
org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) 
org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) 
org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) 
org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) 
org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351) 
org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282) 
org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202) 
org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) 
org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44) 
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(unknown source) 
java.util.concurrent.ThreadPoolExecutor$Worker.run(unknown source) 
java.lang.Thread.run(unknown source) 
+0

向我們展示您的自定義處理程序 – 2012-04-18 05:56:36

+0

順便說一句,3.2.6是相當古老的..你應該升級到3.4.0.Final – 2012-04-18 09:56:44

回答

1

好吧,我想我固定它。

代理示例中較早爭用條件的解決方案不必要地包含對synchronized塊中的write()調用。

原來的問題有這種(罕見)比賽即將離任的線程(TO)和即將到來的線程(TI)之間的條件:)inboundChannel.write((在的messageReceived)

  • TO:

    1. TO :inboundChannel.isWritable()返回(在的messageReceived)
    2. 在(1)被刷新發出接着的未決寫假
    3. TI:inboundChannel.isWritable()返回真(在channelInterestChanged)
    4. TI:歐tboundChannel.setReadable(真)(在channelInterestChanged)
    5. TO:outboundChannel.setReadable(假)(在的messageReceived)

    在2010年的解決方案是圍繞設置可讀標誌引入(用 'trafficlock')同步同時在inboundChannel和outboundChannel(以及在InterestChanged處理程序)的的messageReceived()處理,像這樣:

    synchronized (trafficLock) { 
        outboundChannel.write(msg); 
        // If outboundChannel is saturated, do not read until notified in 
        // OutboundHandler.channelInterestChanged(). 
        if (!outboundChannel.isWritable()) { 
        e.getChannel().setReadable(false); 
        } 
    } 
    

    這確實解決了競爭條件,如可以防止步驟3,4和5干涉步驟2和步驟6.但是,將步驟1(寫入())離開是安全的e同步塊。

    對write()的調用導致了死鎖,因爲在SSLHandler中調用該函數時,它使用另一個鎖handshakelock。

    所以..我把這個調用移到了兩個位置的同步塊之外的write()。僵局現在消失了。我建議「官方」代理示例相應地更改。