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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 原文:Session分布式共享 = Session + Redis + Nginx一、Session 1、Session 介绍       我相信,搞Web开发的对Session一定再熟悉不过了,所以我就简单的介绍一下。
原文: Session分布式共享 = 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原理不是本文介绍重点,所以请大家自行度娘。

image

 

2、又爱又恨的Session

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

【常见问题请见下图】

      image

      我相信一见到这个问题,老程序员都会心里一哆嗦,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(别问我怎么找到的,因为我英文过了四级,我会使用度娘,嘿嘿)

image

 

【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到最新。

imageimage

 

3、Redis安装

3-1、Redis for windows下载

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

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

image

!此处为坑,请注意!

     修改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

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

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

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

     1[6]

注意

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

image

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

image

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

 

三、Ngnix 


1、Ngnix安装&下载

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

2、nginx.conf配置修改

image

2-1、【接口修改】

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

image

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

upstream  Jq_one {  

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

 

image

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、拓扑图

image

         通过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上面。

2

 

 

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

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

3-1、现将Ip_Hash去掉

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

image

3-2、web.config添加MachineKey

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

【注意

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

3-3、演示

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

五、后记&感悟


   希望能通过本文,解决有的项目中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共享

非常感谢上述文章,对本文的启发,谢谢。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
9天前
|
NoSQL Java 关系型数据库
【Redis系列笔记】分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
139 2
|
9天前
|
存储 监控 NoSQL
【Redis】分布式锁及其他常见问题
【Redis】分布式锁及其他常见问题
37 0
|
9天前
|
NoSQL Java Redis
【Redis】Redis实现分布式锁
【Redis】Redis实现分布式锁
13 0
|
9天前
|
供应链 算法
基于分布式优化的多产消者非合作博弈能量共享(Matlab代码)
基于分布式优化的多产消者非合作博弈能量共享(Matlab代码)
|
9天前
|
算法 安全
基于价值认同的需求侧电能共享分布式交易策略(matlab完全复现)
基于价值认同的需求侧电能共享分布式交易策略(matlab完全复现)
|
9天前
|
监控 NoSQL 算法
探秘Redis分布式锁:实战与注意事项
本文介绍了Redis分区容错中的分布式锁概念,包括利用Watch实现乐观锁和使用setnx防止库存超卖。乐观锁通过Watch命令监控键值变化,在事务中执行修改,若键值被改变则事务失败。Java代码示例展示了具体实现。setnx命令用于库存操作,确保无超卖,通过设置锁并检查库存来更新。文章还讨论了分布式锁存在的问题,如客户端阻塞、时钟漂移和单点故障,并提出了RedLock算法来提高可靠性。Redisson作为生产环境的分布式锁实现,提供了可重入锁、读写锁等高级功能。最后,文章对比了Redis、Zookeeper和etcd的分布式锁特性。
149 16
探秘Redis分布式锁:实战与注意事项
|
9天前
|
NoSQL Java 大数据
介绍redis分布式锁
分布式锁是解决多进程在分布式环境中争夺资源的问题,与本地锁相似但适用于不同进程。以Redis为例,通过`setIfAbsent`实现占锁,加锁同时设置过期时间避免死锁。然而,获取锁与设置过期时间非原子性可能导致并发问题,解决方案是使用`setIfAbsent`的超时参数。此外,释放锁前需验证归属,防止误删他人锁,可借助Lua脚本确保原子性。实际应用中还有锁续期、重试机制等复杂问题,现成解决方案如RedisLockRegistry和Redisson。
|
9天前
|
缓存 NoSQL Java
【亮剑】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护,如何使用注解来实现 Redis 分布式锁的功能?
【4月更文挑战第30天】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护。基于 Redis 的分布式锁利用 SETNX 或 SET 命令实现,并考虑自动过期、可重入及原子性以确保可靠性。在 Java Spring Boot 中,可通过 `@EnableCaching`、`@Cacheable` 和 `@CacheEvict` 注解轻松实现 Redis 分布式锁功能。
|
9天前
|
NoSQL Redis 微服务
分布式锁_redis实现
分布式锁_redis实现
|
9天前
|
NoSQL Java Redis
Redis入门到通关之分布式锁Rediision
Redis入门到通关之分布式锁Rediision
22 0