2012-04-18 1 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?

Пример кода прокси-сервера использует блокировку блокировки трафика в качестве решения условия гонки, сообщенного в 2010 году (http://markmail.org/message/x7jc6mqx6ripynqf), происходящего вокруг насыщенных каналов и устанавливающего записываемое и читаемое состояние входящих и исходящие каналы.

Теперь, в моем объединенном примере, при более высокой нагрузке это приводит к тупиковой ситуации, потому что переплетен другой замок «handshakelock» в коде SSL. См. Диагностический вывод профилировщика ниже.

Я боюсь, что даже после прочтения первоначальной дискуссии я не понимаю основной проблемы с блокировкой трафика, достаточной для того, чтобы найти прямое решение для этого тупика.

(это было с Нетти 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

Покажите нам свои пользовательские обработчики –

+0

BTW 3.2.6 довольно старый .. вы должны перейти на 3.4.0. Final –

ответ

1

Ладно, я думаю, что я установил его.

Решение предыдущей задачи гонки в примере прокси без необходимости включает вызов write() в синхронизированном блоке.

Исходная задача была это (редко) состояние гонки между исходящим потоком (К) и входящим поток (TI):

  1. К: inboundChannel.write() (на messageReceived)
  2. К : inboundChannel.isWritable() возвращает ложь (в messageReceived)
  3. Затем в ожидании записи выданных в (1) смываются
  4. TI: inboundChannel.isWritable() возвращает истину (в channelInterestChanged)
  5. TI: НУ tboundChannel.setReadable (истина) (при channelInterestChanged)
  6. К: outboundChannel.setReadable (ложь) (на messageReceived)

Решение в 2010 году ввести синхронизации (с использованием 'trafficlock') вокруг установки читаемый флаг в обработчике messageReceived() из обоих inboundChannel и outboundChannel (а также в обработчике InterestChanged), например, так:

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, write(), из синхронизированный блок.

Звонок на запись() вызвал тупик, так как с помощью этого вызова в SSLHandler он использует другой замок handshakelock.

Итак, я переместил вызов write() вне синхронизированного блока в обоих местоположениях. Тупик теперь исчез. Я предлагаю, чтобы соответствующий «прокси-пример» был соответствующим образом изменен.