不受控制的客户端使用内存过多(websocketx)

时间:2012-06-14 23:01:07

标签: netty

当发送不受控制量的TextWebSocketFrame到一个简单的Netty WebSocket echo服务器实现(在examples包中找到的实现略有修改版本)时,无需等待ChannelFuture上的客户端sync(),堆内存使用情况服务器呈指数级增长,直到它最终耗尽内存。

测试用例:客户端不会等到写入实际字节,也不等待服务器在写下一个文本框之前将文本“回显”回客户端

for (int i = 0; i < 10000000; i++) {
    ch.write(new TextWebSocketFrame("Message #" + i));
}

当观察yourkit内存分析器(测试15秒后写入大约20.000帧)时,BigEndianHeapChannelBuffer对象的数量已经过度增长。

BigEndianHeapChannelBuffer 284,509 (objects) 9,104,288 (shallow size) (after ~30.000 frames sent within 10 second window)

在服务器端,可以观察到主要来自BigEndianHeapChannelBuffers和CompositeChannelBuffers对象的大堆,这些对象从不清理也不会被垃圾收集(这可能不会作为引用被保留)。我猜这与(单个)工作线程无法将下游“echo”响应写入客户端通道有关,因为它忙于处理来自客户端的快速传入请求

有没有办法在服务器端阻止/限制(意外拒绝服务)?

1 个答案:

答案 0 :(得分:4)

在Netty中,大多数I / O操作都是异步的。因此,在不等待先前的写入完成的情况下编写数千条消息将获得OutOfMemoryError。为了避免这种情况,我更喜欢使用计数器变量来计算挂起写入的数量。例如:

private final AtomicInteger pendingWrites = new AtomicInteger();

...
while (pendingWrites.get() < MAX_PENDING_WRITES) {
  pendingWrites.incrementAndGet();
  ch.write(msg).addListener(new ChannelFutureListener() {
    ...
    pendingWrites.decrementAndGet();
    if (pendingWrites.get() < MAX_PENDING_WRITES) {
      // resume writing here
    }
  }
}

或者,您可以使用基本上执行相同工作的ChunkedWriteHandler