level 1
最近在做asp.netcore的分布式布署,网上查了很多资料,都是讲了一半,到关键点的时候没有讲清楚,本文将从头带你从头开始实现Session共享,能阅读本文需要你有一定的asp.netcore开发经验,有nginx及数据库使用经验,针对这些操作将会一笔带过。
一、新建项目。打开VS2019,新建一个asp.netcore的MVC项目。
1、要做Session共享,首先得使用Session,在Startup中注册并使用Session
首先需安装nuget包Microsoft.AspNetCore.Session方可使用session
另外,Session的使用需要用到Cookie的配置
在ConfigureServices中配置Cookie和Session
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 = SameSiteMode.None;
});
//添加session 设置过期时长分钟
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(Convert.ToDouble(20)); //session活期时间
options.Cookie.HttpOnly = true;//设为httponly
});
在Configure中使用Session
app.UseSession();
2、在分布式时,每台机的Session要保持同步,目前比较成熟的方式是将Session存在共享的服务器上,常见的有Redis、Memcache、Sqlserver、Ncache等,各有各的特点,本文讲Sqlserver。
使用Sqlserver保存Session,需要安装nuget包Microsoft.Extensions.Caching.SqlServer。
然后用dotnet sql-cache生成表,可以在程序包管理器控制台执行以下命令进行安装:dotnet sql-cache create "server=127.0.0.1;database=XXX;uid=user;Password=XXX" dbo global_cache
当然,如果没有安装dotnet sql-cache功能,也可以直接在数据库里建表,命令如下 :
CREATE TABLE[dbo].[global_cache](
[Id][nvarchar](449) NOT NULL,
[Value] [varbinary](max)NOT NULL,
[ExpiresAtTime] [datetimeoffset](7) NOT NULL,
[SlidingExpirationInSeconds] [bigint] NULL,
[AbsoluteExpiration] [datetimeoffset](7) NULL,
PRIMARY KEY CLUSTERED( [Id] ASC)
)
在ConfigureServices配置使用SqlServer存储Cache
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "server=127.0.0.1;database=XXX;uid=user;Password=XXX;";
options.SchemaName = "dbo";
options.TableName = "global_cache";
});
有了以上配置后,就可以把Session存储到SqlServer了
3、以上配置只是让到Session存到Sqlserver中,但如果布署多台机,会发现是无效的,需要配置应用使用相同的MachineKey,以便于让生成的SessionId一致,从而达到共享的目的,在asp.netcore中,是通过配置数据保护来实现的。
在ConfigureServices中配置数据保护
services.AddDataProtection(x => x.ApplicationDiscriminator ="session_application_name");
或者用这样的写法,效果是一样的
services.AddDataProtection().SetApplicationName("session_application_name");
其他地方的教程几乎都是配置到这里就结束了配置的操作,但布署后就会发现,通过Nginx反向代理后,访问A服务器上存入Session,在访问B服务器时相同的Key值就会失效。
经研究发现,还差一个PersistKeys没有配置所致,services.AddDataProtection()会反回一个IDataProtectionBuilder对像,通过此对像来配置PersistKeys,有以下几个重载,分别对应不同的位置,PersistKeysToFileSystem,PersistKeysToRegistry,这里用PersistKeysToFileSystem把Key存到文件,里面传入一个DirectoryInfo,首次启动时会生成一个key-XXX.xml的文件,记录了加密的信息。
把此文件复制到项目根目录中,然后配置此xml为始终复制,在发布时就会把此文件复制到发布目录中。
最后把PersistKeysToFileSystem参数的配置路径设为程序运行目录即可,如下所示
services.AddDataProtection()
.SetApplicationName("session_application_name")
.PersistKeysToFileSystem(new System.IO.DirectoryInfo(Environment.CurrentDirectory));
再次布署后就会发现Session可以共享了。
二、编写Session写入与读取的代码
新建Home控制器,加入入下代码
public IActionResult Add(string userName)
{
this.HttpContext.Session.SetString("UserName", userName);
return Content("MachineName:" + Environment.MachineName + Environment.NewLine + "Port:" + this.HttpContext.Connection.LocalPort + Environment.NewLine + "UserName:" + this.HttpContext.Session.GetString("UserName"));
//加上MachineName和Port以便于区分应用;
}
public IActionResult Index()
{
return Content("MachineName:" + Environment.MachineName + Environment.NewLine + "Port:" + this.HttpContext.Connection.LocalPort + Environment.NewLine + "UserName:" + this.HttpContext.Session.GetString("UserName"));
}
三、将用用布署到不同的服务器上,布署过程略。假设布署后的IP及端口如下:
server 192.168.1.2:999;
server 192.168.1.3:800;
四、配置Nginx,安装过程略,配置如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream cachetest{
server 192.168.1.2:999;
server 192.168.1.3:800;
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
proxy_pass http://cachetest;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
启动后试试效果吧
以上只是基础的配置,能够让整个系统运行起来,调优的部分以后有机会再写。
2021年07月04日 07点07分
1
一、新建项目。打开VS2019,新建一个asp.netcore的MVC项目。
1、要做Session共享,首先得使用Session,在Startup中注册并使用Session
首先需安装nuget包Microsoft.AspNetCore.Session方可使用session
另外,Session的使用需要用到Cookie的配置
在ConfigureServices中配置Cookie和Session
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 = SameSiteMode.None;
});
//添加session 设置过期时长分钟
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(Convert.ToDouble(20)); //session活期时间
options.Cookie.HttpOnly = true;//设为httponly
});
在Configure中使用Session
app.UseSession();
2、在分布式时,每台机的Session要保持同步,目前比较成熟的方式是将Session存在共享的服务器上,常见的有Redis、Memcache、Sqlserver、Ncache等,各有各的特点,本文讲Sqlserver。
使用Sqlserver保存Session,需要安装nuget包Microsoft.Extensions.Caching.SqlServer。
然后用dotnet sql-cache生成表,可以在程序包管理器控制台执行以下命令进行安装:dotnet sql-cache create "server=127.0.0.1;database=XXX;uid=user;Password=XXX" dbo global_cache
当然,如果没有安装dotnet sql-cache功能,也可以直接在数据库里建表,命令如下 :
CREATE TABLE[dbo].[global_cache](
[Id][nvarchar](449) NOT NULL,
[Value] [varbinary](max)NOT NULL,
[ExpiresAtTime] [datetimeoffset](7) NOT NULL,
[SlidingExpirationInSeconds] [bigint] NULL,
[AbsoluteExpiration] [datetimeoffset](7) NULL,
PRIMARY KEY CLUSTERED( [Id] ASC)
)
在ConfigureServices配置使用SqlServer存储Cache
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "server=127.0.0.1;database=XXX;uid=user;Password=XXX;";
options.SchemaName = "dbo";
options.TableName = "global_cache";
});
有了以上配置后,就可以把Session存储到SqlServer了
3、以上配置只是让到Session存到Sqlserver中,但如果布署多台机,会发现是无效的,需要配置应用使用相同的MachineKey,以便于让生成的SessionId一致,从而达到共享的目的,在asp.netcore中,是通过配置数据保护来实现的。
在ConfigureServices中配置数据保护
services.AddDataProtection(x => x.ApplicationDiscriminator ="session_application_name");
或者用这样的写法,效果是一样的
services.AddDataProtection().SetApplicationName("session_application_name");
其他地方的教程几乎都是配置到这里就结束了配置的操作,但布署后就会发现,通过Nginx反向代理后,访问A服务器上存入Session,在访问B服务器时相同的Key值就会失效。
经研究发现,还差一个PersistKeys没有配置所致,services.AddDataProtection()会反回一个IDataProtectionBuilder对像,通过此对像来配置PersistKeys,有以下几个重载,分别对应不同的位置,PersistKeysToFileSystem,PersistKeysToRegistry,这里用PersistKeysToFileSystem把Key存到文件,里面传入一个DirectoryInfo,首次启动时会生成一个key-XXX.xml的文件,记录了加密的信息。
把此文件复制到项目根目录中,然后配置此xml为始终复制,在发布时就会把此文件复制到发布目录中。
最后把PersistKeysToFileSystem参数的配置路径设为程序运行目录即可,如下所示
services.AddDataProtection()
.SetApplicationName("session_application_name")
.PersistKeysToFileSystem(new System.IO.DirectoryInfo(Environment.CurrentDirectory));
再次布署后就会发现Session可以共享了。
二、编写Session写入与读取的代码
新建Home控制器,加入入下代码
public IActionResult Add(string userName)
{
this.HttpContext.Session.SetString("UserName", userName);
return Content("MachineName:" + Environment.MachineName + Environment.NewLine + "Port:" + this.HttpContext.Connection.LocalPort + Environment.NewLine + "UserName:" + this.HttpContext.Session.GetString("UserName"));
//加上MachineName和Port以便于区分应用;
}
public IActionResult Index()
{
return Content("MachineName:" + Environment.MachineName + Environment.NewLine + "Port:" + this.HttpContext.Connection.LocalPort + Environment.NewLine + "UserName:" + this.HttpContext.Session.GetString("UserName"));
}
三、将用用布署到不同的服务器上,布署过程略。假设布署后的IP及端口如下:
server 192.168.1.2:999;
server 192.168.1.3:800;
四、配置Nginx,安装过程略,配置如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream cachetest{
server 192.168.1.2:999;
server 192.168.1.3:800;
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
proxy_pass http://cachetest;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
启动后试试效果吧
以上只是基础的配置,能够让整个系统运行起来,调优的部分以后有机会再写。