负载均衡时,在State_Server模式中的Session共享问题(不讨论负载均衡的问题)
2017-03-18 12:43
465 查看
前言:
配置Session的mode为State_Server模式,不说明,请按照如下配置
<sessionState mode="StateServer" stateConnectionString="tcpip=192.168.224.1:42424"cookieless="true" cookieName="APSNET_SessionId" timeout="6000" ></sessionState>
红色部分是关键部分,上面的ip是我的虚拟机的ip地址。
通过services.msc找到ASP.Net状态服务,并且开启,然后到注册表中打开AllowRemoteConnection值,设置成1.注册表地址:自己去网上搜吧,太长了不写了。
以上内容是网上大部分的内容,然后你都做好了,也未必就能Session共享。不信你去试试。(不要给我拿两个浏览器去查询,然后问我为啥不共享,我要咬人的)
补充:关于负载均衡的配置我是使用nginx做的测试,刚刚使用这个工具,还不是很熟练,你可以在网上找到。至于webFrame嘛,装起来真TMD麻烦。
正文
废话说了一大堆,上正文吧。
以上的配置都做好了之后需要检查你的iis配置,网站的应用程序池和网站的id是否相同,一定要保证相同。
那么还有一个很重要的就是要修改你的global.asax文件,添加如下代码
一切就绪,然后就嗨起来吧,真的可以了。我再这里不上截图了,附件将源码带上(其中包括网站项目、mvc项目和网站应用,都需要配置global文件)。
如果一切到这里就结束了,好像也能接受,但是我告诉你,我们还没完呢
通过上面的代码我们可以看到主要思路就是 HttpRuntime的_appDomainAppId属性赋值或者是给OutOfProcSessionStateStore的s_uribase赋值。
我们通过查看.net源码发现这两个属性都是私有属性,在我的源码附件中的mvc项目中可以看到,在不同的机器和iis版本下,输出的内容不一致,这个内容就是存储session库的一个关键值。
以下是我查看到的部分源码,抛出来给大家打打牙祭。
通过上面红色的代码,我们可以看到,不管是在global中赋值给哪个变量,最后都汇集到s_uribase这个变量中。那我们继续找,看一下是在哪里使用到了这个变量吧
下面是SessionNDMakeRequest方法的源代码,很明显在上面使用了这个方法,
真的要到此为止,往下也找不到了,也看不懂了,等到高手来指导,说的就是你,不要走,告诉我这是为什么 ^_^!!!
源码在这里点击下崽哟
配置Session的mode为State_Server模式,不说明,请按照如下配置
<sessionState mode="StateServer" stateConnectionString="tcpip=192.168.224.1:42424"cookieless="true" cookieName="APSNET_SessionId" timeout="6000" ></sessionState>
红色部分是关键部分,上面的ip是我的虚拟机的ip地址。
通过services.msc找到ASP.Net状态服务,并且开启,然后到注册表中打开AllowRemoteConnection值,设置成1.注册表地址:自己去网上搜吧,太长了不写了。
以上内容是网上大部分的内容,然后你都做好了,也未必就能Session共享。不信你去试试。(不要给我拿两个浏览器去查询,然后问我为啥不共享,我要咬人的)
补充:关于负载均衡的配置我是使用nginx做的测试,刚刚使用这个工具,还不是很熟练,你可以在网上找到。至于webFrame嘛,装起来真TMD麻烦。
正文
废话说了一大堆,上正文吧。
以上的配置都做好了之后需要检查你的iis配置,网站的应用程序池和网站的id是否相同,一定要保证相同。
那么还有一个很重要的就是要修改你的global.asax文件,添加如下代码
public override void Init() { base.Init(); foreach (string moduleName in this.Modules) { string appName = "APPNAME"; IHttpModule module = this.Modules[moduleName]; SessionStateModule ssm = module as SessionStateModule; if (ssm != null) { System.Reflection.FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm); if (store == null)//In IIS7 Integrated mode, module.Init() is called later { System.Reflection.FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null); System.Reflection.FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); appNameInfo.SetValue(theRuntime, appName); } else { Type storeType = store.GetType(); if (storeType.Name.Equals("OutOfProcSessionStateStore")) { System.Reflection.FieldInfo uribaseInfo = storeType.GetField("s_uribase", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); uribaseInfo.SetValue(storeType, appName); } } } } }
一切就绪,然后就嗨起来吧,真的可以了。我再这里不上截图了,附件将源码带上(其中包括网站项目、mvc项目和网站应用,都需要配置global文件)。
如果一切到这里就结束了,好像也能接受,但是我告诉你,我们还没完呢
通过上面的代码我们可以看到主要思路就是 HttpRuntime的_appDomainAppId属性赋值或者是给OutOfProcSessionStateStore的s_uribase赋值。
我们通过查看.net源码发现这两个属性都是私有属性,在我的源码附件中的mvc项目中可以看到,在不同的机器和iis版本下,输出的内容不一致,这个内容就是存储session库的一个关键值。
以下是我查看到的部分源码,抛出来给大家打打牙祭。
void OneTimeInit() { SessionStateSection config = RuntimeConfig.GetAppConfig().SessionState; s_configPartitionResolverType = config.PartitionResolverType; s_configStateConnectionString = config.StateConnectionString; s_configStateConnectionStringFileName = config.ElementInformation.Properties["stateConnectionString"].Source; s_configStateConnectionStringLineNumber = config.ElementInformation.Properties["stateConnectionString"].LineNumber; s_configCompressionEnabled = config.CompressionEnabled; if (_partitionResolver == null) { String stateConnectionString = config.StateConnectionString; SessionStateModule.ReadConnectionString(config, ref stateConnectionString, "stateConnectionString"); s_singlePartitionInfo = (StateServerPartitionInfo)CreatePartitionInfo(stateConnectionString); } else { s_usePartition = true; s_partitionManager = new PartitionManager(new CreatePartitionInfo(CreatePartitionInfo)); } s_networkTimeout = (int)config.StateNetworkTimeout.TotalSeconds; string appId = HttpRuntime.AppDomainAppId; string idHash = Convert.ToBase64String(CryptoUtil.ComputeSHA256Hash(Encoding.UTF8.GetBytes(appId))); // Make sure that we have a absolute URI, some hosts(Cassini) don't provide this. if (appId.StartsWith("/", StringComparison.Ordinal)) { s_uribase = appId + "(" + idHash + ")/"; } else { s_uribase = "/" + appId + "(" + idHash + ")/"; } // We only need to do this in one instance s_onAppDomainUnload = new EventHandler(OnAppDomainUnload); Thread.GetDomain().DomainUnload += s_onAppDomainUnload; s_oneTimeInited = true; }
通过上面红色的代码,我们可以看到,不管是在global中赋值给哪个变量,最后都汇集到s_uribase这个变量中。那我们继续找,看一下是在哪里使用到了这个变量吧
void MakeRequest( UnsafeNativeMethods.StateProtocolVerb verb, String id, UnsafeNativeMethods.StateProtocolExclusive exclusiveAccess, int extraFlags, int timeout, int lockCookie, byte[] buf, int cb, int networkTimeout, out UnsafeNativeMethods.SessionNDMakeRequestResults results) {//笔者注:这是一个很重要的out参数 int hr; string uri; OutOfProcConnection conn = null; HandleRef socketHandle; bool checkVersion = false; Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES"); SessionIDManager.CheckIdLength(id, true /* throwOnFail */); if (_partitionInfo == null) { Debug.Assert(s_partitionManager != null); Debug.Assert(_partitionResolver != null); _partitionInfo = (StateServerPartitionInfo)s_partitionManager.GetPartition(_partitionResolver, id); // If its still null, we give up if (_partitionInfo == null) { throw new HttpException(SR.GetString(SR.Bad_partition_resolver_connection_string, "PartitionManager")); } } // Need to make sure we dispose the connection if anything goes wrong try { conn = (OutOfProcConnection)_partitionInfo.RetrieveResource(); if (conn != null) { socketHandle = new HandleRef(this, conn._socketHandle.Handle); } else { socketHandle = new HandleRef(this, INVALID_SOCKET); } if (_partitionInfo.StateServerVersion == -1) { // We don't need locking here because it's okay to have two // requests initializing s_stateServerVersion. checkVersion = true; } Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "Calling MakeRequest, " + "socket=" + (IntPtr)socketHandle.Handle + "verb=" + verb + " id=" + id + " exclusiveAccess=" + exclusiveAccess + " timeout=" + timeout + " buf=" + ((buf != null) ? "non-null" : "null") + c8ef " cb=" + cb + " checkVersion=" + checkVersion + " extraFlags=" + extraFlags); // Have to UrlEncode id because it may contain non-URL-safe characters uri = HttpUtility.UrlEncode(s_uribase + id);//笔者注:在这里使用到了s_uribase //笔者注:在这里使用uri和主方法的out参数作为参数调用了另外一个方法,并且返回了一个int类型,到此可以看到 hr 对我们的价值已经没有了,我们进入到这个方法看看吧。 hr = UnsafeNativeMethods.SessionNDMakeRequest( socketHandle, _partitionInfo.Server, _partitionInfo.Port, _partitionInfo.ServerIsIPv6NumericAddress /* forceIPv6 */, networkTimeout, verb, uri, exclusiveAccess, extraFlags, timeout, lockCookie, buf, cb, checkVersion, out results); Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "MakeRequest returned: " + "hr=" + hr + " socket=" + (IntPtr)results.socket + " httpstatus=" + results.httpStatus + " timeout=" + results.timeout + " contentlength=" + results.contentLength + " uri=" + (IntPtr)results.content + " lockCookie=" + results.lockCookie + " lockDate=" + string.Format("{0:x}", results.lockDate) + " lockAge=" + results.lockAge + " stateServerMajVer=" + results.stateServerMajVer + " actionFlags=" + results.actionFlags); if (conn != null) { if (results.socket == INVALID_SOCKET) { conn.Detach(); conn = null; } else if (results.socket != socketHandle.Handle) { // The original socket is no good. We've got a new one. // Pleae note that EnsureConnected has closed the bad // one already. conn._socketHandle = new HandleRef(this, results.socket); } } else if (results.socket != INVALID_SOCKET) { conn = new OutOfProcConnection(results.socket); } if (conn != null) { _partitionInfo.StoreResource(conn); } } catch { // We just need to dispose the connection if anything bad happened if (conn != null) { conn.Dispose(); } throw; } if (hr != 0) { HttpException e = CreateConnectionException(_partitionInfo.Server, _partitionInfo.Port, hr); string phase = null; switch (results.lastPhase) { case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Initialization: phase = SR.GetString(SR.State_Server_detailed_error_phase0); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Connecting: phase = SR.GetString(SR.State_Server_detailed_error_phase1); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.SendingRequest: phase = SR.GetString(SR.State_Server_detailed_error_phase2); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.ReadingResponse: phase = SR.GetString(SR.State_Server_detailed_error_phase3); break; default: Debug.Assert(false, "Unknown results.lastPhase: " + results.lastPhase); break; } WebBaseEvent.RaiseSystemEvent(SR.GetString(SR.State_Server_detailed_error, phase, "0x" + hr.ToString("X08", CultureInfo.InvariantCulture), cb.ToString(CultureInfo.InvariantCulture)), this, WebEventCodes.WebErrorOtherError, WebEventCodes.StateServerConnectionError, e); throw e; } if (results.httpStatus == 400) { if (s_usePartition) { throw new HttpException( SR.GetString(SR.Bad_state_server_request_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Bad_state_server_request)); } } if (checkVersion) { _partitionInfo.StateServerVersion = results.stateServerMajVer; if (_partitionInfo.StateServerVersion < WHIDBEY_MAJOR_VERSION) { // We won't work with versions lower than Whidbey if (s_usePartition) { throw new HttpException( SR.GetString(SR.Need_v2_State_Server_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Need_v2_State_Server)); } } } }
下面是SessionNDMakeRequest方法的源代码,很明显在上面使用了这个方法,
[DllImport(ModName.ENGINE_FULL_NAME, CharSet=CharSet.Ansi, BestFitMapping=false, ThrowOnUnmappableChar=true)] internal static extern int SessionNDMakeRequest( HandleRef socket, string server, int port, bool forceIPv6, int networkTimeout, StateProtocolVerb verb, string uri, StateProtocolExclusive exclusive, int extraFlags, int timeout, int lockCookie, byte[] body, int cb, bool checkVersion, out SessionNDMakeRequestResults results);
真的要到此为止,往下也找不到了,也看不懂了,等到高手来指导,说的就是你,不要走,告诉我这是为什么 ^_^!!!
源码在这里点击下崽哟
相关文章推荐
- 负载均衡、单点登录环境中Session StateServer模式下Session丢失问题排错步骤
- ASP.NET 负载均衡 StateServer Session共享问题(经验记录)
- 负载均衡之Nginx+tomcat+redis实现session共享的负载均衡
- yii项目做负载均衡时请注意验证码session共享问题
- tomcat-redis-session-manager实现负载均衡session共享问题
- 负载均衡之Nginx+tomcat+redis实现session共享的负载均衡
- [负载均衡案例分享系列] 一个由负载均衡使用模式导致间断访问失败问题的处理
- nginx做负载均衡造成的session共享问题
- Nginx+Tomcat+Redis实现负载均衡与Session共享之四 — Nginx+Tomcat实现负载均衡
- yii项目做负载均衡时请注意验证码session共享问题
- 使用nginx做负载均衡造成的session共享问题
- 负载均衡 session 保存 for StateServer
- 使用Apache Http Server实现负载均衡并共享session
- Session 共享(StateServer模式)(原创)
- nginx+memcached+tomcat实现负载均衡和session共享
- ASP.NET 使用mode=”InProc”方式保存Session老是丢失,无奈改成StateServer 模式。
- Nginx在windows下配合IIS搭建负载均衡多站点共享Session
- Apache+tomcat实现负载均衡集群和session共享、tengine+tomcat实现web动静分离
- 负载均衡热备模式下服务器网卡的主备切换问题 推荐
- Ubuntu10.04.4 Server下基于LVS DR模式+Keepalived的负载均衡高可用