该不该放弃 AppFabric Caching : Session 引发的问题

该不该放弃 AppFabric Caching : Session

 

 

我所在的上个公司用 Velocity 来缓存数据, 对程序的效率起了很大的帮助,所以我在上个项目里尝试使用了 AppFabric 1.1 Caching (Window Server AppFabric),但没有用它来存 Session.

 

当前项目,因为要从外部接口(非内部WCF服务)取数据,而且速度慢,所以,我把取回的数据通过 Session 缓存到 AppFabric Caching 里, 只在几个关键点去重新请求。

 

但是AppFabric 1.1 有几个问题:

内存泄露,莫名其妙的ERRCA0012

其中 ERRCA0012 我没有找到答案。

 

内存泄露我搜了MSDN,说要安装补丁包:KB983182 KB2527387

但是这两个安装包并没有对外开放,要想得这两个包,还要在线提申请,我填到最后一步,发现要:

技术支持服务包, 专业级(Professional)和其他服务 (需要访问ID)

软件保障许可证: 仅适用于服务器 (需要软件保障访问 ID)

看一下支持合同的价格:

http://60.195.251.18:82/ShoppingCart.aspx

最便宜的,单次价格:150,我当然不会出这个钱,公司也不会无缘无故的出这个钱。

 

内存泄露表现如下:

用 Get-CacheStatistics 命令查看的所有数据大小不超过30M,但是 DistributeCacheService.exe 却要占到 700M甚至更高内存(测试环境)。用 Invoke-CacheGC 命令,效果甚微。(之前没有将 Session 保存到 AppFabric 的时候,并没有发现有内存泄露)

 

将 Session 存到 AppFabric 的配置如下:

<sessionState sessionIDManagerType="XXX.Frameworks.Configurations.SessionIDManager, XXX.Frameworks.Configurations" mode="Custom" customProvider="AppFabricCacheSessionStoreProvider" timeout="30">
               <providers>
               <add  name="AppFabricCacheSessionStoreProvider"
 type="Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider, Microsoft.ApplicationServer.Caching.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                                                             cacheName="default"
                                                             sharedId="OnlineSiteSession"
                                              />
               </providers>
</sessionState>

其中 timeout 被设为 30 分钟,是为了满足业务需要,因为要录入的数据很多,还要跳转到其它业务系统里走一圈。

其中 SessionIDManager 是为了解决二级域名共享 Session 而设的, 下文我会贴出供参考。

其中,default 是说把 session 都保存到 default 这个 cache 里。

在用 Get-Cache 看一下,default 下有大量的:Default_Region_XXX(Primary) 的 Region, 我不知道是不是因为把 session 保存到其它 cache 下就不会有这个问题,没有尝试。在用 Get-CacheStatistics 查看一下 default 的大小,size: 0, Item Count: 0。

 

在看一下 Get-CacheConfig

CacheName                : default

TimeToLive               : 10 mins

CacheType                : Partitioned

Secondaries              : 0

MinSecondaries           : 0

IsExpirable              : True

EvictionType             : LRU

NotificationsEnabled     : False

WriteBehindEnabled       : False

WriteBehindInterval      : 300

WriteBehindRetryInterval : 60

WriteBehindRetryCount    : -1

ReadThroughEnabled       : False

ProviderType             :

ProviderSettings         : {}

 

完全默认 LRU, 10 分钟 , 可过期

 

在看一下 Client 的设置:

<hosts>
<host name="172.18.21.23" cachePort="22233"/>
</hosts>
<securityProperties mode="None" protectionLevel="None" />
<!--<transportProperties connectionBufferSize="131072" maxBufferPoolSize="268435456"
                        maxBufferSize="8388608" maxOutputDelay="2" channelInitializationTimeout="60000"
                        receiveTimeout="600000"/>-->

 

对,只有一台缓存主机,因为是测试环境。生产环境也只有一台16G的 CacheHost。

但是:最小缓存集群推荐3个缓存主机,缓存主机的功能要单一:推荐只放缓存服务,不放其它服务。

 

但是:所有的我都不能解决,我也说不上话,我只是一个开发人员。加一台服务器是要成本的。

 

