异常-检查元数据时超时
本文关键字:超时 元数据 检查 异常 | 更新日期: 2023-09-27 18:08:26
我有时在尝试使用protobuf.net反序列化对象时收到以下异常。我很惊讶,因为我从来没有超过一个线程同时对同一个对象进行反序列化,而且protobuf.net源代码似乎没有使用任何静态对象进行反序列化。例外确实建议一个解决方案,但我不确定如何实现,所以欢迎一个例子。
Base Exception Type:
System.TimeoutException: Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection
at ProtoBuf.Meta.RuntimeTypeModel.TakeLock(Boolean& lockTaken)
at ProtoBuf.Meta.RuntimeTypeModel.FindOrAddAuto(Type type, Boolean demand, Boolean addWithContractOnly, Boolean addEvenIfAutoDisabled)
at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey)
Inner Exception Type:
System.TimeoutException: Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection
at ProtoBuf.Meta.RuntimeTypeModel.TakeLock(Boolean& lockTaken)
at ProtoBuf.Meta.RuntimeTypeModel.FindOrAddAuto(Type type, Boolean demand, Boolean addWithContractOnly, Boolean addEvenIfAutoDisabled)
at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey)
Stack Trace:
at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey)
at ProtoBuf.Meta.TypeModel.GetKey(Type& type)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type)
问候,Marc
我这样定义我的可序列化对象:[ProtoContract]
public class Job
{
[ProtoMember(1)]
public long JobId { get; private set; }
}
我很难在每个可序列化对象上轻松调用PrepareSerialiser,因为我在不同的命名空间中有许多对象。然而,想想看,如果protobuf被要求同时反序列化两个相同类型的对象,一个它以前从未见过的对象,会发生什么?
老问题,但如果有人碰巧得到这个错误,请检查您正在使用的DLL版本。此异常在可移植版本中出现的几率非常高。
有几个pr与这个问题有关的便携版本是https://github.com/mgravell/protobuf-net/pull/98和https://github.com/mgravell/protobuf-net/pull/114。
RuntimeTypeModel。Default(默认模型)是静态的,并支持静态Serializer类(请注意没有任何静态状态的注释)。尽管由于偏执而添加了此检查,但我从未看到此错误被引发。我非常希望能看到一个能再现这一点的例子。你确定你不是在穿线吗?如果不是为了线程,我只能想:类型模型真的真的大吗?
事实上,即使在启动时有许多线程猛烈地攻击它(例如在这里的stackoverflow上),它也表现得很好。正如错误消息提示的那样,您可以尝试调用Serializer。在应用程序启动时PrepareSerializer,它将预先初始化一切,避免任何线程问题。但嘿!至少它没有陷入僵局!
但是,这里的奇怪之处在于仍然不应该可能发生死锁—它故意使用粗锁来避免它取锁的顺序带来的问题。我真的很想看到一个例子。为我准备序列化器使用
Serializer.PrepareSerializer<Type>();
并没有真正帮助我。
对我来说,解决方案(又名变通方案)是在启动时序列化类型,这在应用程序启动时造成了麻烦:
MessageSerialization.Serialize(new Type());
MessageSerialization的地方。Serialize是使用protobuf Serializer的序列化方法。序列化(流,o)
我在我的服务器上得到同样的确切错误。虽然我不确定是什么导致错误。几天前,当我们的服务器处于我们所经历过的最高负载下时,它发生了两次,相隔几个小时。在运行8台服务器时,所有服务器上的CPU在几秒钟内从70%上升到100%,但时间略有不同。例如,每个服务器可能在第一个峰值之后1-5分钟开始这个峰值。
以前从未见过这种情况,我已经在生产中使用了几个月的代码。我还没能重现它,我不知道这个错误是由于服务器的CPU达到100%而抛出的,还是这就是导致服务器尖峰的原因。停止与服务器的所有连接并让cpu降回0可以修复这个问题。不需要重新启动iis。
当IIS启动时,我为每种类型运行一次以下代码:
var type = this.GetType();
RuntimeTypeModel.Default.Add(type, true);
Int32 i = 1;
foreach(PropertyInfo info in type.GetProperties())
{
if(info.CanWrite)
{
RuntimeTypeModel.Default[type].AddField(i++, info.Name);
}
}