Memcache+Cookie解决分布式系统共享登录状态
Memcached高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。
Memcached的特点
Memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。
memcache的优点:
1.解决了高并发访问数据库造成的死锁
2.实现了多客户端的共享缓存
3.读写性快,1s:读取可以1w次,写:10w
4.超简单集群搭建Cluster
5.开源代码
6.学习成本低、入门容易、丰富的成功案例
缺点:
没有提供主从复制功能,也没有提供容灾等功能,数据存在缓存中(例如服务器重启就会丢失数据),所有的代码基本只是考虑性能最佳。
Memcache 基础原理
底层通讯:Socket
数据:键值对存储,key最大255个字符,item最大1MB,当然key/item最好都别太大,最长过期时间是30天
内存处理的算法:
本质就是一个大的哈希表。key最大长度是255个字符。
内存模型:Memcache预先将可支配的内存空间进行分区(Slab),每个分区里再分成多个块(Chunk)大小1MB,但同一个分区里:块的长度(bytes)是固定的。
插入数据:查找适合自己长度的块,然后插入,会有内存浪费。
LRU,闲置>过期 >最少访问
惰性删除:它并没有提供监控数据过期的机制,而是惰性的,当查询到某个key数据时,如果过期那么直接抛弃。
集群搭建原理:
Memcache服务器端并没有提供集群功能,但是通过客户端的驱动程序实现了集群配置。 客户端实现集群的原理:首先客户端配置多台集群机器的ip和端口的列表。然后客户端驱动程序在写入之前,首先对key做哈希处理得到哈希值后对总的机器的个数进行取余然后就选择余数对应的机器。
Windows下使用Memcache
下载Memcache
安装服务:以管理员的身份打开cmd进入memcache所在文件夹,输入安装命令:Memcached.exe -d install

打开服务会看到memcached已安装

打开服务监控窗口可以查看服务是否启动。 启动服务:cmd→Memcached.exe -d start(restart重启,stop关闭服务)
检查服务是否启动:
1.开启telnet

2.在控制台输入命令:telnet 192.168.1.22 11211(ip地址 端口号:默认为11211)
通过 memcached.exe -h 可以查看其帮助
3.在控制台输入命令检查当前服务状态:stats

卸载服务:Memcached.exe -d uninstall(先关闭服务)
遇到问题:win8下安装服务。无法启动此程序,因为计算机中丢失 MSVCR71.dll。尝试重新安装该程序以解决此问题。下载dll地址:http://www.dll-files.com/dllindex/dll-files.shtml?msvcr71

