net core+Redis+IIS+nginx实现Session共享
.Net Core Web Api实践(二).net core+Redis+IIS+nginx实现Session共享
前言:虽说公司app后端使用的是.net core+Redis+docker+k8s部署的,但是微信公众号后端使用的是IIS部署的,虽说公众号并发量不大,但领导还是使用了负载均衡,所以在介绍docker+k8s实现分布式Session共享之前,就先介绍一下IIS+nginx实现Session共享的方案,两者其实区别不大,所以这篇着重介绍方案,下篇介绍测试的区别以及填坑的方式。
1、环境准备
操作系统:Windows10
IIS:需要安装模块
VS2019、本地Redis数据库、ngnix(windows版)
2、Session共享的简易说明
下图简要说明了负载均衡通过轮询方式,将同一个客户端请求发送到不同的站点下,操作的Session应该是同一个。
3、添加测试项目
虽然个人认为本来WebApi中使用Session本身就是一种不合理的设计,但这是旧项目迁移需要保留的历史逻辑,所以只能硬着头皮寻找对应的解决方案了。
在VS2019中添加一个.net core 的WebApi项目,使用Session的话需要添加以下配置。
Startup.cs类中,ConfigureServices方法添加services.AddSession(); Configure方法中添加app.UseSession(); 注意要放到UseMVC方法前面。
测试代码如下,添加testController类,在Get1方法中设置Session,记录当前时间,Get2方法中读取Session
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
[Route( "[action]" )] [ApiController] public class testController : ControllerBase { // GET: api/test [HttpGet] public IEnumerable< string > Get() { return new string [] { "value1" , "value2" , HttpContext.Connection.LocalIpAddress.ToString(), HttpContext.Connection.LocalPort.ToString()}; } // GET: api/test/5 [HttpGet] public string Get1( int temp1) { if ( string .IsNullOrEmpty(HttpContext.Session.GetString( "qqq" ))) { HttpContext.Session.SetString( "qqq" , DateTime.Now.ToString()); } return HttpContext.Connection.LocalIpAddress.ToString() + "|" + HttpContext.Connection.LocalPort.ToString(); } [HttpGet] public string Get2( int temp1, int temp2) { return HttpContext.Connection.LocalIpAddress.ToString() + "|" + HttpContext.Connection.LocalPort.ToString() + "|" + HttpContext.Session.GetString( "qqq" ); } } |
4、发布.net core项目到IIS
(1)右键项目点击发布
(2)记录下发布路径,并在IIS中新增两个站点,指向该路径,并设置不同的端口号
记得把应用程序池中改为无托管代码
5、nginx配置负载均衡
下载地址:http://nginx.org/
配置方式:
(1)找到nginx的安装路径,打开nginx.conf文件
(2)添加upstream配置,配置用于负载均衡轮询的站点,即上一步骤中添加的两个站点
(3)配置location节点,注意proxy_pass与upstream中配置的名称保持一致。
(4)启动ngnix,用cmd命令指定nginx的安装目录,然后start nginx
6、在没有做Session共享方案的情况下进行测试
浏览器分别输入http://localhost:7665/Get1与http://localhost:7665/Get2,由于ip是一样的,所以没有参考必要,不停刷新http://localhost:7665/Get1,最后看到的端口号在7666与7667之间不停的来回切换,说明nginx的轮询是成功的。当然这里只是为了实现session共享做的负载均衡,所以把负载均衡放在了同一台服务器上进行配置,感兴趣的同学可以使用不同服务器配置负载均衡,并用压力测试工具测试站点在配置负载均衡的吞吐能力,后面有机会我可以单独介绍这部分内容。
测试结果:
1、过程: 请求http://localhost:7665/Get1,请求分发到站点7667,设置了Session;
请求http://localhost:7665/Get2,请求分发到站点7666,读取不到该Session;
再次请求Get2,请求分发到站点7667,可以读取到Session。
结论:说明负载均衡的两个站点之间不会读取同一个Session,也就是说Session不会共享。
2、 过程: 再次请求Get1,请求分发到站点7666;
再次请求Get2,请求分发到站点7667,读取不到该Session;
再次请求Get2,请求分发到站点7666,可以读取到Session,且session值被刷新。
结论:因为nginx每次都将请求分发到另外一站点,且session没有共享,所以string.IsNullOrEmpty(HttpContext.Session.GetString("qqq"))总是true,然后session都会被刷新,另一个站点的session就丢失了(这里的丢失应该是刷新session后产生了新的cookie值,导致原来的session无法读取,感兴趣的同学还可以用Fiddler跟踪记录下Get1产生cookie值,然后在Get2请求时带上cookie进行验证)。
7、使用Redis将Session存放在Redis服务器
(1)在Startup.cs文件中,ConfigureServices方法加入以下代码

services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false; //这里要改为false,默认是true,true的时候session无效
options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
}); services.AddDataProtection(configure =>
{
configure.ApplicationDiscriminator = "wxweb";
})
.SetApplicationName("wxweb")
.AddKeyManagementOptions(options =>
{
//配置自定义XmlRepository
options.XmlRepository = new SessionShare();
}); #region 使用Redis保存Session
// 这里取连接字符串
services.AddDistributedRedisCache(option =>
{
//redis 连接字符串
option.Configuration = Configuration.GetValue<string>("RedisConnectionStrings");
//redis 实例名
option.InstanceName = "Wx_Session";
}); //添加session 设置过期时长分钟
//var sessionOutTime = con.ConnectionConfig.ConnectionRedis.SessionTimeOut;
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(Convert.ToDouble(8 * 60 * 60)); //session活期时间
options.Cookie.HttpOnly = true;//设为httponly
});
#endregion

