糟糕的序列化性能的可能解决方案

时间:2022-10-11 23:07:19

I recently did some performance testing and analysis of an ASP.NET application using out-of-process session state - this is necessary when using session state on a web farm so that state can be retrieved on any of the web servers, e.g. if subsequent HTTP requests arrive at a different server because the sessions aren't 'sticky' or the original server is down, etc.

我最近对ASP做了一些性能测试和分析。进程外网应用程序使用会话状态——这是必要的,当使用web农场上的会话状态,这样的状态可以在任何检索web服务器,比如如果随后的HTTP请求到不同的服务器,因为会议没有“粘性”或原始服务器,等等。

What surprised me was that when I ran the web servers at full load and profiled the CPU usage something like 99% of CPU time was spent serializing and deserializing session state. Subsequently we implemented a customised 'caching' state server; this always serializes state but also keeps state in-memory so that if you use sticky sessions the state doesn't have to be deserialized most of the time. This improved server throughput by a factor of 2; However, serialization still makes up 98% or more of CPU time.

令我惊讶的是,当我满负荷运行web服务器并分析CPU使用情况时,大约99%的CPU时间都花在了序列化和反序列化会话状态上。随后,我们实现了定制的“缓存”状态服务器;它总是序列化状态,但也保持状态在内存中,因此如果您使用粘性会话,状态在大多数情况下都不必反序列化。这将服务器吞吐量提高了2倍;然而,串行化仍然占据了98%或更多的CPU时间。

We obtained some further improvements in speed by 'trimming' unnecessary object references between objects in the session state prior to serialization - fixing up the references manually upon desrialization. This improved speed by another 10-20% or so. The reasoning here is that some of the performance loss is due to the built in serialization having to walk the graph of object pointers, which becomes a more complex task with more pointers.

在序列化之前,我们在会话状态中“修剪”对象之间不必要的对象引用,从而在速度上取得了一些进一步的改进——在反序列化时手动修复引用。这又提高了10-20%左右的速度。这里的理由是,一些性能损失是由于在序列化过程中必须遍历对象指针的图形,这将成为一个具有更多指针的更复杂的任务。

Continuining the investigation we wrote customized serialization routines for some of our classes rather than relying on .Net's built-in serialization. What we found was that performance was greatly improved, by a factor of about 50x. It seems the bulk of the CPU load is caused by built in .Net serialization, which in turn is slow due to reliance on using Reflection to walk the object pointers/graph and extract field data.

继续调查,我们为一些类编写了定制的序列化例程,而不是依赖于。net内置的序列化。我们发现,性能有了很大的提高,大约是50x。看起来大部分的CPU负载是由内建的。net序列化造成的,而由于依赖于使用反射来遍历对象指针/图并提取字段数据,这种序列化的速度比较慢。

It's very tempting to boost our performance by 50x, thus reducing the web server hardware requirements by a large factor (and power requirements by a lesser but still significant factor). The options currently are:

将我们的性能提高50x是非常诱人的,从而将web服务器硬件需求降低了一个很大的因素(而功耗要求降低了一个较小但仍然很重要的因素)。目前的选择:

1) Write customized serialization. This is an issue due to the complexity of the task and the maintenance overhead it generates, that is, any change to class state requires a change to the serialization/deserialization routines.

1)编写定制的序列化。这是一个问题,因为任务的复杂性及其产生的维护开销,也就是说,对类状态的任何更改都需要对序列化/反序列化例程进行更改。

2) Some third party solution. Perhaps some product that automatically generates state save/load code at build time, thus eliminating the need to use Reflection.

2)第三方解决方案。可能有些产品在构建时自动生成状态保存/加载代码,从而消除了使用反射的需要。

I'd be very interested to know if anyone knows of a third party solution, or has encountered this issue as I haven't found any mention of it from internet searches.

我很想知道是否有人知道第三方解决方案,或者遇到过这个问题,因为我没有在网络搜索中找到任何提及。

UPDATE: Some have suggested a sort of halfway solution between the default built-in serialization and pure customized serialization routines. The idea is that you implement customized serialization for the classes that affect performance the most by, e.g. overiding ISerializable. This is an interesting and promising approach; However I still think there's scope for a complete replacement for built-in serialization without having to write and maintain any custom code - this can't be done at runtime because Reflection is needed to query objects and access private data. But it is theoretically possible to post-process already built assemblies and inject new methods as an additional build step. Some profilers use this approach to inject profiling code into assemblies after they have been built by the C# compiler. Also I /think/ I read somewhere that the .Net framework supports injecting methods into classes - thus all the messing around with IL is potentially taken care of.

