Session + Redis + Nginx

一、Session


1、Session 介绍

我相信,搞Web开发的对Session一定再熟悉不过了,所以我就简单的介绍一下。

Session:在计算机中,尤其是在网络应用中,称为“会话控制”。 每个用户(浏览器)首次与web服务器建立连接时,就会产生一个Session,同时服务器会分配一个SessionId给用户的浏览器。我们可以用Fiddler查看cookies中,会看到有一个ASP.Net_SessionId的cookie。大家都知道Http是无状态请求,但是ASP.Net中的Session仿佛又让Http请求变得有状态,其核心就在于这个叫ASP.Net_SessionId的cookie。大家可以想象一下,这个相当于数据库的Key,服务器那边再有个Session内容缓存表,是不是Session的内容就很容易得到了?当然Session不是那么简单,但Session原理不是本文介绍重点,所以请大家自行度娘。

2、又爱又恨的Session

刚接触程序开发的人一定爱死Session了,因为Session让Http从无状态变成有状态了,页面之间传值、用户相关信息、一些不变的数据、甚至于查出来的DataTable也可以放进去,取值的时候只需要Session[Key]即可,真是方便极了。Session真是个利器,人挡杀人佛挡杀佛,但任何事物被封为利器基本也是双刃剑,Session的许多问题我们不得不去面对。

【常见问题请见下图】

我相信一见到这个问题,老程序员都会心里一哆嗦,Session是导致这个原因之一,大家也会想到这个情景,“我去,是不是Session又丢了,让用户重新登录”,事故报告中会填写:.NET规定,用户登陆后长时间没操作导致的。解决方案为:把Session时间调到9999。

结果该发生的还是继续发生着,Session照样丢失。

常见Session丢失原因】

1、Session超时,用户打开页面,页面长时间不操作会导致此原因

2、IIS应用程序池回收,或者重启

3、Web.Config修改,即IIS应用程序池重启

4、dll被替换或者动态页面修改,即IIS应用程序池重启

5、杀毒软件对.config文件进行扫描,可能会导致IIS应用程序池回收

6、用户浏览器禁用cookie

7、其他原因

其他原因有点不负责,但是好多程序员无法查明是什么原因导致Session丢失,但Session丢失我归结为两大类,一个是数据的Key丢了,一个是Session内容数据库的丢了,大家这样就好理解了,用户浏览器禁用cookie一定是Key没了。IIS应用程序池回收必定会导致Session的内容缓存表丢失,当然还有一些其他原因。

3、解决Session丢失的漫长路

解决过Session丢失的都会用到这几种方法

1、InProc:将Session存到进程内。

2、StateServer:将Session存到独立的状态服务中(Asp.Net State Service)。

3、SqlServer:将Session存到SqlServer中。

4、Cookieless:设置客户端Session存储的方式。

用了这些方法之后,有的是该丢还丢,有的是稳定了速度却慢了。

大家也注意到了,还有个这个Custom自定义模式,有人会说:“除了大牛,有几个敢写的啊,写出来有问题怎么办,算了算了。” 等等,大家不要还停留在非开源模式下解决问题的思想,找找开源项目,一定能找到的,有人说ASP.NET上哪里找开源啊,非常简单NuGet,如果想了解开源,一定要学会使用NuGet。

二、Redis


1、前言 

上文说了那么多,有人一定会说我是来解决Session丢失的,上哪里来的Session分布式共享,标题党,我还是继续用我的cookie吧。

我要说的是,几年前,在Stack Overflow上找到了这个方法解决了丢失问题,之后,发现这种方法还可以实现Session分布式共享。那就是运用Custom自定义模式,将Session持久化到Memcache和Redis中。Session丢失、以及持久化到SqlServer数据的性能问题也随之解决。

此种方法很适合老项目中大量应用Session而导致法搞成分布式而苦恼的.NET开发人员使用。因为很有可能老项目维护过程中,身边的JAVA团队、PHP团队,正在重构你的项目。

2、RedisSessionProvider

