10

我们正试图尽可能减轻我们的页面负载。由于 ViewState 有时会膨胀到 100k 的页面,我很想完全消除它。

我很想听听其他人用来将 ViewState 移动到自定义提供程序的一些技术。

也就是说,有几点需要注意:

  • 我们平均每小时为 200 万独立访客提供服务。
  • 正因为如此,数据库读取一直是一个严重的性能问题,所以我不想将 ViewState 存储在数据库中。
  • 我们还支持负载平衡器,因此任何解决方案都必须与用户在每次回发时从机器跳到机器一起工作。

想法?

4

15 回答 15

5

How do you handle Session State? There is a built-in "store the viewstate in the session state" provider. If you are storing the session state in some fast, out of proc system, that might be the best option for the viewstate.

edit: to do this add the following code to the your Page classes / global page base class

    protected override PageStatePersister PageStatePersister {
        get { return new SessionPageStatePersister(this); }
    }

Also... this is by no means a perfect (or even good) solution to a large viewstate. As always, minimize the size of the viewstate as much as possible. However, the SessionPageStatePersister is relatively intelligent and avoids storing an unbounded number of viewstates per session as well as avoids storing only a single viewstate per session.

于 2008-09-07T04:14:27.207 回答
2

我已经测试了许多方法来从页面以及所有黑客和一些软件之间消除视图状态的负载,唯一真正可扩展的是StrangeLoops As10000 设备。透明,无需更改底层应用程序。

于 2008-09-07T03:07:41.283 回答
2

如前所述,我过去曾使用数据库来存储 ViewState。尽管这对我们有用,但我们每小时的唯一身份访问者并不接近 200 万。

我认为硬件解决方案绝对是要走的路,无论是使用StrangeLoop产品还是其他产品。

于 2008-09-07T03:23:49.513 回答
2

以下对我来说非常有效:

string vsid;

protected override object LoadPageStateFromPersistenceMedium()
{
  Pair vs = base.LoadPageStateFromPersistenceMedium() as Pair;
  vsid = vs.First as string;
  object result = Session[vsid];
  Session.Remove(vsid);
  return result;
}

protected override void SavePageStateToPersistenceMedium(object state)
{
  if (vsid == null)
  {
    vsid = Guid.NewGuid().ToString();
  }
  Session[vsid] = state;
  base.SavePageStateToPersistenceMedium(new Pair(vsid, null));
}
于 2008-09-17T12:03:10.070 回答
1

您始终可以压缩 ViewState,这样您就可以获得 ViewState 的好处,而不会产生太多的臃肿:

public partial class _Default : System.Web.UI.Page {

  protected override object LoadPageStateFromPersistenceMedium() {
    string viewState = Request.Form["__VSTATE"];
    byte[] bytes = Convert.FromBase64String(viewState);
    bytes = Compressor.Decompress(bytes);
    LosFormatter formatter = new LosFormatter();
    return formatter.Deserialize(Convert.ToBase64String(bytes));
  }

  protected override void SavePageStateToPersistenceMedium(object viewState) {
    LosFormatter formatter = new LosFormatter();
    StringWriter writer = new StringWriter();
    formatter.Serialize(writer, viewState);
    string viewStateString = writer.ToString();
    byte[] bytes = Convert.FromBase64String(viewStateString);
    bytes = Compressor.Compress(bytes);
    ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
  }

  // ...

}

using System.IO;
using System.IO.Compression;

public static class Compressor {

  public static byte[] Compress(byte[] data) {
    MemoryStream output = new MemoryStream();
    GZipStream gzip = new GZipStream(output, 
                      CompressionMode.Compress, true);
    gzip.Write(data, 0, data.Length);
    gzip.Close();
    return output.ToArray();
  }

  public static byte[] Decompress(byte[] data) {
    MemoryStream input = new MemoryStream();
    input.Write(data, 0, data.Length);
    input.Position = 0;
    GZipStream gzip = new GZipStream(input, 
                      CompressionMode.Decompress, true);
    MemoryStream output = new MemoryStream();
    byte[] buff = new byte[64];
    int read = -1;
    read = gzip.Read(buff, 0, buff.Length);
    while(read > 0) {
      output.Write(buff, 0, read);
      read = gzip.Read(buff, 0, buff.Length);
    }
    gzip.Close();
    return output.ToArray();
  }
}
于 2011-03-27T02:03:32.477 回答
0

由于典型的组织膨胀,请求新硬件需要花费数万年的时间,并且请求涉及我们当前设置的完整重新布线的硬件可能会受到工程部门的严重抵制。

我真的需要想出一个软件解决方案,因为这是我唯一可以控制的世界。

