MVC如何使用Memcache+Cookie解决分布式系统共享登录状态的问题
创始人
2024-11-28 08:22:04
0次

      为了解决单机处理的瓶颈,增强软件的可用性,我们需要将软件部署在多台服务器上启用多个二级子域名以频道化的方式,根据业务功能将网站分布部署在独立的服务器上,或通过负载均衡技术(如:DNS轮询、Radware、F5、LVS等)让多个频道共享一组服务器。当我们将网站程序分部到多台服务器上后,由于Session受实现原理的局限,无法跨服务器同步更新Session,使得登录状态难以通过Session共享。

      我们使用MemCache+Cookie方案来解决分布式系统共享登录状态的问题。

      Memcache服务器本身就是一个Socket服务端,内部数据采用键值对的形式存储在服务器的内存中,本质就是一个大型的哈希表。数据的删除采用惰性删除机制。虽然Memcache并没有提供集群功能,但是通过客户端的驱动程序很容易就可以实现Memcache的集群配置。

     先简单介绍一下Memcache的用法

1. 下载安装Memcache(Windows平台)

    (1)将程序解压到磁盘任意位置

    (2)进入cmd窗口,运行Memcached.exe -d install安装服务,安装后打开服务窗口查看服务是否安装成功。

MVC如何使用Memcache+Cookie解决分布式系统共享登录状态的问题

    (3)直接在服务管理中启动服务,或者使用cmd命令 net start "Memcache Server"

    (4)使用Telnet连接到Memcache控制台,验证服务是否正常 telnet 127.0.0.1 11211

            使用stats指令查看当前Memcache服务器状态

MVC如何使用Memcache+Cookie解决分布式系统共享登录状态的问题

2. 程序中的用法

    (1)在程序中添加 Memcached.ClientLibrary.dll 的引用

    (2)C#中操作Memcache的代码示例

String[] serverlist = { "192.168.1.100:11211",
"192.168.1.101:11211" };
// initialize the pool for memcache servers
SockIOPool pool = SockIOPool.GetInstance("test");
pool.SetServers(serverlist);
pool.Initialize();
mc = new MemcacheClient();
mc.PoolName = "test";
mc.EnableCompression = false;
pool.Shutdown();//关闭连接池

下面我们做方案的具体实现

1. 首先在Common层中引入Memcached.ClientLibrary.dll,并封装Memcache的帮助类,MemcacheHelper

using Memcached.ClientLibrary;
using System;

namespace PMS.Common
{
 public class MemcacheHelper
 {
 private static readonly MemcachedClient Mc = null;

 static MemcacheHelper()
 {
 //最好放在配置文件中
 string[] serverlist = { "127.0.0.1:11211", "10.0.0.132:11211" };

 //初始化池
 var pool = SockIOPool.GetInstance();
 pool.SetServers(serverlist);

 pool.InitConnections = 3;
 pool.MinConnections = 3;
 pool.MaxConnections = 5;

 pool.SocketConnectTimeout = 1000;
 pool.SocketTimeout = 3000;

 pool.MaintenanceSleep = 30;
 pool.Failover = true;

 pool.Nagle = false;
 pool.Initialize();

 // 获得客户端实例
 Mc = new MemcachedClient {EnableCompression = false};
 }
 /// 
 /// 存储数据
 /// 
 /// 
 /// 
 /// 
 public static bool Set(string key,object value)
 {
 return Mc.Set(key, value);
 }
 public static bool Set(string key, object value,DateTime time)
 {
 return Mc.Set(key, value,time);
 }
 /// 
 /// 获取数据
 /// 
 /// 
 /// 
 public static object Get(string key)
 {
 return Mc.Get(key);
 }
 /// 
 /// 删除
 /// 
 /// 
 /// 
 public static bool Delete(string key)
 {
 return Mc.KeyExists(key) && Mc.Delete(key);
 }
 }
}

2. 改变用户登录方法UserLogin,用户登录成功后生成GUID,将此GUID存入Cookie并以GUID为键将登录用户信息序列化存入Memcache服务器。

public ActionResult UserLogin()
{
 #region 验证码校验
 var validateCode = Session["validateCode"] != null ? Session["validateCode"].ToString() : string.Empty;
 if (string.IsNullOrEmpty(validateCode))
 return Content("no:验证码错误!!");
 Session["validateCode"] = null;
 var txtCode = Request["ValidateCode"];
 if (!validateCode.Equals(txtCode, StringComparison.InvariantCultureIgnoreCase))
 return Content("no:验证码错误!!");
 #endregion

 var userName = Request["UserName"];
 var userPwd = Request["PassWord"];
 //查询用户是否存在
 var user = UserService.LoadEntities(u => u.UserName == userName && u.PassWord == userPwd).FirstOrDefault();
 if (user == null) return Content("no:登录失败");

 //产生一个GUID值作为Memache的键.
 var sessionId = Guid.NewGuid().ToString();
 //将登录用户信息存储到Memcache中。
 MemcacheHelper.Set(sessionId, SerializeHelper.SerializeToString(user), DateTime.Now.AddMinutes(20));
 //将Memcache的key以Cookie的形式返回给浏览器。
 Response.Cookies["sessionId"].Value = sessionId;
 return Content("ok:登录成功");
}

3. 改变登录校验控制器FilterController的OnActionExecuting方法,使其校验方式改为从Memcache服务器中读取Cookie中值为键的对象:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
 base.OnActionExecuting(filterContext);
 //if (Session["user"] == null)
 if (Request.Cookies["sessionId"] != null)
 {
 var sessionId = Request.Cookies["sessionId"].Value;
 //根据该值查Memcache.
 var obj = MemcacheHelper.Get(sessionId);
 if (obj == null)
 {
 filterContext.Result = Redirect("/Login/Index");
 return;
 }
 var user = SerializeHelper.DeserializeToObject(obj.ToString());
 LoginUser = user;
 //模拟出滑动过期时间.
 MemcacheHelper.Set(sessionId, obj, DateTime.Now.AddMinutes(20)); 
 }
 else
 filterContext.Result = Redirect("/Login/Index");
}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...