在上一篇博文中我们通过Nginx+IIS实现了一个简单的负载均衡,那么随之而来的问题就是多个站点在切换时如何共享Session信息,本篇介绍在.net中通过Redis实现分布式站点的Session共享,并且无需修改原项目的Session读取方式。
ASP.Net session存储方式
首先我们看下asp.net中session能采用的存储方式及优缺点。如下:
- InProc模式(进程内模式) ,为默认设置。优点是性能高无需跨进程读取,缺点是依赖asp.net进程,当进程崩溃重启时会丢失,并且在分布式的情况下无法多个站点共享。
- StateServer模式(状态服务器模式)。会话状态存储在一个名为ASP.Net状态服务的单独进程中,这确保了在重新启动Web应用程序时会保留会话状态,并让会话状态可用于网络中的多个Web服务器。
- SQL Server模式。会话状态存储到一个SQL Server数据库中。这确保了在重新启动Web应用程序时会保留会话状态,并让会话状态可用于网络中的多个Web服务器。
- Custom模式。此模式允许您指定自定义存储提供程序,例如分布式中常采用自定义模式将站点Session存储在Redis或Memcached中。
本篇即采用Custom模式自定义存储提供程序将Session存储在Redis中。
Redis存储Session
采用Custom模块需要修改web.config配置文件中网站的sessionState节点的mode属性为Custom,另外我们需要写一个类实现SessionStateStoreProviderBase抽象类,通过实现抽象类的方法可以对Session自定义增删查改,目前微软已经有Redis存储的实现版本了,直接nuget安装RedisSessionStateProvider包即可,如下:
sessionState中将redis配置改为Redis服务器连接配置,然后我们新建一个mvc视图来测试多个站点下的Session读取和共享。Controler代码如下:
public class HomeController : Controller
{
public ActionResult Index()
{
if (this.HttpContext.Session["MySessionTest"] == null)
{
this.HttpContext.Session["MySessionTest"] = string.Format("站点{0}创建的Session", Request.ServerVariables.Get("Server_Port").ToString());
}
return View();
}
public JsonResult GetSession()
{
var result = this.HttpContext.Session["MySessionTest"].ToString();
return Json(new { isok = true, result = result }, JsonRequestBehavior.AllowGet);
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
在index action中我们写入了一个key=MySessionTest的session信息,并且将站点端口信息写入到了值中,然后提供了一个接口方法用来读取并返回session[“MySession”]。然后我们看下视图页面代码:
<div class="jumbotron">
<h1>ASP.NET</h1>
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
<h3>
服务器地址:@Request.ServerVariables.Get("Server_Name").ToString()
</h3>
<h3>
服务器端口:@Request.ServerVariables.Get("Server_Port").ToString()
</h3>
<div>
<input id="sessiontxt" /> <button onclick="GetSession()">读取Session["MySessionTest"]</button>
</div>
</div>
function GetSession() {
$.ajax({
type: "GET",
url: "/Home/GetSession",
xhrFields: { withCredentials: true },
success: function (data) {
if (data.isok == true) {
$("#sessiontxt").val(data.result);
}
}
});
}
功能很简单,显示当前站点的地址及端口信息,点击按钮会调用接口读取session信息并输出到文本框中。现在我们做一个测试,我们在IIS上新建三个站点8010/8020/8030都指向这个网站,然后我们分别访问三个网站查看session获取结果如下:
可以看到我们先访问的8010网站,session在进入8010网站的时候创建了session,在访问8020网站点击按钮获取session时获取到的session和8010是相同的,至此我们已经实现了多个站点的Session共享。配合我在上一篇博文中讲的负载均衡就实现了分布式系统各个web站点之间的session共享了。
上一篇:Nginx+IIS实现负载均衡