是的企业:(

于 2008-09-07T03:28:52.577 回答
0

我试图找到一些我过去研究过的产品,它们就像StrangeLoops一样工作(但基于软件)看起来他们已经全部倒闭了,我列表中唯一仍然存在的东西是ScaleOut但他们专门用于会话状态缓存。

我知道向高级管理层销售硬件解决方案有多难,但至少让管理层接受硬件销售代表的意见总是一个好主意。我宁愿放置一些硬件,这些硬件会给我一个即时的解决方案,因为它可以让我(或给我一些时间)完成一些其他真正的工作。

我理解,这真的很糟糕,但另一种选择是更改代码以进行优化,这可能比购买设备花费更多。

如果您找到其他基于软件的解决方案,请告诉我。

于 2008-09-07T03:54:10.987 回答
0

我可能会在另一篇文章中为您提供一个简单的解决方案。这是一个简单的类,可以包含在您的应用程序中,并在 asp.net 页面本身中包含几行代码。如果将它与分布式缓存系统结合使用,则可以节省大量资金,因为视图状态很大且成本很高。微软的速度也可能是附加此方法的好产品。如果您确实使用它并节省大量资金,尽管我很想提一下。另外,如果您不确定任何事情,请告诉我,我可以亲自与您交谈。

这是我的代码的链接。链接文本

如果您关心扩展,那么使用会话令牌作为唯一标识符或将状态存储在会话中或多或少可以保证在 Web 场场景中工作。

于 2008-11-07T05:02:43.060 回答
0

I'm going to see if I can come up with a way to leverage our current State server to contain the viewstate in memory, I should be able to use the user session ID to keep things synched up between machines.

If I come up with a good solution, I'll remove any IP protected code and put it out for public use.

于 2008-09-07T04:08:06.927 回答
0

Oh no, red tape. Well this is going to be a tall order to fill. You mentioned here that you use a state server to serve your session state. How do you have this setup? Maybe you can do something similar here also?

Edit

Awh @Jonathan, you posted while I was typing this answer up. I think going that route could be promising. One thing is that it will definitely be memory intensive.

@Mike I don't think storing it in the session information will be a good idea, due to the memory intensiveness of viewstate and also how many times you will need to access the viewstate. SessionState is accessed a lot less often as the viewstate. I would keep the two separate.

I think the ultimate solution would be storing the ViewState on the client some how and maybe worth looking at. With Google Gears, this could be possible now.

于 2008-09-07T04:12:31.550 回答
0

将视图状态存储在会话对象中,并使用分布式缓存或状态服务将会话与我们的服务器(例如 microsofts velocity)分开存储。

于 2009-01-11T04:56:02.360 回答
0

您是否考虑过是否真的需要所有这些视图状态?例如,如果您从数据库填充数据网格,则默认情况下所有数据都将保存在视图状态中。但是,如果网格仅用于呈现数据,则不需要所有形式,因此不需要视图状态。

仅当通过回发与用户进行一些交互时才需要视图状态,即使这样,实际的表单数据也可能足以重新创建视图。您可以选择性地禁用页面上控件的视图状态。

如果您确实需要100K 的视图状态,那么您将拥有一个非常特殊的 UI。如果您将视图状态减少到绝对必要的程度,那么将视图状态保留在页面中可能是最简单且最具可扩展性的。

于 2008-09-17T12:00:20.577 回答
0

不久前我在博客上写过 - 解决方案位于http://www.adverseconditionals.com/2008/06/storing-viewstate-in-memcached-ultimate.html

这使您可以通过使用自定义 PageAdapter 将 ViewState 提供程序更改为您的选择之一,而无需更改每个 Page 类。我将 ViewState 存储在 memcached 中。回想起来,我认为将它存储在数据库或磁盘上会更好——我们很快就填满了 memcached。它是一种非常低摩擦的解决方案。

于 2009-08-12T15:24:53.023 回答
0

无需购买或出售任何东西来消除视图膨胀。只需要扩展 HiddenFieldPageStatePersister。100-200KB 的 ViewState 将保留在服务器上,并且只会在页面上发送一个 62 字节的令牌。

这是有关如何完成此操作的详细文章:

http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/

于 2011-11-22T05:59:26.893 回答
0

我知道这有点陈旧,但我已经使用 squid 和 ecap 在开源“虚拟设备”上工作了几天:

1.) gzip 2.) 处理 ssl 3.) 用请求/响应的令牌替换 viewstate 4.) 用于对象缓存的 memcache

无论如何,它看起来很有希望。基本上它会位于负载均衡器的前面,并且应该真正帮助客户端性能。似乎也不是很难设置。

于 2009-07-29T02:44:10.977 回答