首页 > 解决方案 > 使用 protobuf 流式传输压缩的 IDataReader

问题描述

我们需要大大减少后端服务在将数据拉取和推送到 sql 时使用的带宽。SqlClient 使用的 TDS Stream 相当臃肿。多年来,人们在从 sql 中提取时要求提供压缩选项,但微软没有添加它。

我想看看是否有人对处理此问题的最佳方法有任何想法。这是我迄今为止尝试过的:

  1. 我修改了https://github.com/MindFlavor/TDSBridge以在套接字层添加压缩和解压缩。因为有效载荷是 SSL 加密的,所以没有太大区别。

  2. 接下来我将 IDataReader 带到 Protobuf 库中找到:https ://github.com/dotarj/protobuf-net-data和 TCP 框架在https://github.com/jchristn/WatsonTcp中找到,以尝试创建客户端服务器代理通过将 IDataReader 转换为 protobuf,然后压缩此流,并在另一端执行相反的操作,可以通过网络传输 IDataReader。

我得到了一个可以在这里工作的概念证明,与普通 TDS 流相比,网络上的原始字节实际上减少了 84% 到 98%。缺点是 WatsonTcp 希望您在分配流时传入内容长度。但是在您创建整个 protobuf 流之前,无法知道这一点。我们有时会一口气转移数百个演出,所以这是行不通的。

我没有看到 protobuf-net-data 如何通过 grpc 流式传输,即使可以,我也担心 IAsyncEnumerable 中记录的粒度性质可能会减慢大型传输。

毫无疑问,我可以坐下来通过 TCP 流实现编写一个完全自定义的原始套接字压缩 protobuf,客户端的表面积接近 SqlCommand,我只知道这很难做到。

任何节省时间的想法?如果不是,也许我会用它制作一个开源项目。

标签: c#tcpcompressionprotobuf-netidatareader

解决方案


您可以使用此技术让 SQL Server 将结果格式化为 gzip 压缩的 csv(将组中的行数调整 - 1000 是 gzip 开销减少的地方):

with csv as (
    select n = row_number() over (order by (select null)),
        line = convert(nvarchar(max), concat(
            message_id, ',', language_id, ',', severity, ',',
            is_event_logged, ',', '"' + replace([text], '"', '""') + '"'))
    from sys.messages)

select compress(string_agg(line, char(13)) within group (order by n))
from csv group by n / 1000

..如果您在 SQL Server 上遇到实际的出口瓶颈,这应该会有所帮助。将其实现为重写查询然后将结果转换回客户端期望的 TDSBridge 会很有趣。


推荐阅读