二 .NET memcached client library
下载文件:https://sourceforge.net/projects/memcacheddotnet/
里面有.net1.1 和 .net2.0的两种版本 还有一个不错的例子。
三 应用
1 将Commons.dll,ICSharpCode.SharpZipLib.dll,log4net.dll,Memcached.ClientLibrary.dll 放到lib目录,如果项目中已存在log4net.dll则不需要再引用
2 项目右击添加引用
3 代码
using Memcached.ClientLibrary;
using System; namespace CZBK.ItcastOA.MemcaheDemo
{
class Program
{
static void Main(string[] args)
{
//ip地址:端口号
string[] serverlist = { "192.168.1.95:11211", "10.0.0.132:11211" }; //初始化池
SockIOPool pool = SockIOPool.GetInstance();
pool.SetServers(serverlist); pool.InitConnections = ;
pool.MinConnections = ;
pool.MaxConnections = ; pool.SocketConnectTimeout = ;
pool.SocketTimeout = ; pool.MaintenanceSleep = ;
pool.Failover = true; pool.Nagle = false;
pool.Initialize(); // 获得客户端实例
MemcachedClient mc = new MemcachedClient();
mc.EnableCompression = false; Console.WriteLine("------------测 试-----------");
mc.Set("test", "my value"); //存储数据到缓存服务器,这里将字符串"my value"缓存,key 是"test" if (mc.KeyExists("test")) //测试缓存存在key为test的项目
{
Console.WriteLine("test is Exists");
Console.WriteLine(mc.Get("test").ToString()); //在缓存中获取key为test的项目
}
else
{
Console.WriteLine("test not Exists");
} Console.ReadLine(); mc.Delete("test"); //回车移除缓存中key为test的项目 if (mc.KeyExists("test"))
{
Console.WriteLine("test is Exists");
Console.WriteLine(mc.Get("test").ToString());
}
else
{
Console.WriteLine("test not Exists");
}
Console.ReadLine(); SockIOPool.GetInstance().Shutdown(); //关闭池, 关闭sockets
}
}
}
新建同一过滤器类BaseController,在控制器中把继承的Controller换成BaseController
BaseController类过滤器代码
using CZBK.ItcastOA.Common;
using CZBK.ItcastOA.Model;
using System;
using System.Web.Mvc; namespace CZBK.ItcastOA.WebApp.Controllers
{
public class BaseController : Controller
{
/// <summary>
/// 记录登陆用户
/// </summary>
public UserInfo LoginUser { get; set; }
/// <summary>
/// 执行控制器前执行该方法
/// </summary>
/// <param name="filterContext"></param>
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
base.OnActionExecuting(filterContext);
bool isExt = false;
//if (Session["userInfo"]==null)
if(Request["sessionId"]!=null)
{
//接收从cookie中传过来的Memcache的key
string sessionId = Request.Cookies["sessionId"].Value;
//根据key从Memcache中获取用户的信息
object obj = MemcacheHelper.Get(sessionId);
if (obj!=null)
{
UserInfo userInfo = SerializerHelper.DeserializeToObject<UserInfo>(obj.ToString());
LoginUser = userInfo;
isExt = true;
//模拟滑动过期时间
MemcacheHelper.Set(sessionId,obj.ToString(),DateTime.Now.AddMinutes());
} }
if (!isExt)
{
//此跳转会执行完index的方法返回结果才去跳转到登录页面,所以不能用这种方法跳转
//filterContext.HttpContext.Response.Redirect("/Login/Index");
//此方法直接跳转到登录页面,后面的代码不会执行
filterContext.Result = Redirect("/Login/Index");
}
}
}
}
登录页面代码
using CZBK.ItcastOA.Common;
using CZBK.ItcastOA.IBLL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace CZBK.ItcastOA.WebApp.Controllers
{
public class LoginController : Controller
{
IUserInfoService UserInfoService { get; set; }
// GET: Login
public ActionResult Index()
{
//登录时判断Cookie的信息
CheckCookieInfo();
return View();
} #region 获取验证码
public ActionResult GetCodeImage()
{
ValidateCode vlidatecode = new ValidateCode();
//产生验证码
string code = vlidatecode.CreateValidateCode();
//存到session中验证
Session["validatecode"] = code;
//将验证码画到画布上,返回文件
byte[] buffer = vlidatecode.CreateValidateGraphic(code);
//返回文件
return File(buffer, "image/jpeg");
}
#endregion #region 用户登录
public ActionResult UserLogin()
{
//获取验证码验证是否正确
//验证码为空
string validatecode = Session["validatecode"] != null ? Session["validatecode"].ToString() : string.Empty;
if (string.IsNullOrEmpty(validatecode))
{
return Content("no:验证码错误!");
} //验证码不为空
//清空session
Session["validatecode"] = null;
//获取前台输入的code
string txtcode = Request["vCode"].ToString();
//比较验证码忽略大小写
if (!validatecode.Equals(txtcode, StringComparison.InvariantCultureIgnoreCase))
{
return Content("no:验证码错误!");
} //验证用户名和密码
string userName = Request["LoginCode"];
string userPwd = Request["LoginPwd"];
var userInfo = UserInfoService.LoadEntities(a => a.UName == userName && a.UPwd == userPwd).FirstOrDefault();
if (userInfo != null)
{
//记住登录账号
//Session["userInfo"] = userInfo; //用memcache存储用户信息
//作为Memcache的key
string sessionId = Guid.NewGuid().ToString();
//使用Memcache代替Session解决数据在不同Web服务器之间共享的问题。
MemcacheHelper.Set(sessionId, SerializerHelper.SerializeToString(userInfo), DateTime.Now.AddMinutes());
//将Memcache的key以cookie的形式返回到浏览器端的内存中,当用户再次请求其它的页面请求报文中会以Cookie将该值再次发送服务端。
Response.Cookies["sessionId"].Value = sessionId; //记住登录账号
if (!string.IsNullOrEmpty(Request["checkMe"]))
{
HttpCookie cookie1 = new HttpCookie("cp1", userInfo.UName);
//HttpCookie cookie2 = new HttpCookie("cp2", WebCommon.GetMd5String(userInfo.UPwd));
HttpCookie cookie2 = new HttpCookie("cp2", userInfo.UPwd);
cookie1.Expires = DateTime.Now.AddDays();
cookie2.Expires = DateTime.Now.AddDays();
Response.Cookies.Add(cookie1);
Response.Cookies.Add(cookie2);
}
return Content("ok:登录成功!");
}
return Content("no:登录失败!");
}
#endregion #region 登录时判断Cookie的信息
private void CheckCookieInfo()
{
if (Request.Cookies["cp1"] != null && Request.Cookies["cp2"] != null)
{
string userName = Request.Cookies["cp1"].Value;
string userPwd = Request.Cookies["cp2"].Value;
//判断Cookie中存储的用户名和密码是否正确
var userInfo = UserInfoService.LoadEntities(a => a.UName == userName && a.UPwd == userPwd).FirstOrDefault();
if (userInfo != null)
{
//再次记录到Memcache中,30分钟过期
string sessionId = Guid.NewGuid().ToString();
MemcacheHelper.Set(sessionId, SerializerHelper.SerializeToString(userInfo), DateTime.Now.AddMinutes());
Response.Cookies["sessionId"].Value = sessionId;
Response.Redirect("/home/Index");
}
//Response.Redirect表示重定向页面,如果执行Response.Redirect代码则下两句代码不执行
//存在cookies但是错误则设置过期
Response.Cookies["cp1"].Expires = DateTime.Now.AddDays(-);
Response.Cookies["cp2"].Expires = DateTime.Now.AddDays(-);
}
}
#endregion #region 退出登录
public ActionResult Logout()
{
if (Request.Cookies["sessionId"] != null)
{
string key = Request.Cookies["sessionId"].Value;
Common.MemcacheHelper.Delete(key);
Response.Cookies["cp1"].Expires = DateTime.Now.AddDays(-);
Response.Cookies["cp2"].Expires = DateTime.Now.AddDays(-);
}
return Redirect("/Login/Index");
}
#endregion
}
}
关于用户登录状态存session,cookie还是数据库或者memcache的优劣
memcached参考链接:
http://www.cnblogs.com/zjneter/archive/2007/07/19/822780.html
http://www.cnblogs.com/xulb597/archive/2012/11/21/2780506.html
Memcache+Cookie解决分布式系统共享登录状态的更多相关文章
- Memcache+Cookie解决分布式系统共享登录状态------------------------------Why Memcached?
每个用户请求向IIS发送一个请求,但IIS服务器的请求数有限,cpu支持的线程数有限,如果一秒钟向这台服务器发送10000次,那么则一般就会有问题,考虑集群, 请求数据分流,几台服务器共同对应一个公共 ...
- Lab: Brute-forcing a stay-logged-in cookie:点击保持登录状态返回的Cookie里面破解账号密码靶场复盘
靶场内容: 此实验室允许用户在关闭浏览器会话后仍保持登录状态.用于提供此功能的 cookie 容易受到暴力破解. 为了解决实验室问题,暴力破解 Carlos 的 cookie 以访问他的"我 ...
- 【wpf WebBrowser 清空网站的Cookie&Session 清空用户登录状态】
最近做项目遇到了一个说小不小,说大不大的问题,那就是在WebBrowser中清空网站上用户的登陆状态, 一开始心想,那不就清空cookies就行啦,那么简单的事情,百度一下 …… …… 是的,正如你们 ...
- session、cookie 记住登录状态的实现
Cookie的机制 Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能. Cookie的Domain和Path属性标识 ...
- 使用robotframework做接口测试三——保持登录状态
调用登录接口登录了,其他的接口怎么保持登录状态呢? 首先来看一看,web端或者说客户端是怎么样用cookie/token等保持登录状态的.一般来说,cookie都会在登录接口由服务端返回,而且会是在 ...
- JMeter 怎么保存登录状态
在Recording Controller中添加一个HTTP Cookie Manager Recording Controller右键-->add-->config element--& ...
- uni-app 保持登录状态 (Vuex)
在小程序中,保持登录状态是很常见的需求,今天就把写一写使用uni-app框架的保持登录状态功能是怎样实现的. 一.场景需求 1.场景:初始打开---登陆---关闭,再次打开---(已登录)上次关闭前的 ...
- session、cookie与“记住我的登录状态”的功能的实现
Cookie的机制 Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能. Cookie的Domain和Path属性标识 ...
- Postman+Postman interceptor的安装和使用-解决把chrome浏览器登录状态同步到postman进行有依赖的接口测试 Postman 使用方法详解
Postman+Postman interceptor的安装和使用-解决把chrome浏览器登录状态同步到postman进行有依赖的接口测试 问题引入:做接口测试时,有依赖关系的接口往往不好测试( ...
随机推荐
- HTML+jq简单轮播图
.main{ width: 100%; min-width: 1100px; display: table; margin: 0 auto; text-align: ce ...
- ES5拓展
一.JSON拓展 1.JSON.parse(str,fun):将JSON字符串转为js对象 两个参数:str表示要处理的字符串:fun处理函数,函数有两个参数,属性名.属性值 // 定义json字符串 ...
- 【Hive五】Hive函数UDF
Hive函数 系统自带的函数 查看系统自带的函数 查看系统自带的函数 show functions; 显示自带的函数的用法 desc function upper; 详细显示自带的函数的用法 desc ...
- Python学习 :集合
集合 Set 集合的创建 集合的创建只有一种方式 集合中的元素必须是不可变的数据类型 集合是无序的,可以通过 for 循环来遍历或者迭代器进行筛选 s=set('xiaoming') s1=['ale ...
- fedora/centos下gcc编译出现gcc: error trying to exec ‘cc1plus’: execvp: No such file or directory
fedora/centos下gcc编译出现gcc: error trying to exec 'cc1plus': execvp: No such file or directory解决办法 翻译自: ...
- vue生命周期和react生命周期对比
一 vue的生命周期如下图所示(很清晰)初始化.编译.更新.销毁 二 vue生命周期的栗子 注意触发vue的created事件以后,this便指向vue实例,这点很重要 <!DOCTYPE ht ...
- 北京Uber优步司机奖励政策(1月20日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- [转帖]localhost与127.0.0.1的区别
localhost与127.0.0.1的区别 https://www.cnblogs.com/hqbhonker/p/3449975.html 前段时间用PG的时候总有问题 当时没有考虑 localh ...
- hdu1394Minimum Inversion Number(线段树,求最小逆序数)
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- 前端开发工程师 - 02.JavaScript程序设计 - 期末考试
期末考试客观题 期末考试主观题 https://www.15yan.com/story/aY0HWAQ7oNU/ 1(8分) 函数myType用于根据输入参数返回相应的类型信息. 语法如下: ...