正文开始,首先,沿着我们的思路Session持久化到Memcache或者Redis中,通过nuget下载 RedisSessionProvider(别问我怎么找到的,因为我英文过了四级,我会使用度娘,嘿嘿)

【web.config配置如下】

<system.web>
<sessionState mode="Custom" customProvider="RedisSessionProvider">
<providers>
<add name="RedisSessionProvider" type="RedisSessionProvider.RedisSessionStateStoreProvider, RedisSessionProvider"/>
</providers>
</sessionState>
</system.web>

【Global.asax】

    void Application_Start(object sender, EventArgs e)
{ StackExchange.Redis.ConfigurationOptions redisConfigOpts = StackExchange.Redis.ConfigurationOptions.Parse("192.168.8.138:6379");
RedisSessionProvider.Config.RedisConnectionConfig.GetSERedisServerConfig = (HttpContextBase context) =>
{
return new KeyValuePair<string, StackExchange.Redis.ConfigurationOptions>(
"DefaultConnection",
redisConfigOpts);
}; }

【存储方法】

   Session["Test"] = "aa";

【调用方法】

   string str = Session["Test"].ToString()

!前方坑,请注意!

如果你配置好Redis,并且做好上面这些配置,运行会出现以下问题,请更新RedisSessionProvider的依赖包StackExchange.Redis到最新。

3、Redis安装

3-1、Redis for windows下载

如果会配置Redis的同学,请略过此章节,直接进入Nginx。

Redis下载:https://github.com/MSOpenTech/redis

!此处为坑,请注意!

修改Redis.windows.conf,如果不修改,远程不能访问Redis

     1、将bind 127.0.0.1 改成了bind 0.0.0.0。注意:进入生产环境时候,要启用密码,否则会是Redis漏洞,具体请自行度娘和自己公司的运维阿牛

2protected-mode yes 改成 protected-mode no

详细修改的传送门: redis开启远程访问

3-2、启动Redis

redis-server redis.windows.conf

     上图为redis启动成功,默认6379,可以通过redis-cli进行测试,看别的机子能否访问。还可以在找个redis可视化工具看看里面存了啥,也可以监控Session是否持久化到Redis中了。

3-3、验证Session是否持久化到Redis

运行RedisSessionProvider这个项目。同一个IIS下,同域名,不同IP,同一浏览器,不同端口一个是2459,一个是2490。

注意

不同浏览器SessionId是不同的。必须保证SessionId,测试必须是同一个浏览器进程分出的不同子标签才可以,这样SessionId是共享的。

感觉成功了,让我们看看这样的拓扑图:

囧……这是啥玩意?我的分布式呢?这个拓扑图很显然不是分布式啊,还两个IP,我还要在前面做个路由登录页面?这时Nginx该登场了。

三、Ngnix 


1、Ngnix安装&下载

下载地址:http://nginx.org/

2、nginx.conf配置修改

2-1、【接口修改】

       listen   80; 改成  listen   1100; 因为一般都被80都被使用。

2-2、【增加负载均衡】

upstream  Jq_one {  

     server 127.0.0.1:8770;
server 192.168.8.138:7777;
}
server {
.....
}

2-3、【location节点修改】