更新:有些人建议在默认的内置序列化和纯定制的序列化例程之间提供一种中间解决方案。其思想是为影响性能的类实现定制的序列化,例如覆盖ISerializable。这是一种有趣而有希望的方法;然而,我仍然认为,在不需要编写和维护任何自定义代码的情况下,可以完全替换内置的序列化——这在运行时是无法完成的,因为需要反射来查询对象和访问私有数据。但是从理论上讲,对已经构建的程序集进行后处理并将新方法作为额外的构建步骤注入是可能的。一些分析器使用这种方法在c#编译器构建完程序集之后将分析代码注入程序集。另外,我/认为/我在某处读到。net框架支持向类中注入方法——因此所有与IL有关的混乱都有可能得到解决。

5 个解决方案

#1


2  

Unfortunately I am only aware of option one and tbh that can start to get very painful to work on.

不幸的是,我只知道选项一和tbh会开始变得非常痛苦。

But it does only what you want so it's as quick as it gets.

但它只做你想做的事,所以它越快越好。

Good luck.

祝你好运。

#2


1  

One other option is to aggressively disable ViewState on all controls that are not touched on server side postbacks.

另一种选择是在服务器端回发中未触及的所有控件上主动禁用ViewState。

#3


1  

You can partially customize your serialization by implementing ISerializable. If you do this for the worst offenders, you won't increase maintenance as much but will still get some of the speedup.

通过实现isalizable,您可以部分地定制序列化。如果您为最坏的违规者这样做,您将不会增加那么多的维护,但仍然会获得一些加速。

#4


1  

There is a third-party solution:

有一个第三方解决方案:

Simon Hewitt's excellent open source library, see Optimizing Serialization in .NET - part 2.

Simon Hewitt的优秀的开源库,参见。net的优化序列化-第2部分。

I am using it in my application and got a similar speed-up as you, 20-40 times.

我正在我的应用程序中使用它,并得到了类似的加速,20-40次。

It eliminates the reflection that is the cause of the slowdown, but for lists it only supports a few native types. So for Genreric.List's of your own types there needs to be explicit code somewhere or the other. E.g. explicit loops or something smarter that automates this. In any case it is pretty simple and should not be hindrance for the huge benefits.

它消除了导致放缓的反射,但对于列表,它只支持少数本地类型。所以对于Genreric。你自己的类型列表需要有明确的代码。例如,显式循环或更智能的自动循环。无论如何,它非常简单,不应该成为巨大利益的阻碍。

#5


0  

We have encountered similar issues and have devised several ways of improving performance. We use some of these in our Persistore memory mapping product (currently beta). In our case we can simply access persisted data "in situ" because it is always in a memory mapped heap.

我们遇到了类似的问题,并设计了几种改进性能的方法。我们在我们的Persistore内存映射产品(当前beta)中使用了其中的一些。在我们的示例中,我们可以“就地”访问持久数据,因为它始终位于内存映射堆中。

However, one 'trick' is to define your session state data (if possible) as marshalable class/struct and 'serialize' that using .NET marshalling support, this can be very fast indeed but won't handle 'object' graphs.

但是,一个“技巧”是定义您的会话状态数据(如果可能的话),作为可编组的类/结构,并“序列化”使用. net编组支持,这确实非常快,但不会处理“对象”图。

We also support a special persistence based on Binary serialization, but we also extract and persist metadata so that managed code can set/get fields within a memory persisted datum at runtime without the need to deserialize the whole object, this is useful in some settings (e.g securities and stock price updates etc). Our latest beta supports serialization across a network, of LINQ anonymous types, this is a first so far as I am aware.

我们还支持基于二进制序列化的特殊持久性,但我们也提取和持久化元数据,以便托管代码在运行时能够在内存持久数据中设置/获取字段,而不需要反序列化整个对象,这在某些设置中是有用的(e)。g证券和股票价格更新等)。我们最新的beta版支持跨网络的序列化,即LINQ匿名类型,这是我所知的第一次。

Anyway, we'd be interested to have some new beta customers who are pushing ASP.NET and web performance issues, our latest beta is very impressive (but not ready until nex week).

