websocket传输中对二进制数据支持

https://blueprints.launchpad.net/zaqar/+spec/websocket-binary-support

实现websocket传输中对二进制通信的支持,这将减少Zaqar及其客户端之间的网络流量,并提高性能。

问题描述

目前websocket传输仅使用打包在JSON格式中的文本消息与客户端交换数据。

尝试将二进制数据发送到Zaqar的websocket传输会导致Zaqar返回“请求错误”(HTTP错误400)响应。

但websocket协议实际上允许通过二进制消息进行通信。打包(序列化)成二进制格式的数据可以更小,并且打包/解包所需CPU时间也可能更少。

通过使用二进制消息进行通信,可以减少Zaqar及其客户端之间的网络流量,并提高Zaqar的性能。如果客户端不是用JavaScript编写的,也可以提高客户端性能。

提议的变更

我们可以使用MsgPack技术进行序列化/反序列化,该技术已经在 persistent-transport 规范中提出并获得批准。

Zaqar接收消息的反序列化

protocol.py#L55 中所示,Zaqar已经可以区分二进制和文本消息。

因此,我们将使Zaqar尝试使用‘msgpack’库将每个接收到的二进制消息反序列化为python对象,就像Zaqar当前使用‘json’库反序列化JSON消息一样。成功反序列化后,可以像往常一样处理该消息。

Zaqar响应和订阅消息的序列化

Zaqar的响应将以与传入请求相同的格式序列化。

Zaqar的订阅消息将根据订阅创建请求的格式以二进制或文本格式序列化。

让我们看一下客户端在连接打开且订阅仍然存在时突然更改其消息格式的情况。当客户端无法反序列化来自旧订阅的消息时,可能会出现问题,因为它通过更改某个布尔变量(开关)更改了格式。但这种情况几乎不可能发生,即使发生,问题也可以解决。

  1. 很难想象一种情况,客户端更改其序列化格式可能有用。这样的客户端可能永远不会存在。

  2. 即使将来存在这样的客户端,客户端开发人员也会通过在“on message”方法内部添加检查每个传入消息格式并相应地反序列化消息的代码来处理它。Zaqar正是这样做的,例如。所有websocket实现都提供了一种方便的方法来确定每个特定消息的格式。

  3. 即使客户端开发人员没有处理这个潜在问题(例如,他没有经验),并且在旧订阅仍然存在时,客户端只是期望所有传入消息都采用新格式,客户端将在第一个来自该订阅的传入消息上崩溃,并且问题不会被忽视。

Websocket html客户端示例升级

websocket html 客户端示例将被更改,使其也能够通过二进制消息与Zaqar通信。

缺点

JavaScript上的web客户端性能

看起来MsgPack序列化/反序列化在JavaScript中比JSON慢。好吧,这并不奇怪,因为JSON缩写扩展为“JavaScript对象表示法”。这对Zaqar web客户端来说是一个缺点,因为它降低了它们的性能。

如何解决这个缺点

  1. 服务器只有一个,客户端有很多。服务器处理的消息比每个特定客户端多得多。因此,在许多情况下,使用二进制序列化来提高服务器性能,牺牲JavaScript客户端的性能是合理的。

  2. JavaScript客户端上的额外延迟略微弥补了服务器更快响应速度。

  3. JavaScript客户端始终可以使用旧的文本格式与服务器通信,而其他客户端可以同时使用二进制格式与同一服务器通信。

备选方案

这些替代方案完全排除了客户端在连接打开且旧订阅仍然存在时突然更改其消息格式的几乎不可能的情况,以及通过客户端的布尔变量(开关)管理客户端的传入消息的反序列化格式的情况。

Zaqar响应和订阅消息序列化的替代方案

可选参数方法

Zaqar的响应将以与传入请求相同的格式序列化。

Zaqar的订阅消息将根据订阅创建请求消息体中传递的新可选参数以二进制或文本格式序列化。我们可以将此参数添加到websocket API,将其命名为 accept,允许它只有两个可能的值:jsonmsgpack,如果未传递 accept 参数,则将 json 值作为默认值。通过使 accept 参数可选,我们实现了向后兼容性。

实施前订阅请求消息

{
    'action': 'subscription_create',
    'headers': {'Client-ID': 31209ff3-ba03-4cec-b4ca-655f4899f8aa,
                'X-Project-ID': superproject},
    'body': {'queue_name': 'superqueue', 'ttl': 3600}
}

实施后的订阅请求消息可以与之前相同,也可以显式传递 accept 参数

{
    'action': 'subscription_create',
    'headers': {'Client-ID': 31209ff3-ba03-4cec-b4ca-655f4899f8aa,
                'X-Project-ID': superproject},
    'body': {'queue_name': 'superqueue', 'ttl': 3600, 'accept': 'json'}
}
第一条消息方法

Zaqar的响应和订阅消息将根据客户端自连接以来成功解析的第一个消息的格式以二进制或文本格式序列化。

一旦Zaqar和客户端之间的通信格式通过这种方式建立,客户端将无法更改它,除非客户端重新连接到Zaqar并以其他格式发送第一条消息。

Zaqar配置方法

Zaqar的响应和订阅消息将根据Zaqar服务器配置中的布尔变量以二进制或文本格式序列化。

实现

负责人

主要负责人

ubershy

里程碑

完成目标里程碑

Mitaka-2

工作项

依赖项

注意

本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode