首页 > 代码库 > Memcache+cookie实现模拟session
Memcache+cookie实现模拟session
上一片讲到Memcached在Windows上的安装,和用Telnet工具进行命令操作,在稍微了解了原理之后,我也就开始尝试着用程序来对Memcached进行操作。这一篇分为两个部分,第一部分是用.net程序对Memcached进行操作,第二部分是结合mvc实现一个分布式的缓存系统。
一、.net程序对Memcached进行操作
想要用.net操作Memcached,首先我们的去下载.NET客户端类库:https://sourceforge.net/projects/memcacheddotnet,下载完成之后,会发现里面有一些Demo,而需要引用的程序集就只有ICSharpCode.SharpZipLib.dll,Memcached.ClientLibrary.dll,log4net.dll(可有可无)。
上图就是创建了一个控制台应用程序,将这三个程序集引入项目。之后,将Memcached服务打开。再之后,就是代码。
string[] serverlist = { "127.0.0.1:11211" }; SockIOPool sock = SockIOPool.GetInstance(); sock.SetServers(serverlist);//添加服务器列表 sock.InitConnections = 5;//设置连接池初始数目 sock.MinConnections = 3;//设置最小连接数目 sock.MaxConnections = 6;//设置最大连接数目 sock.SocketTimeout = 3000;//设置套接字超时读取 sock.MaintenanceSleep = 30; //设置维护线程运行的睡眠时间。如果设置为0,那么维护线程将不会启动; sock.Failover = true; //获取或设置池的故障标志。 sock.MaxBusy = 1000 * 10; //socket单次任务的最大时间(单位ms),超过这个时间socket会被强行中断,当前任务失败 sock.Initialize(); MemcachedClient mc = new MemcachedClient(); //清除所有的缓存数据 mc.FlushAll(); //增加 mc.Add("k","hello"); //增加一个键k1,值是hello1,有效时间是30s mc.Add("k1", "hello1", DateTime.Now.AddSeconds(30)); // 将k的值重新设置为123 ,用set时,假如键存在,就直接修改,键不存在,就直接创建,再赋值 mc.Set("k","123"); //将k的值重置为456 , 用Replace时,假如键存在,就直接修改,键不存在,报错 mc.Replace("k", "456"); //删除 mc.Delete("k");
到这里,我们用程序操作Memcached已经成功,我们程序运行完成之后,可以用telnet链接,看看数据是否加载进去了。这个比较简单,下面看个复杂点的。
二、Memcache+cookie实现模拟session
1.session的使用原理
以前在开发系统中,像用户这些基本信息,是直接保存在session中的,原理就是如下图所示,用户第一次访问时,服务器创建session,并把sessionid写回浏览器的cookie中,之后,浏览器每次访问服务器时,就把这个sessionid一同和其他数据发送到服务器端,这样就解决了Http协议是无状态链接这个问题了。简单原理就是这样,更加详细的session介绍详见http://www.cnblogs.com/lyzg/p/6067766.html(图也是人家的*-*)。
2.Memcache+cookie代替session
总的来说,session也不是完美的,会有易丢失,耗资源,单台服务器时还好,一遇到集群,就有点尴尬了,所以现在就模拟一下这个情况。这个例子的整体结构是这样子,搭建两个web服务器,同样也搭建两个Memcached服务器,好吧,双集群。
1-6这个过程是,当用户从web1站点登陆,先去查询Memcached集群里是否有用户信息,这个肯定没有,之后就去数据库查,查到之后,就把用户的信息给存到Memcached中,具体存到哪个,这个先不做谈论。
7-10过程,用户通过web2站点 访问数据,先去Memcached集群里查是否有信息(这个如何查的也先不做谈论),查到后,就直接把信息返回。
接下来,我们就新建项目,添加引用,项目的结构如图所示,一个mvc4的框架,数据库链接用的是dapper。项目用了过滤器,写在BaseController里面,并且在Global.asax文件里要进行注册,其中UserLoginController没有继承BaseController,HomeController继承了BaseController。
重要的代码有两段,一段就是登陆时候成功后,用guid生成随机数,将这个随机数作为seeionid写到浏览器的cookie中,同时把该用户的信息,sessionid这些信息存到Memcached中。
string sql = "select * from UserInfo where UName=@UName and UPwd=@UPwd"; using (var conn = SqlHelper.Connection) { var loginUser1 = conn.QueryFirstOrDefault<UserInfo>(sql, new { UName = user.UName, UPwd = user.UPwd }); var loginUser = SqlMapper.QueryFirstOrDefault<UserInfo>(conn,sql, new { UName = user.UName, UPwd = user.UPwd }); if (loginUser == null) { return Content("用户名密码错误!"); } else { Guid sessionId = Guid.NewGuid();//申请了一个模拟的GUID:SessionId //把sessionid写到客户端浏览器里面去了(一定要把sessionid写到客户端,这样用户在访问其他web资源的时候,
// 就会把cookie中的信息传给服务器,然后通过sessionid的key到Memcached中去取对应的值) Response.Cookies["sessionId"].Value =http://www.mamicode.com/ sessionId.ToString(); //再把用户的信息插入到Memcached中 MemcacheHelper.Set(sessionId.ToString(), loginUser, DateTime.Now.AddMinutes(20)); return Content("ok"); } }
而另一段比较重要的代码就写在过滤器里,根据浏览器发过来的sessionid来去memcache中查询数据,查到的话,表示校验成功,否则跳转回登陆界面。
protected override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); //从cookie中获取咱们的 登录的sessionId string sessionId = Request["sessionId"]; //如果sessionid为空值,则跳转到登录页面 if (string.IsNullOrEmpty(sessionId)) { //return RedirectToAction("Login", "Logon"); Response.Redirect("/UserLogin/Index"); return; } object obj = MemcacheHelper.Get(sessionId); UserInfo user = obj as UserInfo; if (user == null) { //用户长时间不操作,。超时。 Response.Redirect("/UserLogin/Index"); } LoginUser = user; //实现session的滑动机制 MemcacheHelper.Set(sessionId, user, DateTime.Now.AddMinutes(20)); }
关于memcached集群的配置很简单,写在MemcacheHelper中,只需要将Memcache的服务地址写进去就行,以逗号分开,之后再设置一下权重就好了。
//通过客户端来进行memcached的集群配置,在插入数据的时候,使用一致性哈希算法,将对应的value值存入Memcached String[] serverlist = { "127.0.0.1:11211" , "127.0.0.1:11212" }; // 初始化Memcached的服务池 SockIOPool pool = SockIOPool.GetInstance("test"); //设置服务器列表 pool.SetServers(serverlist); //各服务器之间负载均衡的设置比例 pool.SetWeights(new int[] { 1 }); pool.Initialize(); //创建一个Memcached的客户端对象 mc = new MemcachedClient(); mc.PoolName = "test"; //是否启用压缩数据:如果启用了压缩,数据压缩长于门槛的数据将被储存在压缩的形式 mc.EnableCompression = false;
之后,将网站发布到iis上的不同的端口号上就行了。要是想有调试效果, 直接将项目复制两份,其中一个端口号改下,启动就好了。
最后发现,当登陆一个网站成功后,我们再去访问另一个网站(不要换浏览器,cookie),发现也能直接访问了。
这样一个关于memcached的分布式缓存系统就完成了,再写的过程,又是知识加深的过程,书常读常新,加油??。
代码地址
码云:http://git.oschina.net/sdadx/leiku/tree/master/WebMemcache
参考:1.memcached安装及.NET中的Memcached.ClientLibrary使用详解
2.使用缓存的9大误区(上)
3.3种web会话管理的方式
4.memcached全面剖析–4. memcached的分布式算法
5.ASP.Net MVC4+Memcached+CodeFirst实现分布式缓存
Memcache+cookie实现模拟session