tsungでjabberのmulti user chatに対応するためのpatch
tsungはerlangで書かれたベンチマーク。MUCに対応していなかったので、練習がてら作ってみた。
前提
ユーザ名が"prefix(xxx)"になってること。(xxxは数字)
追加するもの
追加したoptionは以下の二つ。
<option type="ts_jabber" name="muc:domain" value="conference"></option> <option type="ts_jabber" name="muc:member" value="2"></option>
- []muc
- domain[]:mucサーバのドメイン。(同じoptionのname="domain"の前にドットでつなげるだけ。)
- []muc
- member[]:ひとつのroomに何人入るか。
追加したrequestは以下の四つ。
<request> <jabber type="muc:enter" ack="no_ack"></jabber> </request> <request> <jabber type="muc:initial" ack="local"></jabber> </request> <request> <jabber type="muc:chat" show="xa" status="status" ack="no_ack" size="100"/> </request> <request> <jabber type="muc:exit" ack="no_ack"></jabber> </request>
- []muc
- enter[]:roomに入室
- []muc
- initial[]:(roomがまだ無ければ)roomをつくる。
- []muc
- chat[]:roomにメッセージを送る。
- []muc
- exit[]:roomから退室する。
使い方
こんな感じで利用する。
<options> <option type="ts_jabber" name="global_number" value="100"></option> <option type="ts_jabber" name="userid_max" value="10000"></option> <option type="ts_jabber" name="domain" value="localhost"></option> <option type="ts_jabber" name="username" value="user"></option> <option type="ts_jabber" name="passwd" value="password"></option> <option type="ts_jabber" name="muc:domain" value="conference"></option> <option type="ts_jabber" name="muc:member" value="10"></option> </options> <sessions> <session probability="100" name="jabber-example" type="ts_jabber"> <request> <jabber type="connect" ack="no_ack"></jabber> </request> <thinktime value="2"></thinktime> <transaction name="auth_plain"> <request> <jabber type="auth_get" ack="local"></jabber> </request> <request> <jabber type="auth_set_plain" ack="local"></jabber> </request> <request> <jabber type="muc:enter" ack="local"></jabber> </request> <request> <jabber type="muc:initial" ack="local"></jabber> </request> </transaction> <request> <jabber type="presence:initial" ack="no_ack"/> </request> <thinktime value="2"></thinktime> <request> <jabber type="muc:chat" show="xa" status="I may never come back..." ack="no_ack" size="100"/> </request> <thinktime value="2"></thinktime> <transaction name="close"> <request> <jabber type="muc:exit" ack="local"></jabber> </request> <request> <jabber type="close" ack="no_ack"></jabber> </request> </transaction>
patch
diff -crN tsung-1.2.1.old/include/ts_jabber.hrl tsung-1.2.1/include/ts_jabber.hrl *** tsung-1.2.1.old/include/ts_jabber.hrl 2006-09-20 19:52:53.000000000 +0900 --- tsung-1.2.1/include/ts_jabber.hrl 2007-05-16 18:34:10.000000000 +0900 *************** *** 34,39 **** --- 34,41 ---- cle, id = 0, domain, %% jabber domain + muc_domain, %% jabber muc domain + muc_member, %% muc room per member username, %% first chars of username (will append id dynamically) passwd, %% first chars of passwd (will append id dynamically) nonce, %% used to generate sip-digest passwd diff -crN tsung-1.2.1.old/src/tsung/ts_jabber_common.erl tsung-1.2.1/src/tsung/ts_jabber_common.erl *** tsung-1.2.1.old/src/tsung/ts_jabber_common.erl 2006-09-20 19:52:53.000000000 +0900 --- tsung-1.2.1/src/tsung/ts_jabber_common.erl 2007-05-16 18:34:43.000000000 +0900 *************** *** 183,188 **** --- 183,197 ---- << >> end; + get_message(Jabber=#jabber{type = 'muc:enter'}) -> + muc_get_message(Jabber); + get_message(Jabber=#jabber{type = 'muc:initial'}) -> + muc_get_message(Jabber); + get_message(Jabber=#jabber{type = 'muc:chat'}) -> + muc_get_message(Jabber); + get_message(Jabber=#jabber{type = 'muc:exit'}) -> + muc_get_message(Jabber); + get_message(Jabber=#jabber{username=Name, passwd=Passwd, id=Id}) -> FullName = Name ++ Id, FullPasswd = Passwd ++ Id, *************** *** 190,195 **** --- 199,259 ---- %%---------------------------------------------------------------------- + %% Func: muc_get_message/1 + %%---------------------------------------------------------------------- + muc_get_message(Jabber=#jabber{username=Name, id=Id, domain=Domain, muc_domain = MucDomain, muc_member=MucMember}) -> + Room = integer_to_list(list_to_integer(Id) div MucMember), + Nick = integer_to_list(list_to_integer(Id) rem MucMember), + FullName = Name ++ Id ++ "@" ++ Domain ++ "/" ++ Nick, + RoomName = Room ++ "@" ++ MucDomain ++ "." ++ Domain, + muc_get_message(Jabber#jabber{username=FullName}, RoomName, Nick). + %%---------------------------------------------------------------------- + %% Func: muc_get_message/3 + %%---------------------------------------------------------------------- + muc_get_message(#jabber{type = 'muc:enter', username=UserName}, Room, Nick) -> + list_to_binary( + ["<presence id='", ts_msg_server:get_id(list), + "' from='", UserName, + "' to='", Room , "/", Nick, + "'> <x xmlns='http://jabber.org/protocol/muc#user'/> </presence>" + ]); + muc_get_message(#jabber{type = 'muc:initial', username=UserName}, Room, Nick) -> + list_to_binary( + ["<iq id='", ts_msg_server:get_id(list), + "' from='", UserName, + "' to='", Room, "/", Nick, + "' type='set'>", + "<query xmlns='http://jabber.org/protocol/muc'>", + "<x xmlns='jabber:x:data' type='submit'/>", + "</query></iq>" + ]); + muc_get_message(#jabber{type = 'muc:chat', size=Size, data=undefined, username=UserName}, Room, _Nick) -> + list_to_binary( + ["<message id='", ts_msg_server:get_id(list), + "' from='", UserName, + "' to='", Room, + "' type='groupchat'", + "> <body>", garbage(Size),"</body></message>" + ]); + muc_get_message(#jabber{type = 'muc:chat', data=Data, username=UserName}, Room, _Nick) -> + list_to_binary( + ["<message id='", ts_msg_server:get_id(list), + "' from='", UserName, + "' to='", Room, + "' type='groupchat'", + "> <body>", Data, "</body></message>" + ]); + muc_get_message(#jabber{type = 'muc:exit', username=UserName}, Room, Nick) -> + list_to_binary( + ["<presence id='", ts_msg_server:get_id(list), + "' from='", UserName, + "' to='", Room, "/", Nick, + "' type='unavailable'/>" + ]). + + + + %%---------------------------------------------------------------------- %% Func: get_message2/1 %%---------------------------------------------------------------------- get_message2(Jabber=#jabber{type = 'register'}) -> diff -crN tsung-1.2.1.old/src/tsung_controller/ts_config_jabber.erl tsung-1.2.1/src/tsung_controller/ts_config_jabber.erl *** tsung-1.2.1.old/src/tsung_controller/ts_config_jabber.erl 2006-09-20 19:52:53.000000000 +0900 --- tsung-1.2.1/src/tsung_controller/ts_config_jabber.erl 2007-05-16 18:35:38.000000000 +0900 *************** *** 62,67 **** --- 62,69 ---- Domain =ts_config:get_default(Tab, jabber_domain_name, jabber_domain), UserName=ts_config:get_default(Tab, jabber_username, jabber_username), Passwd =ts_config:get_default(Tab, jabber_passwd, jabber_passwd), + MucDomain =ts_config:get_default(Tab, jabber_muc_domain_name, jabber_muc_domain_name), + MucMember =ts_config:get_default(Tab, jabber_muc_room_per_member, jabber_muc_room_per_member), Msg=#ts_request{ack = Ack, dynvar_specs= DynVar, *************** *** 69,74 **** --- 71,78 ---- subst = SubstFlag, match = MatchRegExp, param = #jabber{domain = Domain, + muc_domain = MucDomain, + muc_member = MucMember, username = UserName, passwd = Passwd, data = Data, *************** *** 96,101 **** --- 100,111 ---- "domain" -> Val = ts_config:getAttr(string,Element#xmlElement.attributes, value,"erlang-projects.org"), ets:insert(Tab,{{jabber_domain_name,value}, Val}); + "muc:domain" -> + Val = ts_config:getAttr(string,Element#xmlElement.attributes, value,"conference"), + ets:insert(Tab,{{jabber_muc_domain_name,value}, Val}); + "muc:member" -> + N = ts_config:getAttr(integer,Element#xmlElement.attributes, value,10), + ets:insert(Tab,{{jabber_muc_room_per_member,value}, N}); "global_number" -> N = ts_config:getAttr(integer,Element#xmlElement.attributes, value, 100), ts_timer:config(N), diff -crN tsung-1.2.1.old/src/tsung_controller/ts_user_server.erl tsung-1.2.1/src/tsung_controller/ts_user_server.erl *** tsung-1.2.1.old/src/tsung_controller/ts_user_server.erl 2006-09-20 19:52:53.000000000 +0900 --- tsung-1.2.1/src/tsung_controller/ts_user_server.erl 2007-05-16 18:35:26.000000000 +0900 *************** *** 199,205 **** {reply, State#state.first_client, State}; handle_call({reset, NFin}, _From, _State) -> ! Offline = ets:new(offline,[set, private]), Online = ets:new(online, [set, private]), Connected = ets:new(connected, [set, private]), --- 199,206 ---- {reply, State#state.first_client, State}; handle_call({reset, NFin}, _From, _State) -> ! %%Offline = ets:new(offline,[set, private]), ! Offline = ets:new(offline,[ordered_set, private]), Online = ets:new(online, [set, private]), Connected = ets:new(connected, [set, private]),
問題点
- etsの変更
ランダムなIDが割り当てられてしまうのを避けるためにts_user_server.erlで生成しているofflineのユーザの集合をordered_setにしている。これが問題かどうかは追っていないけど。
- mucのベンチを正しく取れない?
ts_client.erlにあるhandle_next_requestやhandle_infoがそれぞれメッセージの生成と送信、受信を行っている。
erlang:displayで送受信を出力してみると一目瞭然なのだが、mucを使うと受信が爆発的に増える。これのおかげで、サーバに負荷をかけたいのに逆にアタックを受けるような状態に。。。
roomにN人いて、それぞれが1回メッセージを送ると(N-1)Nの送信が発生するからなぁ。
あ、一台でやるのがいけないのか!Erlangなんだし二台三台でやれば問題無いのかも。