On Wednesday 19, Christian Martinez wrote: > Maybe I'm missing something here, but are people asserting here that one > can't do a request reply MEP with various RPC technologies and exceed 1000 > 1KB messages a second?
With only 1 client and 1 concurrent request, then yes. The msg/sec throughput will be limited by latency in this case. Both client & server will be maxing out their CPUs, each will be sitting idle most of the time waiting for a reply from the other side. If you want more throughput, then you need to increase the number of concurrent requests sent by the clients. I did a quick comparison of zmq & (nginx + ab). Hardware: Client: Laptop 100Mbit connection 1 core 2.2Ghz AMD Server: desktop 1Gbit connection 8 core 3.6Ghz AMD Test parameters: requests: 400,000 max concurrent: 8 concurrent requests, 8 concurrent TCP sockets request/response size: 1k zmq: (using lua-zmq + LuaJIT, see attached Lua scripts) Client: 8 threads, so 8 concurrent requests, cpu maxed out. Server: 1 thread, low cpu usage throughput: 10,990 reqs/sec, about 90Mbits (both directions) bottleneck: client cpu maxed & client bandwidth. nginx: (1k post data including HTTP headers, 1k response data including HTTP headers) Client: ab (apache bench) keep-alive, 8 concurrent requests, cpu maxed out. Server: nginx keepalive_requests = 400,000, limited to 1 worker process. throughput: 9,055 reqs/sec, about 74Mbits (both directions) bottleneck: client cpu maxed. For reference using PUB/SUB the server can push 1k size messages out at 11,335 msg/sec, or about 92Mbits (in one direction server -> client). The bottleneck here is the 100Mbit client connection. -- Robert G. Jakabosky
-- Copyright (c) 2010 Aleksey Yeschenko <[email protected]> -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. if not arg[3] then print("usage: lua local_lat.lua <bind-to> <message-size> <roundtrip-count>") os.exit() end local bind_to = arg[1] local message_size = tonumber(arg[2]) local roundtrip_count = tonumber(arg[3]) local zmq = require"zmq" local ctx = zmq.init(1) local s = ctx:socket(zmq.REP) s:bind(bind_to) local msg = zmq.zmq_msg_t() local timer for i = 1, roundtrip_count do assert(s:recv_msg(msg)) if not timer then timer = zmq.stopwatch_start() end assert(msg:size() == message_size, "Invalid message size") assert(s:send_msg(msg)) end local elapsed = timer:stop() s:close() ctx:term() local latency = elapsed / roundtrip_count / 2 print(string.format("mean latency: %.3f [us]", latency)) local secs = elapsed / (1000 * 1000) print(string.format("elapsed = %f", secs)) print(string.format("msg/sec = %f", roundtrip_count / secs))
-- Copyright (c) 2011 Robert G. Jakabosky <[email protected]> -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. if #arg < 1 then print("usage: lua " .. arg[0] .. " [message-size] [roundtrip-count] [concurrent] [connect-to]") end local message_size = tonumber(arg[1] or 1) local roundtrip_count = tonumber(arg[2] or 100000) local concurrent = tonumber(arg[3]) or 1 local connect_to = arg[4] or 'tcp://localhost:5555' local zmq = require"zmq" local zthreads = require"zmq.threads" local child_code = [[ local connect_to, message_size, roundtrip_count = ... local zmq = require"zmq" local zthreads = require"zmq.threads" local ctx = zthreads.get_parent_ctx() local s = ctx:socket(zmq.REQ) s:connect(connect_to) local data = ("0"):rep(message_size) local msg = zmq.zmq_msg_t.init_size(message_size) local timer = zmq.stopwatch_start() for i = 1, roundtrip_count do assert(s:send_msg(msg)) assert(s:recv_msg(msg)) assert(msg:size() == message_size, "Invalid message size") end local elapsed = timer:stop() s:close() local latency = elapsed / roundtrip_count / 2 print(string.format("message size: %i [B]", message_size)) print(string.format("roundtrip count: %i", roundtrip_count)) print(string.format("mean latency: %.3f [us]", latency)) local secs = elapsed / (1000 * 1000) print(string.format("elapsed = %f", secs)) print(string.format("msg/sec = %f", roundtrip_count / secs)) ]] local ctx = zmq.init(1) local child_threads = {} local per_count = roundtrip_count / concurrent for i=1,concurrent do local child = zthreads.runstring(ctx, child_code, connect_to, message_size, per_count) child:start() child_threads[i] = child end for i=1,concurrent do child_threads[i]:join() end ctx:term()
_______________________________________________ zeromq-dev mailing list [email protected] http://lists.zeromq.org/mailman/listinfo/zeromq-dev
