负载平衡系统中的 Protobuf-net 动态类型

Posted

技术标签:

【中文标题】负载平衡系统中的 Protobuf-net 动态类型【英文标题】:Protobuf-net dynamic types in a load-balanced system 【发布时间】:2018-08-09 19:10:21 【问题描述】:

我在一个应用程序中使用 protobuf-net,该应用程序对来自(出于所有意图和目的)第 3 方 dll 的对象进行大量二进制序列化。结果,我不能在合约本身上使用 [Proto-] 属性,而是使用 RuntimeTypeModel 在运行时准备序列化程序,因为它遇到新类型。示例序列化程序包装器:

public static class ProtobufSerializer

    public static byte[] Serialize<T>(T obj)
    
         PrepareSerializer(typeof(T));
         ProtoBuf.Serialize(memoryStream, obj); 
    

    public static T Deserialize<T>(byte[] bytes)
    
         PrepareSerializer(typeof(T));
         ProtoBuf.Serialize(memoryStream, obj); 
    

我们可以安全地假设PrepareSerializer 能够准备RuntimeTypeModel 来序列化任何给定的类型。我在对象的反序列化方面遇到了一些问题,我必须利用DynamicType=true。例如,给定以下接口:

public interface IFoo

    string Name get;

以及实现:

public class Foo : IFoo

    public string Name get;set;
    public Bar Bar get;set;

    [OnDeserializing]
    public void OnDeserializing(Type t)
    
        PrepareSerializer(typeof(Foo));
    


public class Bar

    public int Baz get;set;

PrepareSerializer 方法本质上会使用代理并生成一个大致相当于:

// registered surrogate for IFoo
[ProtoContract]
public class IFooSurrogate

    [ProtoMember(1, DynamicType=true)]
    public object Value

    [OnSerializing]
    public void OnSerializing(Type t)
    
        PrepareSerializer(this.Value.GetType());
    

其中Value 由隐式转换器设置为等于IFoo 的实例。这在序列化期间工作正常(触发事件并让我有机会为特定接口实现类型准备序列化程序)。它在非分布式系统中也可以正常工作,在该系统中,我必须在尝试反序列化该类型之前运行一个序列化方法。但是,在分布式系统中的反序列化过程中,当前节点以前从未见过 Foo,ProtoBuf.Serializer 在运行 Foo.OnDeserializing 事件之前会抛出 InvalidOperationException 抱怨 Bar 类型缺少序列化程序(给我一个有机会告诉它如何反序列化 Bar)。

有没有办法附加一个钩子来确保我的代码有机会在 protobuf-net 抱怨缺少序列化程序之前了解“Foo”?

【问题讨论】:

【参考方案1】:

我还没有完全尝试过这种情况,但是:为了允许一些灵活性,所有Type 存储和再水化都通过TypeModel.DynamicTypeFormatting 事件进行;所以,理论上你可以把这个事件挂在RuntimeTypeModel.Default上,比如:

RuntimeTypeModel.DynamicTypeFormatting += (sender, args) => 
    if (args.FormattedName != null)  // meaning: rehydrating
        lock(SomeSyncLock) 
            if(NotYetKnown(args.FormattedName))
                Prepare(args.FormattedName);
        
    
;

此 API 的意图是让您控制类型的解析方式,但是……我想它也适用于这个?


但是,我可以在第一次看到新的Type 时更刻意地针对事件的想法,本质上替换/补充“应用默认行为”代码。不过,我认为它今天不存在。

【讨论】:

这很好用。我之前正在查看此事件以优化动态类型的大小,但出于此目的没有考虑它。谢谢! @MarcGravell 如果我们将此 DynamicTypeFormatting 事件的处理程序添加到 RuntimeTypeModel.Default - 是否会为绝对所有序列化对象调用它,或者是否有其他 RuntimeTypeModel 实例需要挂钩?另外,您能否确认“所有类型的存储和再水化都通过”这一点,而不仅仅是动态类型? 我们已经实现了上述操作以从序列化流中省略程序集版本,但看起来某些类型正在使用默认名称编写,所以我想知道这是否可能会被跳过。跨度> @zvolkov 如果你有一个奇怪的例子,我很乐意在 github 上看到它

以上是关于负载平衡系统中的 Protobuf-net 动态类型的主要内容,如果未能解决你的问题,请参考以下文章

负载均衡

Windows Server 2008 R2 负载平衡入门篇

国家数字交换系统工程技术研究中心张帆等 | MDLB:一种基于强化学习的元数据动态负载均衡机制

负载平衡环境中的 .Net Core 托管服务

通过动态 url 参数负载平衡 websocket 连接

protobuf-net 中的动态 protobuf 消息