c# - 使用 protobuf 流式传输压缩的 IDataReader
问题描述
我们需要大大减少后端服务在将数据拉取和推送到 sql 时使用的带宽。SqlClient 使用的 TDS Stream 相当臃肿。多年来,人们在从 sql 中提取时要求提供压缩选项,但微软没有添加它。
我想看看是否有人对处理此问题的最佳方法有任何想法。这是我迄今为止尝试过的:
我修改了https://github.com/MindFlavor/TDSBridge以在套接字层添加压缩和解压缩。因为有效载荷是 SSL 加密的,所以没有太大区别。
接下来我将 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,我只知道这很难做到。
任何节省时间的想法?如果不是,也许我会用它制作一个开源项目。
解决方案
您可以使用此技术让 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 会很有趣。
推荐阅读
- kotlin - Kotlin arrow.kt - Option.getOrElse 接受 T 以外的其他类型
- google-apps-script - CalendarApp.getCalendarById(email) 为我组织中的某些人返回 null
- css - 媒体查询冲突
- c - 与 0 进行比较与与某个值进行比较是否更快?
- notifications - 使用 GetStream API,如果通知被分组,我会得到不正确的未见和未读计数
- python-3.x - 在 Flask 响应上下文中并行执行?
- python - 使用 Python 和 BeautifulSoup,有没有办法在页面的特定部分中找到“强”标签?
- c# - 处理 FieldOffsets C# C++
- html - 无法为列表元素找到正确的辅助功能角色
- javascript - 获取 yargs 的“无效值:”消息