使用C#将非常大的项目列表序列化到Azure Blob存储中

Iva*_*van 5 c# serialization azure protocol-buffers capnproto

我有大量的对象,以后需要存储和检索。该列表将始终用作一个单位,并且不会单独检索列表项。该列表包含约7000个项目,总计约1GB,但可以轻松升级到十倍甚至更多。

我们一直在使用BinaryFormatter.Serialize()序列化(System.Runtime.Serialization.Formatters.Binary.BinaryFormatter)。然后,此字符串作为Blob上传到Azure Blob存储。我们发现它通常是快速且高效的,但是由于我们正在以更大的文件大小对其进行测试(并抛出)而变得不足OutOfMemoryException。据我了解,尽管我使用的是流,但我的问题是该BinaryFormatter.Serialize()方法必须先将所有内容序列化到内存,然后才能上传Blob,从而导致异常。

二进制序列化程序如下所示:

public void Upload(object value, string blobName, bool replaceExisting)
{
    CloudBlockBlob blockBlob = BlobContainer.GetBlockBlobReference(blobName);
    var formatter = new BinaryFormatter()
    {
        AssemblyFormat = FormatterAssemblyStyle.Simple,
        FilterLevel = TypeFilterLevel.Low,
        TypeFormat = FormatterTypeStyle.TypesAlways
    };

    using (var stream = blockBlob.OpenWrite())
    {
        formatter.Serialize(stream, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

OutOfMemoryException发生在该formatter.Serialize(stream, value)行上。

因此,我尝试使用其他协议,即协议缓冲区。我尝试使用Nuget包protobuf-net和Google.Protobuf中的两种实现,但是序列化非常慢(大约30分钟),而且据我所读,Protobuf并未针对序列化大于1MB的数据进行优化。因此,我回到了绘图板上,遇到了Cap'n Proto,Cap'n Proto承诺通过使用内存映射解决我的速度问题。我正在尝试使用@ marc-gravell的C#绑定,但是在实现序列化程序时遇到了一些困难,因为该项目还没有详尽的文档。而且,我不确定100%的Cap'n Proto是协议的正确选择-但我正努力在网上找到其他建议。

如何以合理的快速方式将非常大的项目集合序列化到Blob存储,而不会遇到内存问题?

Jam*_*all 1

也许您应该切换到 JSON?

使用 JSON 序列化器,您可以流式传输到文件或从文件中传输,并分段序列化/反序列化(在读取文件时)。

您的对象能很好地映射到 JSON 吗?

这就是我用来获取 NetworkStream 并将其放入 Json 对象中的方法。

    private static async Task<JObject> ProcessJsonResponse(HttpResponseMessage response)
    {
        // Open the stream the stream from the network
        using (var s = await ProcessResponseStream(response).ConfigureAwait(false))
        {
            using (var sr = new StreamReader(s))
            {
                using (var reader = new JsonTextReader(sr))
                {
                    var serializer = new JsonSerializer {DateParseHandling = DateParseHandling.None};

                    return serializer.Deserialize<JObject>(reader);
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

此外,您可以对流进行 GZip 以减少文件传输时间。我们直接流式传输到 GZipped JSON,然后再返回。

编辑,虽然这是反序列化,但相同的方法应该适用于序列化