location / {
root html;
index index.aspx index.html index.htm;
#其中jq_one 对应着upstream设置的集群名称
proxy_pass http://Jq_one;
#设置主机头和客户端真实地址,以便服务器获取客户端真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

2-4、【Nginx启动命令】

C:\server\nginx-1.0.2>start nginx

C:\server\nginx-1.0.2>nginx.exe

2-5、【Nginx重新载入命令】

C:\server\nginx-1.0.2>nginx.exe -s reload

2-6、【参考文章】

详细配置传送门:nginx+iis实现负载均衡

四、Session分布式共享

1、拓扑图

通过Nginx+Redis实现对Session的分布式共享功能。通过测试,发现Session分布式共享共有两种解决方案。

2、利用Nginx的Ip_Hash进行Session分布式共享

使用nginx将同一ip的请求分配到固定服务器,修改如下。ip_hash会计算ip对应hash值,然后分配到固定服务器

upstream Jq_one{
server 127.0.0.1:8770;
     server 192.168.8.138:7777;
     ip_hash;
}

效果可以理解为就是一个Ip,通过Nginx路由到IIS_1上面,在多次请求,会一直在IIS_1上,不会路由到IIS_2上面。

3、利用MachineKey进行Session分布式共享

Ip_Hash在一定程度上解决了Session分布式共享的问题,但是总感觉没有发挥出nginx均衡负载的功能,继续改造

3-1、现将Ip_Hash去掉

    去掉Ip_Hash重启Nginx,打开网站,点击设置Session按钮,结果报错

3-2、web.config添加MachineKey

<machineKey
validationKey="86B6275BA31D3D713E41388692FCA68F7D20269411345AA1C17A7386DACC9C46E7CE5F97F556F3CF0A07159659E2706B77731779D2DA4B53BC47BFFD4FD48A54"
decryptionKey="9421E53E196BB56DB11B9C25197A2AD470638EFBC604AC74CD29DBBCF79D6046"
validation="SHA1"
decryption="AES"
/>

【注意

负载均衡的两个网站的MachineKey必须一样,否则出问题。

3-3、演示

下图,大家可以看到,服务器的Ip在不断变化,而Session却没有丢失,至此实现了Session分布式共享。

五、后记&感悟


希望能通过本文,解决有的项目中Session分布式共享和Session丢失的难题,给大家一些解决问题、分析问题启发。

ASP.Net给我们带来了新的一种编码体验,如今.Net已经15岁了,.Net的在企业中发展中扮演最多的角色是快枪手和背锅侠的角色,在企业刚起步时候选择易上手的.Net无非是最好的选择之一,但是因为.Net的高度封装,让.Net高级人才在市场上十分稀少,而且企业在创立之初应用.net的时候也不会考虑架构之类的问题。可是随着业务越来越复杂,.Net开发人员无法解决和满足市场的需求和项目中出现的技术难题,技术债随之产生,解决不了问题随之一些程序员便让.Net背锅,再加上.Net的新技术推陈出新(有好多人说微软瞎折腾,囧),WebForm、mvc、silverlight、sharepoint、wpf、window phone、wcf等等。可是中国大环境并不买账,慢慢成长的企业发现.Net现有架构无法满足,.Net开发人员又无法解决现有问题,又找不到.Net架构师之类的角色,又看到了京东等大厂转JAVA的成功,其他企业家便会想咱也转个JAVA试试,招聘Java架构师,结果一大堆人应聘(高级的、中级的、技术总监),企业家高兴坏了,很快JAVA便组建了一支精英团队准备重构.net项目。JAVA发展的历史比Net要长很多,早些做JAVA开发早已转型为管理,你会发现现在市场上,挖过来的其中一些CTO很喜欢组建JAVA、PHP团队,NET团队很少,原因多数是.Net不开源、不跨平台、解决方案不成熟,背后的原因就不得而知了。但不得不说,JAVA语言很容易培养牛人,因为当你学了JAVA中的Spring,你就开始接触了IOC容器,你就在慢慢的面向接口编程,当你学会了的AOP,你就开始在面向方面编程的道路上迈出了一小步。语言只是一个工具,干了这么多年.Net,看看招聘信息或多或少有了些迷茫,路是自己走的,做出的决定就不能后悔,但在十字路口时,还是多想一想。

以上为个人观点,有可能因为知识和阅历的原因,分析片面,请多谅解。

六、参考文章

redis开启远程访问

nginx+iis实现负载均衡

ASP.NET性能优化之分布式Session

.Net分布式架构(一):Nginx实现负载均衡

.Net分布式架构(二):基于Redis的Session共享

Session Redis Nginx的更多相关文章

  1. Session分布式共享 = Session + Redis + Nginx

    一.Session 1.Session 介绍 我相信,搞Web开发的对Session一定再熟悉不过了,所以我就简单的介绍一下. Session:在计算机中,尤其是在网络应用中,称为"会话控制 ...

  2. springboot+spring session+redis+nginx实现session共享和负载均衡

    环境 centos7. jdk1.8.nginx.redis.springboot 1.5.8.RELEASE session共享 添加spring session和redis依赖 <depen ...

  3. Session分布式共享 = Session + Redis + Nginx(转)

    出处:http://www.cnblogs.com/newP/p/6518918.html 一.Session 1.Session 介绍 我相信,搞Web开发的对Session一定再熟悉不过了,所以我 ...

  4. Nginx+Tomcat搭建集群,Spring Session+Redis实现Session共享

    小伙伴们好久不见!最近略忙,博客写的有点少,嗯,要加把劲.OK,今天给大家带来一个JavaWeb中常用的架构搭建,即Nginx+Tomcat搭建服务集群,然后通过Spring Session+Redi ...

  5. 基于Spring Boot/Spring Session/Redis的分布式Session共享解决方案

    分布式Web网站一般都会碰到集群session共享问题,之前也做过一些Spring3的项目,当时解决这个问题做过两种方案,一是利用nginx,session交给nginx控制,但是这个需要额外工作较多 ...

  6. Spring boot配合Spring session(redis)遇到的错误

    背景:本MUEAS项目,一开始的时候,是没有引入redis的,考虑到后期性能的问题而引入.之前没有引用redis的时候,用户登录是正常的.但是,在加入redis支持后,登录就出错!错误如下: . __ ...

  7. 单点登录实现(spring session+redis完成session共享)

    一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...

  8. Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程

    待解决的问题 Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程 解决办法 为spring session添加spr ...

  9. .NetCore Session.Redis

    首先创建ASP.NET CORE Web项目,然后按如下顺序操作.1.添加nuget程序包: Microsoft.AspNetCore.Session; Microsoft.AspNetCore.Da ...

随机推荐

  1. NSAttributeString创建各种文字效果

    NSDictionary *attributes =@{ NSForegroundColorAttributeName: [UIColorredColor], NSFontAttributeName: ...

  2. 【习题 3-11 UVA - 1588】Kickdown

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟一下就好 一位一位地往右移动. [代码] #include <bits/stdc++.h> using namesp ...

  3. [D3] Build a Scatter Plot with D3 v4

    Scatter plots, sometimes also known as bubble charts, are another common type of visualization. They ...

  4. ArcEngine数据删除几种方法和性能比较

    转自原文 ArcEngine数据删除几种方法和性能比较 一.  几种删除方法代码 1.  查询结果中删除 private void Delete1(IFeatureClass PFeatureclas ...

  5. 使用RxPermissions(基于RxJava2)

    使用RxPermissions(基于RxJava2) 0. 背景 Android 6.0 (API level 23)中.将权限分成了两类.一类是Install权限(称之为安装时权限).还有一类是Ru ...

  6. 事件处理之一:两种方式:监听器与回调 分类: H1_ANDROID 2013-10-31 10:26 3250人阅读 评论(0) 收藏

    Android组件的事件处理有2种方式: 1.基于监听器的事件处理方式:先定义组件,然后为组件设定监听器. 详见http://blog.csdn.net/jediael_lu/article/deta ...

  7. JQuery中Ajax详细参数使用案例

    JQuery中Ajax详细参数使用案例 参考文档:http://www.jb51.net/shouce/jquery1.82/ 参考文档:http://jquery.cuishifeng.cn/jQu ...

  8. Android自己主动检測版本号及自己主动升级

    步骤: 1.检測当前版本号的信息AndroidManifest.xml-->manifest-->android:versionName. 2.从server获取版本号号(版本号号存在于x ...

  9. js课程 1-3 Javascript变量类型详解

    js课程 1-3  Javascript变量类型详解 一.总结 一句话总结:js对象点(属性方法),json对象冒号(属性方法).属性和方法区别只有一个括号. 1.json对象中的函数的使用? 函数名 ...

  10. nopCommerce 3.9 大波浪系列 之 使用部署在Docker中的Redis缓存主从服务

    一.概述 nop支持Redis作为缓存,Redis出众的性能在企业中得到了广泛的应用.Redis支持主从复制,HA,集群. 一般来说,只有一台Redis是不可行的,原因如下: 单台Redis服务器会发 ...