【实践】Memcached实例解析
关于Memcached
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。 Memcached是一种基于内存的Key-Value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。 Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。 本质上,它是一个简洁的key-value存储系统。 一般的使用目的,是通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。
Memcached特征
Memcached作为高速运行的分布式缓存服务器,具有以下的特点。
- 协议简单
- 基于libevent的事件处理
- 内置内存存储方式
- Memcached不互相通信的分布式
Memcached的分布式部署极其简单,通常较小的应用一台Memcached服务器就可以满足需求,但是大中型项目可能就需要多台Memcached服务器了,这就牵涉到一个分布式部署的问题。对于多台Memcached服务器,怎么确定一个数据应该保存到哪台服务器呢?有两种方案,一是普通Hash分布,二是一致性Hash分布。普通Hash分布对于Memcached服务器数量固定的情况推荐使用,比较简单。但是当服务器数量发生改变时,问题就出来了。因为同一个KEY经Hash算法处理后,与服务器数量取模,会导致结果与服务器数量未变化时不同,这就导致之前保存的数据丢失。采取一致性Hash分布可以有效的解决这个问题,把丢失的数据减到最小(注意这里并没有说完全不丢失)。
Memcached实际运用
下面通过一个简单的实例来说明Memcached的高性能,以及Memcached是如何工作的。数据源采用的是随机生成的1500万条记录,通过控制台程序来模拟用户登录的业务逻辑,如果首次登录成功,则把用户信息写入Memcached缓存中,再次登录时即可从缓存中取得用户信息进行验证。以下是详细代码过程:
数据操作接口:
1 namespace MemcachedLibrary 2 { 3 interface IDataOperator 4 { 5 //获取数据库连接 6 SqlConnection OpenConnection(); 7 //获取用户信息 8 void GetUserInfo(string user, string pass); 9 } 10 }
具体的登录业务操作:
1 public class SQLDataOperator : IDataOperator 2 { 3 //数据库连接串 4 private const string connectKey = "server=DESKTOP-ALQLV05;database=db_TencentEmailInfo;uid=sa;pwd="; 5 6 //标记变量,标记是否已经缓存 7 private bool IsMemcachedFinished = false; 8 9 //获取用户信息 10 public void GetUserInfo(UserInfo user) 11 { 12 Stopwatch memcachedWatch = new Stopwatch(); 13 memcachedWatch.Start(); 14 15 //从Memcached中取得数据,初始化SockIOPool 16 SockIOPool pool = MemcachedMain.MemcachedInitialize(); 17 MemcachedClient client = MemcachedMain.GetMemcachedInstance(); 18 //检查Memcached是否缓存了User信息 19 if (client.KeyExists("user") && client.KeyExists("pass")) 20 { 21 if (user.User == client.Get("user").ToString() && user.Pass == client.Get("pass").ToString()) 22 { 23 Debug.WriteLine("登录成功!已从Memcached中取得用户信息!"); 24 } 25 IsMemcachedFinished = true; 26 } 27 memcachedWatch.Stop(); 28 Debug.WriteLine("Memcached取得用户信息耗时:" + memcachedWatch.ElapsedMilliseconds + "毫秒"); 29 30 //如果Memcached中已经缓存User信息,则无需到数据库中检索数据,提高性能 31 if (IsMemcachedFinished) 32 { 33 return; 34 } 35 36 37 //如果Memcached中没有缓存过数据,则从数据库中取得数据,并将结果缓存到Memcached 38 Stopwatch databaseWatch = new Stopwatch(); 39 databaseWatch.Start(); 40 SqlConnection con = OpenConnection(); 41 string cmdsql = string.Format("select * from tb_emailInfo where email='{0}' and classCode='{1}' ", user.User, user.Pass); 42 using (SqlCommand cmd = new SqlCommand(cmdsql, con)) 43 { 44 DataTable tb = new DataTable(); 45 SqlDataAdapter sda = new SqlDataAdapter(cmd); 46 sda.Fill(tb); 47 Debug.WriteLine("登录成功!已从数据库中取得用户信息!已查询到人数:" + tb.Rows.Count); 48 if (tb.Rows.Count > 0) 49 { 50 client.Set("user", user.User, DateTime.Now.AddMinutes(30));//Set中的第三个参数是指定缓存过期时间 51 client.Set("pass", user.Pass, DateTime.Now.AddMinutes(30)); 52 } 53 } 54 databaseWatch.Stop(); 55 Debug.WriteLine("数据库取得用户信息耗时:" + databaseWatch.ElapsedMilliseconds + "毫秒"); 56 } 57 58 public SqlConnection OpenConnection() 59 { 60 SqlConnection conn = new SqlConnection(connectKey); 61 { 62 conn.Open(); 63 Debug.WriteLine(conn.State); 64 return conn; 65 } 66 }
下面的代码是在控制台调用的过程:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 while (true) 7 { 8 UserInfo userInfo = new UserInfo();//只存储了用户名和密码属性的实体 9 Console.WriteLine("请输入测试用户:"); 10 userInfo.User = Console.ReadLine(); 11 Console.WriteLine("请输入测试密码:"); 12 userInfo.Pass = Console.ReadLine(); 13 14 SQLDataOperator sqlDO = new SQLDataOperator(); 15 Stopwatch watch = new Stopwatch(); 16 watch.Start(); 17 sqlDO.GetUserInfo(userInfo); 18 watch.Stop(); 19 20 } 21 } 22 }
最后的运行结果截图如下:
图一
图二
图三
图四
本文的实例是将用户信息以字符串的形式缓存起来并提供检索,其实也可以直接把UserInfo实体对象缓存到Memcached中,取出来后进行转化即可,前提是Userinfo需要有序列化关键字serializable关键字。后面有时间在更新下Memcached缓存实体的实例。
参考资料:
http://www.runoob.com/memcached/memcached-tutorial.html Memcached详细教程
https://blog.phpha.com/backup/archives/1303.html Memcached分布式部署
—— EOF ——
作者:悠扬的牧笛
地址:https://www.cnblogs.com/xhb-bky-blog/p/5782444.html
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。