使用 protobuf-net 的 ASP.NET SessionState 模式 SQLServer 序列化
Posted
技术标签:
【中文标题】使用 protobuf-net 的 ASP.NET SessionState 模式 SQLServer 序列化【英文标题】:ASP.NET SessionState mode SQLServer serialization with protobuf-net 【发布时间】:2011-02-12 05:52:10 【问题描述】:问题背景
我一直在考虑如何优化 SQL Server 中会话的状态外存储,我遇到的一些方法是:
在不需要会话的页面上禁用会话状态。此外,在不写入会话的页面上使用只读。 在 ASP.NET 4.0 中使用 gzip 压缩选项。 尽量将会话中存储的数据量保持在最低限度。 等现在,我在会话中存储了一个对象(一个名为 SessionObject 的类)。好消息是,它是完全可序列化的。
使用 protobuf-net 进行优化
我认为另一种可能是优化会话存储的好方法是使用协议缓冲区(protobuf-net)序列化/反序列化而不是标准 BinaryFormatter。我知道我可以让我的所有对象都继承 ISerializable,但我不想创建 DTO 或使用序列化/反序列化逻辑弄乱我的域层。
任何使用带有会话状态 SQL 服务器模式的 protobuf-net 的建议都会很棒!
【问题讨论】:
仅供参考,Gzip 压缩与会话和会话存储无关。如果您将 SQL 服务器用于会话状态,那么几乎没有理由将会话用于状态,因为您在会话中存储的大部分信息都在您的数据库中。因此,如果您仍然有要保存到会话的状态并且您正在遵循您的第 3 点,那么您要保存到会话中的是什么? SessionObject 的属性也是如此吗? 另外,我会在应用程序级别(在 web.config 文件中)设置会话状态,然后为特定页面打开或只读,这样您就不必记住打开关掉它。 @Shiv - 我非常不同意你在第一条评论中的观点;在过去,我见过很多使用会话状态来处理瞬态数据的例子个人 写了一个基于 gzip 的会话状态提供程序,以帮助减少网络 IO。它工作得很好,并且显着提高了性能。 @Marc,从他谈到 gzip 的方式来看(至少对我而言)似乎并不意味着使用 gzip 来压缩会话状态,而是使用 gzip 来压缩响应,所以我说它有与会话状态无关(他试图优化的东西)。当然压缩会话状态应该有助于 I/O 带宽的使用。至于你的另一点。我确实说过,“大部分情况下”,我确实要求澄清。 就我个人而言,我尽可能远离会话状态。当我在非常繁忙的站点(300 个请求/秒及更多)上查看 IIS 中的挂起请求时,我发现所有挂起的请求都处于“获取会话状态”状态。取消会话状态(并使用 cookie 和/或隐藏字段)不会留下挂起的请求。就个人而言,我从来不需要保存(在会话状态下)任何无法从数据库中获取的东西。再说一次,我不是说没有必要,但也许重新思考可能会导致没有必要?这是我最初评论的重点。 【参考方案1】:如果现有的会话状态代码使用BinaryFormatter
,那么您可以通过让protobuf-net 充当BinaryFormatter
的内部代理来作弊,方法是在您的根对象上实现ISerializable
强>:
[ProtoContract]
class SessionObject : ISerializable
public SessionObject()
protected SessionObject(SerializationInfo info, StreamingContext context)
Serializer.Merge(info, this);
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
Serializer.Serialize(info, this);
[ProtoMember(1)]
public string Foo get; set;
...
注意事项:
只有根对象需要这样做;任何封装的对象都将由 protobuf-net 自动处理 它仍然会为最外层的对象添加 little 类型的元数据,但不会太多 这将打破现有状态;改变序列化机制本质上是一个突破性的改变如果您想从 root 对象中删除类型元数据,则必须实现自己的状态提供程序(我认为 MSDN 上有一个示例);
优点:输出更小 优点:无需在根对象上实现ISerializable
缺点:您需要维护自己的状态提供程序;p
(以上提出的所有其他点仍然适用)
还请注意,此处 protobuf-net 的有效性将在一定程度上取决于您存储的数据是什么。它应该更小,但如果你有很多非常大的字符串,它不会很多小,因为 protobuf 仍然使用 UTF-8 作为字符串。
如果您确实有很多字符串,您可能会考虑另外使用 gzip - 我为我上一个尝试 gzip 的雇主编写了一个状态提供程序,并存储了最小的(原始或 gzip) -显然需要进行一些检查,例如:
如果小于 [某个值],不要 gzip 如果 gzip 超过原始压缩率,请尽早短路 gzip 压缩以上内容可以非常愉快地结合与 protobuf-net 一起使用 - 如果您正在编写 state-provider 无论如何,您可以放弃 ISerializable
等最高性能。
最后一个选项,如果你真的想要,我先给[ProtoContract(..., CompressionMode = ...)]
添加一个“压缩模式”属性;其中:
ISerializable
用法(出于技术原因,更改主布局没有意义,但这种情况可以)
在上述序列化/反序列化期间自动应用 gzip [也许与我上面提到的相同检查]
这意味着您不需要添加自己的状态提供程序
但是,这只是我真正想申请“v2”的东西(我对仅在 v1 中的错误修复非常残酷,这样我就可以保持理智)。
如果感兴趣,请告诉我。
【讨论】:
我认为这将是 v2 的一个很棒的功能! 在传输旁边使用 ProtoBuf 时,CompressionMode 会派上用场,因为它可以更好地控制哪些对象会在树中进行压缩,而不是盲目地执行许多较小的值类型并获得更少的净值-谷物。以上是关于使用 protobuf-net 的 ASP.NET SessionState 模式 SQLServer 序列化的主要内容,如果未能解决你的问题,请参考以下文章