ASP.NET 负载均衡 StateServer Session共享问题(经验记录)
(源地址:http://www.cnblogs.com/ryhan/p/3748976.html)
最近在改造公司的一个系统 支持F5硬件负载,由于系统后面还跟了个异步工具,需要将Admin上传的文件保存本地后发送到FTP上,并记录位置,异步工具根据位置进行下载。对于工具异步导出的文件,需要在Admin上进行下载,采用的方式是异步工具生成文件包,分发到Admin下的文件夹里(将Admin下的文件发布FTP)并更新数据库记录,Admin展示可下载的包,并链接下载。 到此为止 ,完成系统上的功能性改造。
下面,另一件本来以为很容易的事情,就来了。。。也是这件事情,让我产生了 一定要写下此篇文章的动力。。。
----正文开始----
现网公网端口只开80,且公网端口走F5负载,方式为轮询。既然为负载就肯定要考虑Session保存问题。
初始设想:
使用Memcache共享缓存,并自己开发一个索引器,在索引器写好以后,突然发现如何标识客户端是个问题,需要自己设定cookies标识,要自己拦截请求等等等。。。,方案不好搞了。。
改动方案:
ASP.NET的网站,首选肯定是微软整出来的功能、组件。 经过问度娘,得到两个比较靠谱的方式(不需要自己写代码,修改sessionState配置即可)
1. 使用StateServer,选择其中一个Admin所在的服务器,开启ASP.NET 状态服务
2. 使用SQLServer ,在数据库整一库,专门保存Session,然后用作业清理过期的登录信息。
(以上配置是ASP.NET关于存储Session方式的其中两个,具体可百度。。。)
状态服务(运行services.msc):
我最终选择了方案1,原因是觉得这个简单,靠谱~~ ,好吧,以下还原我的整个配置、处理过程。。。。
1.首先,状态服务端口是42424。 修改web.config配置:
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" cookieless="false" timeout="30" />
完事后,启动调测,登录成功,表示存储OK。
2.果断发布版本,在服务器A、B上分别部署,并将状态服务IP都指向A。然后打开登录页面。。。
无法向会话状态服务器发出会话状态请求。请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同。如果服务器位于远程计算机上,请检查 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection 的值,确保服务器接受远程请求。如果服务器位于本地计算机上,并且上面提到的注册表值不存在或者设置为 0,则状态服务器连接字符串必须使用“localhost”或“127.0.0.1”作为服务器名称。
图:
额?黄页??为毛??? 好吧看来需要修改注册表AllowRemoteConnection ,把0改成1,然后重启状态服务。再次打开页面。。。哈哈。。终于显示了。。。A、B分别登录各种操作都是正常的。。。表示当时很开心。。。
图:
3.公司研发环境内没有F5,只能使用Nginx进行模拟负载。那就下载下来启动。。。每次启动都挂,说是神马创建日志文件失败。。。。好吧再问度娘,有人说要把CMD.EXE拷贝到那nginx-1.2.5下面,然后在把nginx.exe拖到CMD里面执行,额 果然好了可以启动。。。
然后把CMD拷贝到根目录
百度下,配置好复杂有点乱,那就删删删除,最后配置就几句话,测试了下,满足了我的需求(这种配置情况下,每次负载转发请求都是轮询的 就是ABABAB。。。):
#user nobody;
worker_processes 1; #error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info; #pid logs/nginx.pid; events {
worker_connections 1024;
} http {
include mime.types;
default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on;
#tcp_nopush on; #keepalive_timeout 0;
keepalive_timeout 65; #gzip on; upstream xx.xx.xx.xx{
server 192.168.xx.x2:2014;
server 192.168.xx.x1:2014;
} server {
listen 2014;
server_name xx.xx.xx.xx;
location / {
proxy_pass http://xx.xx.xx.xx;
# access_log off;
proxy_connect_timeout 10;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
} }
4.负载启动后,果断访问虚拟主机,额。。。悲剧的事情,从此处开始。。。。
a.正确的密码帐号,登录后页面刷了下,没登录成功
b.验证码 偶尔不正确,搞不懂了。。
c.偶尔登录成功,各种操作也OK。
d.在用X帐号登录第一次时,页面刷新了下,然后用了Y帐号登录,成功。 刷了下页面,嗯? 怎么编写X了,再刷一次,我擦怎么又是Y了。然后。。。发现了,这次缓存有问题了。。。。session貌似没共享? 度娘都是说这样可以共享的,但是为毛不行。。。
------------------------------------------------------------------------------------------------------------------------
中间各种测试,各种分析,最终结论是要么A的session没发给B的服务器,要么就是哪地方挂了,果断把状态服务给关了,然后两个页面都挂了。看来,两个页面都用了这状态服务器,但是为啥不行呢。。。
果断在增加一个sessiontest.aspx页面,输出当前登录的用户,图片验证码、Cookies、SessionID信息。
打开虚拟主机页面,刷新:
第一次:
sessionid=ajfjs245ywd12p45nnjwvqe5
username=
userpwd=
userRole=
randmKey=2715
cookies=ASP.NET_SessionId:ajfjs245ywd12p45nnjwvqe5
第二次:
sessionid=ajfjs245ywd12p45nnjwvqe5
username=
userpwd=
userRole=
randmKey=8432
cookies=ASP.NET_SessionId:ajfjs245ywd12p45nnjwvqe5
第三次:
sessionid=ajfjs245ywd12p45nnjwvqe5
username=
userpwd=
userRole=
randmKey=2715
cookies=ASP.NET_SessionId:ajfjs245ywd12p45nnjwvqe5
什么情况? 为毛来回变换。。。。猜测,就是这个原因导致每次登录时系统反馈验证码不正确,偶尔登录成功后,X、Y用户会来回切换 也是这个。。。
然后用Fiddler构造请求,使用 ASP.NET_SessionId:ajfjs245ywd12p45nnjwvqe5 分别对两台负载WEB进行发包,得到的结果分别与请求虚拟主机的第一次和第二次结果一致。。。说明两台负载WEB的Session没存在一起,或者存在一起了,但是是分开的,压根没共享。。。。
好吧问题定位清楚,那就开始排查是什么导致这问题产生的。。。
------------------------------------------------------------------------------------------------------------------------
5.拿出神器,开始抓包,发现通信正常,A的SESSION也发给B的服务器了。但是为啥还不行?
------------------------------------------------------------------------------------------------------------------------
中间各种测试,各种分析,最终 还是没结论,然后就一边分析、一边百度。。。。
------------------------------------------------------------------------------------------------------------------------
最终,在一个网页上看到一段话,才恍然大悟。。。原来虽然我Session共享了,但是A、B存储的位置不对,每次读写都不是一个。囧
要在 Web 场中的不同 Web 服务器间维护会话状态,Microsoft“Internet 信息服务”(IIS) 配置数据库中 Web 站点的应用程序路径(例如,\LM\W3SVC\2)与 Web 场中所有 Web 服务器必须相同。大小写也必须相同,因为应用程序路径是区分大小写的。在一台 Web 服务器上,承载 ASP.NET 应用程序的 Web 站点的实例 ID 可能是 2(其中应用程序路径是 \LM\W3SVC\2)。在另一台 Web 服务器上,Web 站点的实例 ID 可能是 3(其中应用程序路径是 \LM\W3SVC\3)。因此,Web 场中的 Web 服务器之间的应用程序路径是不同的。我们必须使Web 场Web 站点的实例 ID 相同即可。你可以在IIS中把某一个WEB配置信息保存为一个文件,其他Web 服务器的IIS配置可以来自这一个文件。
为验证实际情况,继续抓包,并把A、B WEB使用的状态服务改到C上,刷新虚拟主机页面:
第一次(A <-> C):
第二次(B <-> C):
解码后情况:
第一次:
GET /LM/W3SVC/753869457/ROOT(njUDW6dgPSYnBQVKY6MYyJpdicI=)/ajfjs245ywd12p45nnjwvqe5 HTTP/1.1
Host: 192.168.14.75
Exclusive: acquire
第二次:
GET /LM/W3SVC/753869456/Root(tHayTJV6gf0ZP3QdeL9pR3YM4mg=)/ajfjs245ywd12p45nnjwvqe5 HTTP/1.1
Host: 192.168.14.75
Exclusive: acquire
可以看到,第一次和第二次的请求路径不一样(红色部分),cookies ID是一样的,也就是说状态服务器上已经保存了两个负载WEB的Session,但是两个WEB存储的路径不一致。
------------------------------------------------------------------------------------------------------------------------
解决方案:
1.使用VBS脚本更改IIS站点设置(http://support.microsoft.com/default.aspx?scid=kb;zh-cn;325056)
使用代码修改 IIS 配置数据库。
创建一个文本文件,然后将该文件命名为 Moveinstance.vbs。
将下面的脚本代码添加到 Moveinstance.vbs 中,这些代码会修改 Web 站点的实例 ID,以便这些实例 ID 是相同的:
Dim WebService
Dim oldstr
Dim newstr
Dim args
Set args = WScript.Arguments
If args.Count < 1 Then
Wscript.Echo "Must have original instance id and new instance id" & chr(10) & chr(13) & _
"usage: moveinstance.vbs 1 5" & chr(10) & chr(13) & _
"Moves instance 1 to instance 5"
WScript.Quit()
End If
Set WebService = GetObject("IIS://LocalHost/W3SVC")
oldstr = args(0) 'old instance
newstr = args(1) 'new instance
WebService.MoveHere oldstr,newstr
WebService.SetInfo
Set WebService = nothing
Set args=nothing
WScript.echo "DONE" 保存 Moveinstance.vbs。
在命令提示符下从您在上一步中保存该 .vbs 文件时的同一个位置运行此脚本。 例如,在命令提示符下,键入 cscript moveinstance.vbs 1 5。这会在配置数据库中将 Web 站点的实例 ID 从 1 更改为 5。 注意:分配给 Web 站点的新实例 ID 一定不能已经分配给其他 Web 站点。这会导致不可靠的结果。
2.使用MetaEdit工具直接修改(http://support.microsoft.com/kb/240225):
MetaEdit IIS 4.0 资源工具包介绍 MetaEdit 如下所示:
元数据库编辑器 (MetaEdit) 是一个工具,它提供的功能类似于 Windows NT 注册表编辑器。使用 MetaEdit,可以浏览和修改配置数据库中的属性。请注意,在使用 MetaEdit,您可以进行更改,可能会损坏您的 IIS 配置。请务必认真编辑所有项。
MetaEdit 是附带可从 Microsoft Press IIS 4.0 资源工具包实用程序之一。 MetaEdit 文档 (MetaEdit.doc) 位于 IIS 资源工具包光盘上的 \IIS Resource Kit\Utility\MetaEdit 文件夹中。
3.将站点A配置导出,在B服务器使用A导出的配置进行发布(需要保证A、B服务器上的结构、目录 文件一致。)
另外:
若要在A、B Web上负载,还必须保证A、B的 machineKey 配置一致,不然也会黄页。
我的配置:
<machineKey validationKey="3FF1E929BC0534950B0920A7B59FA698BD02DFE8" decryptionKey="280450BB36319B474C996B506A95AEDF9B51211B1D2B7A77" decryption="3DES" validation="SHA1"/>
在整个过程中,发现好多问题,最终还是解决掉! 另外,一直不用SQLServer存储Session的原因就是,那建库脚本老是执行失败。。
by:MR.HAN 2014.05.23
ASP.NET 负载均衡 StateServer Session共享问题(经验记录)的更多相关文章
- nginx+tomcat+redis负载均衡及session共享
概述 本文档是用来详细描述 nginx+tomcat+redis负载均衡实现session共享 所需软件及下载地址 软件名称 下载地址 功能说明 Nginx-v1.6.0 http://nginx.o ...
- haproxy+tomcat实现负载均衡以及session共享(linux centos7环境)
一.安装HAProxy 1.进入home目录,下载最新haproxy安装包. cd /home wget http://haproxy.1wt.eu/download/1.4/src/haproxy- ...
- keepalived+nginx+tomcat+redis实现负载均衡和session共享(原创)
keepalived+nginx+tomcat+redis实现负载均衡和session共享 直接上链接,码了一天,就不再重写了,希望能帮到大家,有问题欢迎留言交流.
- Nginx+Tomcat8+Memcached实现负载均衡及session共享
1> 基础环境 简易拓扑图: 2> 部署Tomcat [root@node01 ~]# ll -h ~ |egrep 'jdk|tomcat'-rw-r--r-- 1 root root ...
- 玩转spring boot——负载均衡与session共享
前言 当项目上线后,如果要修复bug或扩充功能,都需要重启tomcat服务.此时,正在使用应用的用户们就需要等待服务器的重启,而这就会造成不好的用户体验.还有,当仅仅只有一台tomcat服务时,如果 ...
- 负载均衡服务器session共享的解决方案
在ASP.NET的程序中要使用Session对象时,必须确保页面的@page指令中EnableSessionState属性是True或者Readonly,并且在web.config文件中正确的设置了S ...
- asp.net 负载均衡下session存储的解决方法
转自:http://www.cnblogs.com/david100zhang/archive/2011/12/28/2304917.html 在WEB场中,动态网页往往会因为几台主机做了负载而产生S ...
- Asp.net负载均衡之Session
在WEB场中,动态网页往往会因为几台主机做了负载而产生SESSION丢失的问题,网上也有很多的介绍,我这里只将我经历的过程给大家分享一下: 系统要运行在负载平衡的 Web 场环境中,而系统配置文件we ...
- 使用nginx做负载均衡的session共享问题
查了一些资料,看了一些别人写的文档,总结如下,实现nginx session的共享PHP服务器有多台,用nginx做负载均衡,这样同一个IP访问同一个页面会被分配到不同的服务器上,如果session不 ...
随机推荐
- siganl tappII的应用及MATLAB调用
1.在应用SIGNAL TAPPII时一定要把不用的端口设置为输入三态,否则观察不到数据. 2.用SIGNAL TAPII 观察数据时双向是观察不到数据的,但模块内部用于传输双向口数据的寄存器可以看到 ...
- C#操作Excel(创建、打开、读写、保存)几种方法的总结
在.NET开发中,不管是web程序还是桌面软件(尤其是涉及数据库操作的MIS系统等),常常需操作Excel,如导出数据到Excel,读取Excel中数据到程序中等.总结起来,其操作不外乎创建.打开.读 ...
- mysql中设置默认字符编码为utf-8
使用过Linux的同志就知道,在Linux下安装mysql,尤其是使用yum安装的时候,我们是没法选择其默认的字符编码方式.这个就是一个比较头痛的问题,如果Linux数据库中使用到中文的时候,乱码问题 ...
- spring mvc 注解@Controller @RequestMapping @Resource的详细例子
现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了.不过 ...
- Python学习-38.Python中的正则表达式(二)
在Python中,正则表达式还有较其他编程语言有特色的地方.那就是支持松散正则表达式了. 在某些情况,正则表达式会写得十分的长,这时候,维护就成问题了.而松散正则表达式就是解决这一问题的办法. 用上一 ...
- Intellij Idea 14编译golang 插件
最近项目实在太赶了,很久没有写过博文了. 公司新配了一台笔记本电脑,原装win8的.于是又从linux回到了windows.不想用win命令行来搞go了,win下太折腾了.还是用一直使用的idea. ...
- Checkpoint--相关问题
Checkpoint是实例级别还是数据库级别? 答:数据库级别,在SQL Server关闭时,会对所有数据库逐一提交checkpoint 测试代码 USE DB0002 GO CHECKPOINT G ...
- 关于Java_Web连接Oracle数据库
1.前提条件 1>装有Oracle数据库(因为连接的时候需要开启两项服务) 2>myeclipse或eclipse(支持WebProject的版本)开发环境,本机以myeclipse为例, ...
- 执行js-----Selenium快速入门(十四)
Selenium能够执行js,这使得Selenium拥有更为强大的能力.既然能执行js,那么js能做的事,Selenium应该大部分也能做.这应该得益于JavascriptExecutor这个接口,而 ...
- 诸神眷顾的幻想乡(zjoi2015,bzoj3926)(广义后缀自动机)
幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. ...