2015年2月10日 星期二

Howto: methods of creating testing user data for benchmarking ejabberd



This article talks about methods I learnt to create testing users when I setup an ejabberd (XMPP service implemented in Erlang language) and tries to benchmark the performance my new setup.

When talking about the benchmark, the first step is always to have the testing data prepared. In our case, we need to prepare the user accounts with passwords just in order to allow testing clients to log in to the XMPP server and then we can start evaluating the performance by applying different configurations. Unfortunately, if you are using Mnesia as the database backend to store these information and you are unfamiliar with Erlang like I did. You probably don't know how to batch creating users in a short time.

The first and the most naive method to create the test user is to use the command ejabberdctl. This tool comes along with the ejabberd package when you installed (Assume we are using Ubuntu 12.04+/Debian 7) and allows you to talk to ejabberd through command line. One of the function is to to register user

sudo ejabberdctl register <username> <host> <password>

For example, if you want to create an account handsome@1a2b.com with password set as 1a2b. You can execute command

sudo ejabberdctl register handsome 1a2b.com 1a2b

And then it shall create an account for you immediately. But the problem to create account in this way is that it's very slow and you cannot speed up by executing multiple ejabberdctl command concurrently (it will crash). It took roughly 120 seconds to create a thousand accounts (Intel Core i7 2.8GHz, 8GB RAM) which is roughly 8 accounts per second. You can image how long it gonna take if you want to create more.

The second one is to create account by using the in-band registration extension which is supported by ejabberd. To enable the in-band registration, you need to

  1. Modify /etc/ejabberd/ejabberd.cfg
      {access, register, [{allow, all}]}.
      {registration_timeout, infinity}.
    and make sure mod_register is listed in modules.
  2. Restart service: sudo ejabberd restart
And then you can use tsung to create the testing account with the following xml file (tsung is a tool used for testing http/xmpp performances which is also written in Erlang).
---
  <?xml version="1.0"?>
  <!DOCTYPE tsung SYSTEM "/usr/share/tsung/tsung-1.0.dtd">
  <tsung loglevel="debug" dumptraffic="false" version="1.0">
    <clients>
      <client host="localhost" use_controller_vm="true" maxusers="1000000"></client>
    </clients>

    <servers>
      <server host="1a2b.com" port="5222" type="tcp"/>
    </servers>

    <!-- register 1000000 users in less than 30 minutes  -->
    <load>
      <arrivalphase phase="1" duration="30" unit="minute">
        <users maxnumber="1000000" interarrival="0.001" unit="second"/>
      </arrivalphase>
    </load>

    <options>
      <option type="ts_jabber" name="global_number" value="1000000"/>
      <option type="ts_jabber" name="userid_max" value="1000000"/>
      <option type="ts_jabber" name="domain" value="1a2b.com"/>
      <option type="ts_jabber" name="username" value="blah"/>
      <option type="ts_jabber" name="passwd" value="blahblah"/>
    </options>

    <sessions>
      <session probability="100" name="jabber-example" type="ts_jabber">
        <request><jabber type="connect" ack="local"/></request>

        <request>
          <match do="abort" when="match">error</match>
          <jabber type="register" ack="local" id="new"/>
        </request>

        <request>
          <jabber type="close" ack="local"/>
        </request>
      </session>
    </sessions>
  </tsung>

---
And then execute command: tsung -f create_user.xml start
If things working correctly, then you shall be able to have all user created.
Note, you have to set appropriate thresholds to throttle the concurrent connections established from tsung to ejabberd. Otherwise, part of the registration requests might fail. (and you have to do it all over again)

But still, I prefer the last method I tried to create the user. That is instead of registering XMPP user by using tsung. I ended up with writing a python script which uses xmpppy module to do the in-band user registration.
In this way, it's easy for you to create users with a simple script without worrying about first configuring tsung configuration xml file.

Below is a python code snippet I found at stackoverflow.
---
import xmpp

def register_user(jid, password):
 jid=xmpp.protocol.JID(jid)
 cli=xmpp.Client(jid.getDomain(), debug=[])
 cli.connect()
 # getRegInfo has a bug that puts the username as a direct child of the

 # IQ, instead of inside the query element.  The below will work, but
 # won't return an error when the user is known, however the register
 # call will return the error.
 xmpp.features.getRegInfo(cli,
         jid.getDomain(),
         sync=True)
 if xmpp.features.register(cli,
         jid.getDomain(),
         {'username':jid.getNode(),
         'password':password}):
     return 0
 else:
     print("Error registering: %s\n" % jid)
     return -1
---
I modify the code snippet as function and run the function with multiple threads. In this way I can create a large amount of user accounts in a more reliable way and shorter time.