Nginx+iis 中搭建的站点解决session 一致性的解决方案

上一篇文件介绍了使用nginx+iis 模拟负载均衡的问题。详细搭建过程请查看( http://blog.csdn.net/u010533180/article/details/52784696

   模拟负载均衡站点已经搭建完毕,那么问题来了,两个站点也许在不同的机器下使用不同ip和端口号,即使部署在同一机器下面,端口号也肯定不同。现在有很多的信息保存在session中,那么session信息的一致性该如何解决呢?
  Session 保存在服务器中,唯一的回话标识,有一个对应的SessionId。用户关闭浏览器,即回话结束,当用户在打开浏览器浏览时,就是一个新的回话了。而且Session的唯一标识是基于cookie存储的。如果用户禁用了cookie,Session也是无法使用的。如何解决,请自行查阅相关资料,因为这是不是本文的重点。关于Session更详细的信息,也可以查阅微软官方的站点(https://msdn.microsoft.com/zh-cn/library/ms178581(v=vs.100).aspx)

这里Session的测试也是基于上次的搭建进行继续下去的。还是那个熟悉的default.aspx,里面的测试代码如下:
    protected void Page_Load(object sender, EventArgs e)
        {
            int port = Request.Url.Port;
            if (port == 8081)
            {
                Response.Write("第一个页面<br/>");
            }
            else if (port == 8082)
            {
                Response.Write("第二个页面<br/>");
            }
            else
            {
                Response.Write(port.ToString() + "<br/>");
            }

            Response.Write("请求开始时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "<br/>");
            Response.Write("服务器名称:" + Server.MachineName + "<br/>"); //服务器名称  
            Response.Write("服务器IP地址:" + Request.ServerVariables["LOCAL_ADDR"] + "<br/>"); //服务器IP地址  
            Response.Write("HTTP访问端口:" + Request.ServerVariables["SERVER_PORT"]);//HTTP访问端口"
            Response.Write(".NET解释引擎版本:" + ".NET CLR" + Environment.Version.Major + "." + Environment.Version.Minor + "quot;." + Environment.Version.Build + "." + Environment.Version.Revision + "<br/>"); //.NET解释引擎版本  
            Response.Write("服务器操作系统版本:" + Environment.OSVersion.ToString() + "<br/>");//服务器操作系统版本  
            Response.Write("服务器IIS版本:" + Request.ServerVariables["SERVER_SOFTWARE"] + "<br/>");//服务器IIS版本  
            Response.Write("服务器域名:" + Request.ServerVariables["SERVER_NAME"] + "<br/>");//服务器域名  
            Response.Write("虚拟目录的绝对路径:" + Request.ServerVariables["APPL_RHYSICAL_PATH"] + "<br/>");//虚拟目录的绝对路径  
            Response.Write("执行文件的绝对路径:" + Request.ServerVariables["PATH_TRANSLATED"] + "<br/>");//执行文件的绝对路径  
            Response.Write("虚拟目录Session总数:" + Session.Contents.Count.ToString() + "<br/>"); //虚拟目录Session总数  
            Response.Write("虚拟目录Application总数:" + Application.Contents.Count.ToString() + "<br/>");//虚拟目录Application总数  
            Response.Write("域名主机:" + Request.ServerVariables["HTTP_HOST"] + "<br/>");//域名主机  
            Response.Write("服务器区域语言:" + Request.ServerVariables["HTTP_ACCEPT_LANGUAGE"] + "<br/>");//服务器区域语言  
            Response.Write("用户信息:" + Request.ServerVariables["HTTP_USER_AGENT"] + "<br/>");
            Response.Write("CPU个数:" + Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS") + "<br/>");//CPU个数  
            Response.Write("CPU类型:" + Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER") + "<br/>");//CPU类型  
            Response.Write("请求来源地址:" + Request.Headers["X-Real-IP"] + "<br/>");
            Session["nginx"] = port;
            if (Session["port"] == null)
            {
                Response.Write("Session为null<br/>");
                LoginSession loginSession = new LoginSession();
                loginSession.LoginPort = port;
                loginSession.LoginTime = DateTime.Now;
                Session["port"] = loginSession;
            }
            else
            {
                LoginSession loginSession = Session["port"] as LoginSession;
                if (loginSession != null)
                {
                    Response.Write(loginSession.LoginPort + ";" + loginSession.LoginTime.ToString("yyyy-MM-dd HH:mm:ss") + "</br>");
                }
                else
                {
                    Response.Write("不知道何种原因从Session里面取到的LoginSession 为null");
                }
            }
        }

添加一个LoginSession 类,记得要标记[Serializable],因为Session里面的对象需要支持序列化才能成功。 进行测试

using System;
using System.Collections.Generic;
using System.Web;

namespace NginxWebProject
{
    [Serializable]
    public class LoginSession
    {
        private int loginPort;
        public int LoginPort
        {
            get
            {
                return loginPort;
            }
            set
            {
                loginPort = value;
            }
        }

        private DateTime loginTime;
        public DateTime LoginTime
        {
            get
            {
                return loginTime;
            }
            set
            {
                loginTime = value;
            }
        }
    }
}

为了测试我这里把session统一放到了一个新的机器中(,该节点里面的信息读者还是自己查阅,信息量确实很大)。则最终的对应的web.config文件修改如下:

<?xml version="1.0"?>
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true"/>
    <httpRuntime/>
      **<sessionState mode="StateServer" stateConnectionString="tcpip=192.168.164.129:42424" timeout="60" stateNetworkTimeout="20"/>**
  </system.web>
</configuration>

上面的配置中我把Session的信息存储在了IP地址为 192.168.164.129 这台机器中,端口号为默认的42424。则要保证这台机器服务列表里面的Asp.net 状态服务启动。

这里写图片描述

注册表里面的 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state 下面的 AllowRemoteConnection 的值为1。 否则部署的站点也无法访问。
这里写图片描述
如果这样部署到服务器上面,会发现Session总是会被覆盖掉,达不到统一致性。
解决方法如下:在站点里面的Global.asax文件中添加如下代码即可。如果站点里面没有这个文件,则项目右键-》添加新建项-》在弹窗中找到Visual C# -》web》全局应用程序类

这里写图片描述

public override void Init()
        {
            base.Init();

            foreach (string moduleName in this.Modules)
            {
                //string appName = "APPNAME";
                string appName = moduleName;
                IHttpModule module = this.Modules[moduleName];
                SessionStateModule ssm = module as SessionStateModule;
                if (ssm != null)
                {
                    FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", BindingFlags.Instance | BindingFlags.NonPublic);
                    FieldInfo configMode = typeof(SessionStateModule).GetField("s_configMode", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);

                    SessionStateMode mode = (SessionStateMode)configMode.GetValue(ssm);
                    if (mode == SessionStateMode.StateServer)
                    {
                        SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm);
                        if (store == null)//In IIS7 Integrated mode, module.Init() is called later
                        {
                            FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
                            HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
                            FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);
                            appNameInfo.SetValue(theRuntime, appName);
                        }
                        else
                        {
                            Type storeType = store.GetType();
                            if (storeType.Name.Equals("OutOfProcSessionStateStore"))
                            {
                                FieldInfo uribaseInfo = storeType.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic);
                                uribaseInfo.SetValue(storeType, appName);
                                object obj = null;
                                uribaseInfo.GetValue(obj);
                            }
                        }
                    }
                    break;
                }
            }
        }

浏览站点访问,我的测试效果图如下:

这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值