负载平衡系统中的 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 负载平衡入门篇