这个问题出现很久了,特别是 ERRCA0012 等莫名的错误,它们让我饱受同事鄙夷、质疑、不信任的眼光。你们说是我错信了MS的威力还是神马??

我期待 AppFabric Caching 方面有经验的大神的帮助。

为了不久的正式上线,我提出将 Session 转移到 SqlServer 里,这是在回避问题,但是也是无奈的解决方法(我们的多个业务系统需要共享 Session)

 

具体步骤:

1, 生成数据库:

 

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>ASPNET_REGSQL.EXE –ssadd -U sa –S XXX\TEST -sstype c -d Session

会提示你输入密码,是 sa 的密码。

 

2, 配置 web.config

<sessionState mode="SQLServer"                                                                    allowCustomSqlDatabase="true"                                                           sqlConnectionString="data source=XXX\TEST;Initial Catalog=Session;user id=sa;password=xxx"                                                  sessionIDManagerType="XXX.Frameworks.Configurations.SessionIDManager,XXX.Frameworks.Configurations"                                                                             timeout="30" />

 

换用之后,效果明显,到目前为止以经1个小时了,没有在出现ERRCA0012 这个错误。

 

上文中的 SessionIDManager 代码,仅供参考:

    public class SessionIDManager : ISessionIDManager {
        private SessionStateSection pConfig = null;
 
        public void Initialize() {
            if(pConfig == null) {
                var cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
                pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");
            }
        }
 
 
        public bool InitializeRequest(HttpContext context ,
                                      bool suppressAutoDetectRedirect ,
                                      out bool supportSessionIDReissue) {
 
            if(pConfig.Cookieless == HttpCookieMode.UseCookies) {
                supportSessionIDReissue = false;
                return false;
            } else {
                supportSessionIDReissue = true;
                return context.Response.IsRequestBeingRedirected;
            }
        }
 
         public string GetSessionID(HttpContext context) {
            string id = null;
 
            if(pConfig.Cookieless == HttpCookieMode.UseUri) {
                // Retrieve the SessionID from the URI.
            } else {
                var cookie = context.Request.Cookies[pConfig.CookieName];
                if(cookie != null)
                    id = context.Request.Cookies[pConfig.CookieName].Value;
            }
 
            // Verify that the retrieved SessionID is valid. If not, return null.
 
            if(!Validate(id))
                id = null;
 
            return id;
        }
 
        public string CreateSessionID(HttpContext context) {
            return Guid.NewGuid().ToString();
        }
 
        public void RemoveSessionID(HttpContext context) {
            context.Response.Cookies.Remove(pConfig.CookieName);
        }
 
        public void SaveSessionID(HttpContext context , string id , out bool redirected , out bool cookieAdded) {
            redirected = false;
            cookieAdded = false;
 
            if(pConfig.Cookieless == HttpCookieMode.UseUri) {
                // Add the SessionID to the URI. Set the redirected variable as appropriate.
 
                redirected = true;
                return;
            } else {
                context.Response.Cookies.Add(new HttpCookie(pConfig.CookieName , id) {
                    Domain = ConfigurationHelper.GetSection<Paths>().RootDomain.Path
                });
                cookieAdded = true;
            }
        }
 
        public bool Validate(string id) {
            try {
                Guid testGuid = new Guid(id);
 
                if(id == testGuid.ToString())
                    return true;
            } catch {
            }
 
            return false;
        }
    }

 

注意在方法 SaveSessionID 将 Session 的 Cookie 存到的是根域名下。这样可以解决因为二级域名带来的 Session 不能共享的问题。

 

另外:MBCA 结合 AppFabricCachingBPA 可以检查 AppFabric 缓存主机存在的问题。

 

另外,没有被吓倒的同志可以参考下:

Windows Server AppFabric 缓存容量规划指南

ASP.NET 4 缓存会话状态提供程序的配置设置(AppFabric 1.1 缓存)

应用程序配置设置(Windows Server AppFabric 缓存)

服务器不可用性疑难解答(Windows Server AppFabric 缓存)

错误代码字符串表(Windows Server AppFabric 缓存)

运行状况监控工具(Windows Server AppFabric 缓存)

 

我以心力交瘁,期待大神的指点

你可能感兴趣的:(session)