为何基于RabbitMQ的STOMP比普通WebSocket传输速度更快?
问题:RabbitMQ+STOMP比纯WebSocket发送消息更快的原因分析
当用Python服务器向JavaScript客户端发送10万条300字符的消息时,RabbitMQ+STOMP方案耗时10-20秒,反而比纯WebSocket方案的至少22秒更快。原本以为STOMP是WebSocket叠加RabbitMQ的额外处理,理论上应该更慢,特此咨询该现象的原因,是否与asyncio有关?
一、RabbitMQ+STOMP方案代码
Python服务端
import stomp PORT = 61613 LOCALHOST = '0.0.0.0' conn = stomp.Connection11([(LOCALHOST, PORT)]) # conn.start() conn.connect('guest','guest') from random import choice from string import ascii_uppercase from time import time conn.send(body="start",destination='/queue/test') t = time() for i in range(100000): conn.send(body=''.join(choice(ascii_uppercase) for i in range(300)),destination='/queue/test') t = time() - t conn.send(body="end",destination='/queue/test') print() print(100000, "took ", t*1000, " ms") conn.disconnect()
JavaScript客户端
<script> var client = Stomp.client('ws://localhost:15674/ws'); var test = document.getElementById("test") client.debug = null; var date1 = null var date2 = null test.innerText = "READY... START!" var sub = function(d) { test.innerText = d.body if(d.body == "start") { date1 = new Date().valueOf() } if(d.body == "end") { date2 = new Date().valueOf() console.log(100000, "took ", date2 - date1, " ms") } } var on_connect = function(x) { id = client.subscribe("/queue/test", sub); console.log("connected") }; var on_error = function(e) { console.log('error', e); }; client.connect('guest', 'guest', on_connect, on_error, '/'); </script>
二、纯WebSocket方案代码
Python服务端
import asyncio import websockets import random import string async def echo(websocket): print("connected") await websocket.send("start") for i in range(100000): await websocket.send(''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(300))) await websocket.send("end") print("sent") async def main(): async with websockets.serve(echo, "localhost", 8765): await asyncio.Future()
JavaScript客户端
<body> <div id="test"> READY... SET... GO!! </div> <script> var time1 = null var time2 = null var socket = new WebSocket('ws://localhost:8765/ws'); socket.onmessage = function(e) { var server_message = e.data; if (server_message == "start") { time1 = new Date().valueOf() } if (server_message == "end") { time2 = new Date().valueOf() console.log("100000 messages took ", (time2 - time1) / 1000, "seconds") } document.getElementById("test").innerText = server_message } </script> </body>
原因分析
- asyncio的调度开销:纯WebSocket方案中,Python服务端在循环里逐个调用
await websocket.send(),每次await都会让出事件循环,等待发送回调完成,频繁的上下文切换会带来额外开销。而stomp库的conn.send()是同步阻塞发送,底层IO处理更高效,没有频繁的事件循环切换。 - RabbitMQ的批量转发优化:RabbitMQ作为消息中间件,会对消息进行缓存批量转发,减少了TCP层面的小包传输和握手开销,提升了整体吞吐量;纯WebSocket则是逐个发送消息,没有批量处理机制。
- 协议层面的效率差异:STOMP协议的帧结构虽然有额外头部,但RabbitMQ会对帧进行合并或高效序列化处理;纯WebSocket的
send()每次都是单独的消息帧,协议 overhead更高。 - 客户端处理差异:纯WebSocket客户端每条消息都会触发
onmessage并更新DOM,频繁的DOM操作会占用客户端资源,拖慢耗时统计;STOMP客户端可能对消息接收做了批量回调优化,减少了这类开销。
内容的提问来源于stack exchange,提问作者qwerty_99
相关产品推荐
相关产品推荐