无论如何,我们有兴趣有一些新的beta客户,他们正在推动ASP。NET和web性能方面的问题,我们最新的测试版非常令人印象深刻(但要到下个星期才准备好)。

If anyone is curious just contact us for the latest info on the product.

如果有人好奇,请联系我们的最新信息产品。

Hugh Moran

休·莫兰

PS: Website is out of date, the product goes far beyond what is described there.

PS:网站已经过时了,产品远远超出了上面所描述的。

#1


2  

Unfortunately I am only aware of option one and tbh that can start to get very painful to work on.

不幸的是,我只知道选项一和tbh会开始变得非常痛苦。

But it does only what you want so it's as quick as it gets.

但它只做你想做的事,所以它越快越好。

Good luck.

祝你好运。

#2


1  

One other option is to aggressively disable ViewState on all controls that are not touched on server side postbacks.

另一种选择是在服务器端回发中未触及的所有控件上主动禁用ViewState。

#3


1  

You can partially customize your serialization by implementing ISerializable. If you do this for the worst offenders, you won't increase maintenance as much but will still get some of the speedup.

通过实现isalizable,您可以部分地定制序列化。如果您为最坏的违规者这样做,您将不会增加那么多的维护,但仍然会获得一些加速。

#4


1  

There is a third-party solution:

有一个第三方解决方案:

Simon Hewitt's excellent open source library, see Optimizing Serialization in .NET - part 2.

Simon Hewitt的优秀的开源库,参见。net的优化序列化-第2部分。

I am using it in my application and got a similar speed-up as you, 20-40 times.

我正在我的应用程序中使用它,并得到了类似的加速,20-40次。

It eliminates the reflection that is the cause of the slowdown, but for lists it only supports a few native types. So for Genreric.List's of your own types there needs to be explicit code somewhere or the other. E.g. explicit loops or something smarter that automates this. In any case it is pretty simple and should not be hindrance for the huge benefits.

它消除了导致放缓的反射,但对于列表,它只支持少数本地类型。所以对于Genreric。你自己的类型列表需要有明确的代码。例如,显式循环或更智能的自动循环。无论如何,它非常简单,不应该成为巨大利益的阻碍。

#5


0  

We have encountered similar issues and have devised several ways of improving performance. We use some of these in our Persistore memory mapping product (currently beta). In our case we can simply access persisted data "in situ" because it is always in a memory mapped heap.

我们遇到了类似的问题,并设计了几种改进性能的方法。我们在我们的Persistore内存映射产品(当前beta)中使用了其中的一些。在我们的示例中,我们可以“就地”访问持久数据,因为它始终位于内存映射堆中。

However, one 'trick' is to define your session state data (if possible) as marshalable class/struct and 'serialize' that using .NET marshalling support, this can be very fast indeed but won't handle 'object' graphs.

但是,一个“技巧”是定义您的会话状态数据(如果可能的话),作为可编组的类/结构,并“序列化”使用. net编组支持,这确实非常快,但不会处理“对象”图。

We also support a special persistence based on Binary serialization, but we also extract and persist metadata so that managed code can set/get fields within a memory persisted datum at runtime without the need to deserialize the whole object, this is useful in some settings (e.g securities and stock price updates etc). Our latest beta supports serialization across a network, of LINQ anonymous types, this is a first so far as I am aware.

我们还支持基于二进制序列化的特殊持久性,但我们也提取和持久化元数据,以便托管代码在运行时能够在内存持久数据中设置/获取字段,而不需要反序列化整个对象,这在某些设置中是有用的(e)。g证券和股票价格更新等)。我们最新的beta版支持跨网络的序列化,即LINQ匿名类型,这是我所知的第一次。

Anyway, we'd be interested to have some new beta customers who are pushing ASP.NET and web performance issues, our latest beta is very impressive (but not ready until nex week).

无论如何,我们有兴趣有一些新的beta客户,他们正在推动ASP。NET和web性能方面的问题,我们最新的测试版非常令人印象深刻(但要到下个星期才准备好)。

If anyone is curious just contact us for the latest info on the product.

如果有人好奇,请联系我们的最新信息产品。

Hugh Moran

休·莫兰

PS: Website is out of date, the product goes far beyond what is described there.

PS:网站已经过时了,产品远远超出了上面所描述的。