简要说明:
services.Configure<CookiePolicyOptions>是为了可以使用cookie
SetApplicationName("wxweb")是为了保证不同站点下的应用程序名称是一致的。
options.XmlRepository = new SessionShare();是为了保证不同站点下应用程序使用的machinekey是一样的,详情见https://www.cnblogs.com/newP/p/6518918.html
AddDistributedRedisCache是一个官方的拓展组件,用户将session保存在redis中。
RedisConnectionStrings是Redis连接字符串
(2)SessionShare的实现如下

public class SessionShare : IXmlRepository
{
private readonly string keyContent =
@"自己的machinekey"; public virtual IReadOnlyCollection<XElement> GetAllElements()
{
return GetAllElementsCore().ToList().AsReadOnly();
} private IEnumerable<XElement> GetAllElementsCore()
{
yield return XElement.Parse(keyContent);
}
public virtual void StoreElement(XElement element, string friendlyName)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
StoreElementCore(element, friendlyName);
} private void StoreElementCore(XElement element, string filename)
{
}
}

(3)再次进行发布
8、添加Session共享方案以后进行测试
测试结果:无论Get1刷新多少次,Get2都能拿到Session值,且Session没有被刷新(当前时间没有变化),即Session共享成功。
总结:以前总是看别人的文章了解Session共享,这次自己从配置负载均衡到解决Session共享从头到尾走了一遍,所以记录了下来。下篇文章我会介绍AddDistributedRedisCached在并发量较高时timeout的解决方案。
参考文章(同时感谢这些大佬的文章提供的帮助)
net core+Redis+IIS+nginx实现Session共享的更多相关文章
- .Net Core Web Api实践(二).net core+Redis+IIS+nginx实现Session共享
前言:虽说公司app后端使用的是.net core+Redis+docker+k8s部署的,但是微信公众号后端使用的是IIS部署的,虽说公众号并发量不大,但领导还是使用了负载均衡,所以在介绍docke ...
- nginx+tomcat+redis的集群+session共享
nginx+tomcat+redis的集群+session共享 环境准备 1.tomcat版本:tomcat7 tomcat下载及安装,目前很多好的资源和步骤,此处省略. 2.jdk版本:jdk1.7 ...
- nginx+tomcat+redis负载均衡及session共享
概述 本文档是用来详细描述 nginx+tomcat+redis负载均衡实现session共享 所需软件及下载地址 软件名称 下载地址 功能说明 Nginx-v1.6.0 http://nginx.o ...
- springboot+spring session+redis+nginx实现session共享和负载均衡
环境 centos7. jdk1.8.nginx.redis.springboot 1.5.8.RELEASE session共享 添加spring session和redis依赖 <depen ...
- SpringBoot2.x+Redis+nginx实现session共享和负载均衡
1.创建SpringBoot项目添加依赖 <dependency> <groupId>org.springframework.session</groupId> & ...
- 用Nginx实现Session共享的均衡负载
前言 大学三年多,也做个几个网站和APP后端,老是被人问到,如果用户多了服务器会不会挂,总是很尴尬的回答:“哈哈,我们的用户还少,到了服务器撑不住的时候,估计都上市了吧”.说是这么说,但是对于有强迫症 ...
- Nginx 分布式session共享问题
在集群的时候每次访问,都会被代理转到不同的服务器,那么在这些服务器之间如何共享session? 解决方式1:session复制 只能在window下好使,web服务器解决(广播机制,将一台机器上的se ...
- Redis安装及实现session共享
一.Redis介绍 1.redis是key-value的存储系统,属于非关系型数据库 2.特点:支持数据持久化,可以让数据在内存中保存到磁盘里(memcached:数据存在内存里,如果服务重启,数据会 ...
- memcache+tomcat7.0.37+nginx实现session共享
一.session工作原理 由于http是无状态的协议,当我们访问了页面A,然后访问页面B,http无法确定这2个页面的访问是来自同一个人.因此,我们要用cookie或session来跟踪用户,根据授 ...
随机推荐
- Springboot全局事务处理
什么是全局事务 Spring Boot(Spring)事务是通过aop(aop相关术语:通知(Advice).连接点(Joinpoint).切入点(Pointcut).切面(Aspect).目标(Ta ...
- 转:RBAC如何设计一个权限系统
前言 权限管理是所有后台系统的都会涉及的一个重要组成部分,主要目的是对不同的人访问资源进行权限的控制,避免因权限控制缺失或操作不当引发的风险问题,如操作错误,隐私数据泄露等问题.目前在公司负责权限这块 ...
- javascript 获取两点的像素距离
getPosLen(sdot, edot){//获取2点距离 /* 56 40 56 40 00 40 56 40 56 */ return parseInt(Math.sqrt(Math.pow(M ...
- Time-Frequency Networks For Audio Super-Resolution
论文题目:2018_用于音频超分辨率的时频网络 博客作者:凌逆战 博客地址:https://www.cnblogs.com/LXP-Never/p/12345950.html 摘要 音频超分辨率(即带 ...
- python 安装自己下载的whl依赖
下载好之后保存到相应的地方,如下载了xxxx.whl文件并将它保存在D:\python\project目录下,然后 pip install D:\python\project\xxxx.whl即可
- Leetcode面试题17.20_连续中值
题目地址 实现一个数列的动态添加和查询中位数. 复杂点的话应该可以写个平衡树什么的,然后查询第k大,还可以删除数字. 简单点的话显然可以维护两个堆,一个大顶堆一个小顶堆,而且大顶堆最多比小顶堆多一个, ...
- Jedis客户端即redis中的pipeline批量操作
关注公众号:CoderBuff,回复"redis"获取<Redis5.x入门教程>完整版PDF. <Redis5.x入门教程>目录 第一章 · 准备工作 第 ...
- Java 添加超链接到Excel文档
超链接即内容链接,通过给特定对象设置超链接,可实现载体与特定网页.文件.邮件.网络等的链接,点击链接载体可打开链接目标,在文档处理中是一种比较常用的功能.本文将介绍通过Java程序给Excel文档添加 ...
- 使用Nginx对.NetCore站点进行反向代理
前言 之前的博客我已经在Linux上部署好了.NetCore站点且通过Supervisor对站点进行了进程守护,同时也安装好了Nginx.Nginx的用处非常大,还是简单说下,它最大的功能就是方便我们 ...
- go实现java虚拟机02
上一篇通过flag包实现了命令行参数的解析,其实就是将输入的参数保存到一个结构体中,上一篇说过的例如java -classpath hello.jar HelloWorld这种命令,那么HelloWo ...