asp.net、状态服务器、NLB、会话丢失
stackoverflow 上的第 1 篇文章,希望能得到很好的反馈:)
我目前正在尝试对我们的网站进行负载平衡。 我们在带有 IIS 6 的 Windows Server 2003 上设置了 2 个集群 NLB。
在测试设置时,我发现有时我们的会话会丢失。 一天半后,结果如下:
- 是的,我们的 machine.config 都有相同的加密/解密密钥。
- 是的,两台机器的 iis metabase.xml 中的 id 是相同的。 实际上,除了“AdminACL”之外,整个文件都是相同的。
- 两个 Web 应用程序都设置了“StateServer”,并且都指向同一台计算机。
从这一点来看,在谷歌上搜索提供的信息和可能的解决方案较少。
据我所知,没有特定的模式会导致这个问题。 它只是偶尔发生一次。
在尝试查找问题时,我看到一个请求将 asp 会话 id cookie 发送到服务器,但服务器没有将其映射到用户会话。
于是客户端发出了请求号x,有了cookie,session就被映射了,一切都很顺利。 客户端发送了请求号x+1,带有cookie,但是没有找到session。
这两个请求都是在 NLB 中的同一台计算机上发出的。
以下是 asp trace.axd 的片段:
第一个请求:
请求详细信息 会话 ID:j2ffvy45updpc52uhw1mbg55 请求类型:GET 请求时间:2008 年 11 月 26 日 2:58:06 PM 状态代码:200 请求编码:Unicode (UTF-8) 响应编码:Unicode (UTF-8)
请求 Cookie 集合
名称 值 大小
ASP.NET_SessionId j2ffvy45updpc52uhw1mbg55 42 AID 22 9
响应 Cookie 集合
名称值大小
标头集合
名称值
Cookie ASP.NET_SessionId=j2ffvy45updpc52uhw1mbg55; AID=22
第二个请求:
请求详细信息 会话 ID:请求类型:POST 请求时间:11/26/2008 2:58:08 PM 状态代码:
请求编码:Unicode (UTF-8) 响应编码:
请求 Cookie 集合
名称值大小
响应 Cookie 集合
名称值大小
标头集合 名称 值 Cookie ASP.NET_SessionId=j2ffvy45updpc52uhw1mbg55; AID=22
正如您在第二个请求中看到的,cookie 是从客户端发送的,但 asp 似乎从未在其“请求 Cookies 集合”中添加 cookie。 我认为这就是它找不到会话的原因。
那么为什么cookie没有映射到session呢? 这是问题所在吗? 问题出在其他地方吗?
如有任何疑问,请随时询问。
感谢大家的反馈。
杰峰
1st post on stackoverflow, hope to have great feedback :)
I'm currently trying to load balance our web site. We have set up a 2 cluster NLB on windows server 2003 with IIS 6.
While testing the setup, I found that sometimes, our session is lost. A day and a half later, here's the result:
- Yes, our machine.config both have the same encryption/decryption key.
- Yes, the id in iis metabase.xml are the same for both machine. Actually, the entire file are the same, except for "AdminACL".
- Both web application are set with "StateServer" and both pointing at the same machine.
From that point, searching on google gives less information and possible solutions.
From what I know, there's no particular pattern that cause this problem. It just happen once in a while.
While trying to find the problem, I've seen that a request sent the asp session id cookie to the server, but the server didn't map it to the user session.
So the request number x was sent from the client, with the cookie, session was mapped, and everything went smoothly.
The request number x+1 was sent from the client, with the cookie, but session was not found.
Both request were made on the same machine in the NLB.
Here's a snippet of the asp trace.axd:
1st request:
Request Details
Session Id: j2ffvy45updpc52uhw1mbg55 Request Type: GET
Time of Request: 11/26/2008 2:58:06 PM Status Code: 200
Request Encoding: Unicode (UTF-8) Response Encoding: Unicode (UTF-8)
Request Cookies Collection
Name Value Size
ASP.NET_SessionId j2ffvy45updpc52uhw1mbg55 42
AID 22 9
Response Cookies Collection
Name Value Size
Headers Collection
Name Value
Cookie ASP.NET_SessionId=j2ffvy45updpc52uhw1mbg55; AID=22
2nd Request:
Request Details
Session Id: Request Type: POST
Time of Request: 11/26/2008 2:58:08 PM Status Code:
Request Encoding: Unicode (UTF-8) Response Encoding:
Request Cookies Collection
Name Value Size
Response Cookies Collection
Name Value Size
Headers Collection
Name Value
Cookie ASP.NET_SessionId=j2ffvy45updpc52uhw1mbg55; AID=22
As you can see in the 2nd request, the cookie is sent from the client, but asp seems to never add the cookies in it's "Request Cookies Collection". I think that's why it doesn't find the session.
So why the cookie is not mapped to the session? Is that the problem? Is the problem elsewhere?
Feel free to ask any clarifications.
Thank you all for your feedback.
JF
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我终于找到了我的问题的答案。 它的根源在于应用程序代码(就像程序员的 99% 的第 3 方工具“错误”)。 无论如何,我决定发布它,以防有人遇到类似的情况。
此代码是 WebServiceRequester 类的一部分。 Web 服务请求者类在创建会话时实例化,并保存在会话中。 在创建过程中,我们初始化了成员“m_webServiceURL”,并且该成员随后保存在会话中。 该成员初始化的值取决于本地计算机上的设置。
重要的部分如下:
WebServiceRequester 类包含一个WebService 对象。
WebService 对象无法保存在会话中,它们在 asp 中不可序列化。 该属性具有 [NonSerialized] 属性。 因此,每次我们在页面生命周期中第一次访问对象的“WebService”属性时,都必须创建一个新属性,并为其分配保存在会话中的 url“m_webServiceURL”。
所以您会看到,新的 Web 服务对象可能位于不同的计算机上,这意味着每台计算机上的设置不同。
所以这就是发生的事情:
框 29 设置为访问 localhost 处的 Web 服务
框 30 设置为访问 192.168.253.29 的 Web 服务。
从技术上讲,它们都设置在同一台机器上。 但这里有一个场景:
在框 29 上登录。m_webServiceURL 在会话中设置为 localhost。
[此处第 29 框的一些请求]
NLB 平衡为我们带来了第 30 框。
框 30 加载其会话,创建一个新的 Web 服务对象,并将 localhost 作为 Web 服务地址。
框 30 向错误的 Web 服务发出了请求,导致会话过期异常。
调试期间的问题之一是网络监视器未记录本地通信。
引导我进行跟踪的是,我们从未在框 29 日志跟踪上记录过异常,而它应该有。
谢谢大家的建议,真的很感激。
祝你有美好的一天。
杰峰
I finally found the answer to my problem. It's origin are within the application code (like 99% of a programmer's 3rd party tools 'bugs'). I decided to post it anyway in case someone is in a similar scenario.
This code was part of WebServiceRequester class. The web service requester class was instanciated when session was created and it is saved in session. During creation, we initalizate the member 'm_webServiceURL', and this member is saved in session after. At which value was this member initialize was depending on a setting on the local machine.
The important part is the following:
WebServiceRequester class contains a WebService objects.
WebService objects can't be saved in session, they are not serializable in asp. The property had the [NonSerialized] attribute on it. So everytime we accessed the 'WebService' property of the object for the first during a page life cycle, we had to create a new one, and assigning ot it the url 'm_webServiceURL' which was saved in session.
So you see, new webservice object, on possibly a different machine, meaning a different setting on each machine.
so here's what happened:
box 29 was set to access Web Service at localhost
box 30 was set to access Web Service as 192.168.253.29.
Technically, they are both set on the same machine. But here's a scenario:
login on box 29. m_webServiceURL is set to localhost in session.
[some request on box 29 here]
NLB balancing bring us on box 30.
box 30 loads it's session, create a new webservice obect with localhost as the web service address.
box 30 made the request to the wrong web service leading to a Session Expired exception.
One of the problem during the debug, was that the local communication were not recorded with the network monitor.
What lead me on the trace, was that we never had an exception logged on the box 29 log trace, as it should have.
Thanks for you suggestions everyone, it was really appreciated.
Have a good day.
JF
严格来说不是您问题的答案,但是您是否尝试过使用基于 sql server 的会话存储? (在 MSDN 上搜索永久脚本而不是 asp.net 提供的临时脚本)
我听说过有关可执行会话服务的“坏事”,因此没有使用它。 不过,使用基于 SQL Server 的解决方案进行网络农业从未遇到过任何问题。
抱歉,严格来说这并不是您问题的答案,但它应该(a)修复它,或者(b)显着缩小范围。
Not strictly an answer to your question, but have you tried it using a sql server based session store? (Search on MSDN for the permanent script rather than the temp script that's provided with asp.net)
I've heard "bad things" about the executable session service, and consequently have not used it. Never had any problems web farming with the sql server based solution though.
Sorry it's not strictly an answer to your problem, but it should either (a) fix it, or (b) narrow it down significantly.
好吧,如果您使用的是 Visual Studio,您至少可以使用 MSDE(Visual Studio 附带的 SQL Server 精简版)对其进行测试...
它可能有助于排除状态服务器问题...
Well, if you're using visual studio, you could at least test it with the MSDE (the cut down version of SQL Server that comes with Visual Studio)...
It might help rule out state server problems...
使用数据库方法有其自身的问题。 我认为您应该能够使用您喜欢的方法。
也许这篇会话故障排除文章会帮助?
或“排查 ASP.NET 中与会话相关的问题”
或“对过期的 ASP.NET 会话状态进行故障排除和您的选项"
Using the database approach has its own issues. I think you should be able to use your preferred approach.
Perhaps this session troubleshooting article would help?
Or "Troubleshooting Session Related Issues in ASP.NET"
Or "Troubleshooting Expired ASP.NET Session State and Your Options"
我会蹩脚并重申MS SQL Server 的建议。 安装 SQL Server Express,它是完全免费的,包括商业用途,它只有以下 3 个缺点,在这个阶段对您来说应该不是问题:
I'll be lame and re-iterate the proposal of MS SQL Server. Install SQL Server Express which is completeley free including for commercial use and it has only these 3 drawbacks which shouldn't be a problem for you in this stage :
需要考虑的几点:
如果您打算使用 MSSQL Express 作为状态数据库,请记住它不附带 SQL Server 代理,这意味着没有任务调度程序在后台运行并清理过期的会话。 我建议找到一个调度程序并定期运行清理过期会话存储过程。
祝你好运
A few points to take into consideration:
If you're about to user MSSQL Express as your state DB, remember that it doesn't come with SQL Server Agent meaning there's no tasks scheduler running in the background and cleaning your expired sessions. I'd recommend finding a scheduler and running the clean expired sessions stored procedure periodically.
Good luck
不要乱搞 SQL,而是将测试直接发送到 IIS 节点之一,看看是否仍然遇到相同的问题。 我确信如果您只进行少量测试 StateServer 不会成为问题。
Instead of messing around with SQL, send your tests directly into one of your IIS nodes to see if you still get the same issue. I'm sure if your only doing a small number of tests StateServer won't be the issue.
尝试通过代码将asp.net_sessionid的域名设置为“.yourdomain.com”。
默认情况下,ASP.net_SessionID cookie 域名设置为完整的应用程序路径。 所以,这可能是 cookie 不传播的原因之一。
例如
Request.Cookies["ASP.NET_SessionId"].Domain = ".yourdomain.com"。
记住第一个“。” 在域名中很重要。
您可以在 HttpModule 的 AcquireRequestState 事件中执行此操作。
Try setting the domain name of the asp.net_sessionid through code to ".yourdomain.com".
By default the ASP.net_SessionID cookie domain name is set to the full application path. So, this may be one of the reason why the cookie is not travelling.
E.g.
Request.Cookies["ASP.NET_SessionId"].Domain = ".yourdomain.com".
Remember the first "." is important in the domain name.
You could do this in the HttpModule in the AcquireRequestState event.