Protobuf.net 异常 - 检查元数据时超时
当我尝试使用 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)
问候, 马克
编辑添加:我这样定义我的可序列化对象:
[ProtoContract]
public class Job
{
[ProtoMember(1)]
public long JobId { get; private set; }
}
对我来说,在每个可序列化对象上轻松调用PrepareSerialiser是很困难的,因为我有许多可序列化对象位于不同的命名空间中。然而想一想,如果 protobuf 被要求在同一时间反序列化两个相同类型的对象(这是它以前从未见过的类型),会发生什么?
I am sometimes receiving the following exception when attempting to deserialise an object using protobuf.net. I'm surprised as I never have more than a single thread deserialising the same object at the same time and the protobuf.net source does not seem to use any static objects for deserialising. The exception does suggest a solution but I am unsure as to how to implement so would welcome an example.
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)
Regards,
Marc
edit to add: I define my serialisable objects thus:
[ProtoContract]
public class Job
{
[ProtoMember(1)]
public long JobId { get; private set; }
}
It would be difficult for me to easily call PrepareSerialiser on each one of my serialisable objects as I have many in different namespaces. However thinking about it what happens if protobuf is asked to deserialise two objects of the same type, a type it has not seen before, at exactly the same time?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
老问题,但如果有人碰巧遇到此错误,请检查您正在使用的 DLL 版本。此异常出现在便携式版本中的可能性非常高。
有几个与便携式版本的问题相关的 PR,它们是 https://github .com/mgravell/protobuf-net/pull/98 和 https://github.com/mgravell/protobuf-net/pull/114。
Old question, but if somebody happens to get this error, please check the DLL version you are using. Chances for this exception to show up in portable version are very high.
There are a couple of PRs related to this issue with the Portable version that are https://github.com/mgravell/protobuf-net/pull/98 and https://github.com/mgravell/protobuf-net/pull/114.
RuntimeTypeModel.Default(默认模型)是静态的,并且支撑静态 Serializer 类(重新注释没有任何静态状态)。尽管由于偏执而添加了此检查,但我从未看到出现此错误。我非常希望看到一个能够重现这一点的例子。你确定你不是线程?如果不是为了线程,我只能想:类型模型真的真的大吗?
事实上,即使有许多线程在启动时积极地攻击它(即在 stackoverflow 上),它也表现良好。正如错误消息提示的那样,您可以尝试在应用程序启动期间调用 Serializer.PrepareSerializer,这将预先初始化所有内容,避免任何线程问题。
但是嘿!至少没有陷入僵局!
不过,这里奇怪的是,它仍然不应该可能死锁 - 它故意使用粗略锁来避免出现问题锁定的顺序。再说一遍 - 我真的很想看看样品。
RuntimeTypeModel.Default (the default model) is static, and underpins the static Serializer class (re the comment that there wasn't any static state). Despite adding this check due to paranoia, I have never seen this error raised. I would absolutely love to see an example that will repro this. Are you sure you aren't threading? If not for threading, I can only wonder: is the type-model really really big?
Indeed, even with many threads hitting it aggressively at startup (i.e. here on stackoverflow) it is well behaved. As the error message hints, you might try calling Serializer.PrepareSerializer during app-startup, which will pre-initialize everything, avoiding any threading concerns.
But hey! At least it didn't deadlock!
The odd thing here, though, is that it still shouldn't be possible to deadlock - it deliberately uses a coarse lock to avoid issues from the order it takes lock. Again - I'd really love to see a sample.
准备序列化器
对于我来说,使用
Serializer.PrepareSerializer();
并没有真正帮助我。
对我来说,解决方案(也称为解决方法)是在启动时序列化类型,这会在应用程序启动时造成问题:
MessageSerialization.Serialize(new Type());
其中 MessageSerialization.Serialize 是使用 protobuf Serializer 的序列化方法。序列化(流,o)
For me preparing Serializers using
Serializer.PrepareSerializer<Type>();
didn't really helped me.
For me, solution (aka workaround) was to serialize type at startup which was causing trouble at app startup :
MessageSerialization.Serialize(new Type());
Where MessageSerialization.Serialize is serialization method using protobuf Serializer.Serialize(stream, o)
我的服务器上也遇到同样的错误。虽然我不确定是什么导致了错误。几天前,当我们的服务器处于我们经历过的最高负载时,这种情况发生了两次,相隔几个小时。运行 8 台服务器时,所有服务器的 CPU 在几秒钟内就从 70% 升至 100%,但时间略有不同。例如,每个服务器可能在第一个峰值后 1-5 分钟启动此峰值。
以前从未见过这种情况发生,我已经将这段代码投入生产几个月了。仍然无法重现它,我无法判断抛出错误是否是因为服务器的 CPU 利用率为 100%,或者这是否是导致服务器峰值的原因。停止与服务器的所有连接并让 cpu 降回 0 解决了该问题。无需重新启动 iis。
当 IIS 启动时,我为每种类型运行一次以下代码。
I'm getting this same exact error on my servers. Though I'm not sure what is causing the error. A few days ago it happened twice a few hours apart while our servers were under the highest load we've experienced. Running 8 servers the CPU across all of them went from 70% to 100% in seconds but a slightly different times. For example each of the servers might have started this spike 1-5 minutes after the first.
Never seen this happen before and i've had this code in production for a few months. Still haven't been able to reproduce it and I can't tell if the error is thrown because the server was at 100% CPU or if this is what caused the server to spike. Stopping all the connections to the servers and letting the cpu drop back to 0 fixed the issue. No iis restart was required.
When IIS starts i run the following code once for each type.