[ejabberd] [PATCH] Kill sockets with very slow receivers

Stephan Maka stephan at spaceboyz.net
Mon Nov 30 03:01:13 MSK 2009


Hi

We're working with ejabberd in a high-throughput setup. That means we
use high-bandwidth shapers or none at all. When one of our clients is
very slow in receiving stanzas ejabberd starts accumulating more and
more pending messages. I'm afraid this can happen with default shapers
over time too.

Here's a patch that solves this problem for me and a simple Ruby test
script. ejabberd without shapers easily consumes >1GB RSS after running
it.

-------------- next part --------------
#!/usr/bin/env ruby
require 'socket'

s = TCPSocket.new('::1', 5222)
s << <<-eof
<stream:stream to='localhost'
               xmlns='jabber:client'
               xmlns:stream='http://etherx.jabber.org/streams'>
<iq type='set'>
  <query xmlns='jabber:iq:auth'>
    <username>a</username>
    <password>a</password>
    <resource>clog</resource>
  </query>
</iq>
eof

buf = ''
while buf += s.recv(1)
  break if buf.index('<iq')
end

n = 0
loop do
  s.puts('<presence/>')

  # If target's send hangs it cannot receive
  buf += s.recv(1) # if n % 100 == 0

  n += 1
  print "\r#{n}"
  $stdout.flush
end
-------------- next part --------------
>From 391827622abd3ebfec311a44071857e8b118135c Mon Sep 17 00:00:00 2001
From: Astro <astro at spaceboyz.net>
Date: Mon, 30 Nov 2009 00:52:33 +0100
Subject: [PATCH] ejabberd_socket:send/2: check_message_queue_len() to kill uber-slow receivers

---
 src/ejabberd_socket.erl |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
index a3c008c..c76c7f2 100644
--- a/src/ejabberd_socket.erl
+++ b/src/ejabberd_socket.erl
@@ -162,6 +162,7 @@ reset_stream(SocketData) when is_atom(SocketData#socket_state.receiver) ->
 
 %% sockmod=gen_tcp|tls|ejabberd_zlib
 send(SocketData, Data) ->
+    check_message_queue_len(),
     case catch (SocketData#socket_state.sockmod):send(
 	     SocketData#socket_state.socket, Data) of
         ok -> ok;
@@ -225,3 +226,14 @@ peername(#socket_state{sockmod = SockMod, socket = Socket}) ->
 %%====================================================================
 %% Internal functions
 %%====================================================================
+
+-define(MAX_MESSAGE_QUEUE_LEN, 1000).
+
+check_message_queue_len() ->
+    {message_queue_len, MessageQueueLen} =
+	process_info(self(), message_queue_len),
+    if
+	MessageQueueLen > ?MAX_MESSAGE_QUEUE_LEN ->
+	    exit(max_message_queue_len_exceeded);
+	true -> ok
+    end.
-- 
1.6.5.3



More information about the ejabberd mailing list