【发布时间】:2010-12-02 01:03:20
【问题描述】:
我最近使用进程外会话状态对 ASP.NET 应用程序进行了一些性能测试和分析 - 在网络场上使用会话状态时这是必要的,以便可以在任何网络服务器上检索状态,例如如果后续 HTTP 请求由于会话不“粘”或原始服务器已关闭等而到达不同的服务器。
令我惊讶的是,当我以满负荷运行 Web 服务器并分析 CPU 使用率时,大约 99% 的 CPU 时间都用于序列化和反序列化会话状态。随后我们实现了一个定制的“缓存”状态服务器;这总是序列化状态,但也将状态保留在内存中,因此如果您使用粘性会话,则大多数时间都不必反序列化状态。这将服务器吞吐量提高了 2 倍;但是,序列化仍占 CPU 时间的 98% 或更多。
通过在序列化之前“修剪”会话状态中的对象之间不必要的对象引用,我们进一步提高了速度 - 在反序列化时手动修复引用。这将速度提高了 10-20% 左右。这里的原因是,一些性能损失是由于内置的序列化必须遍历对象指针的图,这变成了具有更多指针的更复杂的任务。
继续调查,我们为我们的一些类编写了定制的序列化例程,而不是依赖 .Net 的内置序列化。我们发现,性能大大提高了,提高了大约 50 倍。似乎大部分 CPU 负载是由内置的 .Net 序列化引起的,而由于依赖于使用反射来遍历对象指针/图形并提取字段数据,这反过来又很慢。
将我们的性能提高 50 倍非常诱人,从而大大降低了 Web 服务器硬件要求(功率要求降低了一个较小但仍然很重要的因素)。目前的选项是:
1) 编写自定义序列化。这是由于任务的复杂性及其产生的维护开销造成的问题,也就是说,对类状态的任何更改都需要对序列化/反序列化例程进行更改。
2) 一些第三方解决方案。也许某些产品会在构建时自动生成状态保存/加载代码,从而无需使用反射。
我很想知道是否有人知道第三方解决方案,或者遇到过这个问题,因为我在互联网搜索中没有找到任何提及。
更新: 有些人提出了一种介于默认内置序列化和纯定制序列化例程之间的中间解决方案。这个想法是您为影响性能最大的类实现自定义序列化,例如覆盖 ISerializable。这是一种有趣且有前途的方法;但是,我仍然认为可以完全替代内置序列化,而无需编写和维护任何自定义代码——这不能在运行时完成,因为查询对象和访问私有数据需要反射。但理论上可以对已构建的程序集进行后处理并注入新方法作为额外的构建步骤。一些分析器使用这种方法在由 C# 编译器构建后将分析代码注入到程序集中。此外,我 /think/ 我在某处读到 .Net 框架支持将方法注入类 - 因此可能会处理所有与 IL 相关的问题。
【问题讨论】:
-
很确定您所说的注入方法是使用部分类。我认为原则是如果同一个命名空间中的两个类具有相同的名称并且一个被标记为部分。生成一个 dll,并结合两个类的方法和属性。
标签: .net asp.net performance serialization reflection