1 命令行查看状态
很多时候我们需要去查看Memcached 的使用状态,比如Memcached 的运行时间,使用状态等等。在Windows系统中我们可以使用telnet 命令来查看Memcached 的相关运行情况。
开始—>运行àcmd 运行得到如下:
输入telnet命令: telnet 服务地址 端口
Memcached 的默认端口号是11211
输入stats 命令: 在这里屏幕是空白,看不到输入的内容,回车之后可以看到Memcached的运行相关信息。
Pid: Memcached 服务器中的进程编号
Uptime:Memcached服务器启动之后所经历的时间,单位秒
Time: 当前系统时间,单位秒
Version: Memcached 的版本号
pointer_size:服务器所在主机操作系统的指针大小,一般为32或64
curr_items:表示当前缓存中存放的所有缓存对象的数量
total_items:表示从memcached服务启动到当前时间,系统存储过的所有对象的数量,包括已经删除的对象
bytes:表示系统存储缓存对象所使用的存储空间,单位为字节
curr_connections:表示当前系统打开的连接数
total_connections:表示从memcached服务启动到当前时间,系统打开过的连接的总数
cmd_get: 查询缓存的次数,即使不成功也算一次
cmd_set: 保存数据的次数,当然这里只保存成功的次数
get_hits:表示获取数据成功的次数。
get_misses:表示获取数据失败的次数。
evictions:为了给新的数据项目释放空间,从缓存移除的缓存对象的数目。比如超过缓存大小时根据LRU算法移除的对象,以及过期的对象
bytes_read:memcached服务器从网络读取的总的字节数
bytes_written:memcached服务器发送到网络的总的字节数
limit_maxbytes:memcached服务缓存允许使用的最大字节数
threads:被请求的工作线程的总数量
2 Memcached 存储机制
关于Memcached的存储机制,在网上搜了一下讲解基本上都是千篇一律的。
memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。在之前的版本中,Memcached存储会导致很多内存碎片,从而加重了操作系统对内存管理的负担。Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块, 以完全解决内存碎片问题。
Slab Allocation 将分配的内存分割成各种尺寸的chunk (块),并把大小相同尺寸的chunk分为一组,就如上图一样:分割了 88b,112b,144b等尺寸。其实Slab Allocation还有重复利用内存的功能,也就是说分配的内存不会释放,而是重复利用。
当存储数据的时候,它会自动去查找最为匹配的chunk,然后将数据存储到其中。比如我存储数据的大小为110B,那么它会存储到112B的chunk中。
上面的问题来了,我存储只需要110B,但是我存储到112B的chunk中。如下图(借用):
那么在110b的存储中会浪费2B的内存空间
至于如何完全解决这个内存空间浪费的问题,还没有很好的方案,不过Memcached的 增长因子(Growth Factor)能够适当解决此问题。目前Memcached的默认增长因子 是1.25,也就是说会以原有的最大值基础上乘以1.25 来分配空间。
3 Memcached 对内存资源的有效利用
之前已经提到过了,Memcached 会重复利用已经分配的内存,也就是说不会去删除已有的数据而且释放内存空间,而是数据过期之后,用户将数据不可见。
Memcached 还是用了一种Lazy Expiration (延迟过期[姑且这样翻译]) 技术,就是Memcached不会去监视服务器上的数据是否过期,而是等待get的时候检查时间戳是否过期,减少Memcached在监控数据上所用到的时间。
4 Memcached 客户端使用简单封装
本文很多都是理论上的分析,这些大多也是从网络上看来的,根据自己的理解和实际的应用做了一些总结。有时候我们使用Memcached的客户端时并不是那么的友好,这里对其做了一下简单的封装,抽象出来了一个接口:
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Collections;
6
7 namespace MemcachedTest
8 {
9 public interface ICache
10 {
11 bool ContainKey( string argKey);
12
13 bool Add( string argKey, object argValue);
14
15 bool Add( string argKey, object argValue, DateTime argDateExpiration);
16
17 bool Add < T > ( string argKey, T entity) where T : class ;
18
19 bool Add < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class ;
20
21 bool Set( string argKey, object argValue);
22
23 bool Set( string argKey, object argValue, DateTime argDateExpiration);
24
25 bool Set < T > ( string argKey, T entity) where T : class ;
26
27 bool Set < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class ;
28
29 bool Replace( string argKey, object argValue);
30
31 bool Replace( string argKey, object argValue,DateTime argDateExpiration);
32
33 bool Replace < T > ( string argKey, T entity) where T : class ;
34
35 bool Replace < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class ;
36
37 object Get( string argKey);
38
39 T Get < T > ( string argKey);
40
41 bool Remove( string argKey);
42
43 bool Remove( string argKey, DateTime argDateExpiration);
44
45 bool Remove();
46
47 bool Remove(ArrayList servers);
48
49 }
50 }
下面这段代码对上面的接口进行了实现,里面的代码大多数人应该能够看懂,是比较简单的代码封装,如果能够了解本人上一篇的简单应用,对于这个封装的理解应该没有难度。实现代码如下:
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Memcached.ClientLibrary;
6 using System.Collections;
7
8 namespace MemcachedTest
9 {
10 public class Memcache:ICache
11 {
12 private MemcachedClient client;
13 private static Memcache memcache;
14
15 /// <summary>
16 /// 构造方法
17 /// </summary>
18 protected Memcache()
19 {
20 SockIOPool pool = SockIOPool.GetInstance();
21 string [] servers = { " 127.0.0.1:11211 " };
22 pool.SetServers(servers);
23 pool.MinConnections = 3 ;
24 pool.MaxConnections = 5 ;
25 pool.InitConnections = 3 ;
26 pool.SocketConnectTimeout = 5000 ;
27 pool.Initialize();
28 this .client = new MemcachedClient();
29 client.EnableCompression = false ;
30 }
31
32 public static Memcache Instance()
33 {
34 if (memcache == null )
35 {
36 memcache = new Memcache();
37 }
38 return memcache;
39 }
40
41
42 /// <summary>
43 /// 判断是否包含某个键
44 /// </summary>
45 /// <param name="argKey"> 键值 </param>
46 /// <returns></returns>
47 public bool ContainKey( string argKey)
48 {
49 return client.KeyExists(argKey);
50 }
51
52 /// <summary>
53 /// 添加缓存数据
54 /// </summary>
55 /// <param name="argKey"> 键值 </param>
56 /// <param name="argValue"> 存储值 </param>
57 /// <returns></returns>
58 public bool Add( string argKey, object argValue)
59 {
60 return client.Add(argKey,argValue);
61 }
62
63 /// <summary>
64 /// 添加缓存数据
65 /// </summary>
66 /// <param name="argKey"> 键值 </param>
67 /// <param name="argValue"> 存储值 </param>
68 /// <param name="argDateExpiration"> 过期时间 </param>
69 /// <returns></returns>
70 public bool Add( string argKey, object argValue, DateTime argDateExpiration)
71 {
72 return client.Add(argKey, argValue, argDateExpiration);
73 }
74
75 /// <summary>
76 /// 添加缓存数据
77 /// </summary>
78 /// <typeparam name="T"> 存储对象类型 </typeparam>
79 /// <param name="argKey"> 键值 </param>
80 /// <param name="entity"> 存储值 </param>
81 /// <returns></returns>
82 public bool Add < T > ( string argKey, T entity) where T : class
83 {
84 return client.Add(argKey, entity);
85 }
86
87 /// <summary>
88 /// 添加缓存数据
89 /// </summary>
90 /// <typeparam name="T"> 存储对象类型 </typeparam>
91 /// <param name="argKey"> 键值 </param>
92 /// <param name="entity"> 存储值 </param>
93 /// <param name="argDateExpiration"> 过期时间 </param>
94 /// <returns></returns>
95 public bool Add < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class
96 {
97 return client.Add(argKey, entity, argDateExpiration);
98 }
99
100 /// <summary>
101 /// 添加缓存数据,如果存在则替换原有数据
102 /// </summary>
103 /// <param name="argKey"> 键值 </param>
104 /// <param name="argValue"> 存储值 </param>
105 /// <returns></returns>
106 public bool Set( string argKey, object argValue)
107 {
108 if (ContainKey(argKey))
109 {
110 return false ;
111 }
112 return client.Set(argKey, argValue);
113 }
114
115 /// <summary>
116 /// 添加缓存数据,如果存在则替换原有数据
117 /// </summary>
118 /// <param name="argKey"> 键值 </param>
119 /// <param name="argValue"> 存储值 </param>
120 /// <param name="argDateExpiration"> 过期时间 </param>
121 /// <returns></returns>
122 public bool Set( string argKey, object argValue, DateTime argDateExpiration)
123 {
124 if (ContainKey(argKey))
125 {
126 return false ;
127 }
128 return client.Set(argKey, argValue, argDateExpiration);
129 }
130
131 /// <summary>
132 /// 添加缓存数据,如果存在则替换原有数据
133 /// </summary>
134 /// <typeparam name="T"> 存储对象类型 </typeparam>
135 /// <param name="argKey"> 键值 </param>
136 /// <param name="entity"> 存储值 </param>
137 /// <returns></returns>
138 public bool Set < T > ( string argKey, T entity) where T : class
139 {
140 if (ContainKey(argKey))
141 {
142 return false ;
143 }
144 return client.Set(argKey, entity);
145 }
146
147 /// <summary>
148 /// 添加缓存数据,如果存在则替换原有数据
149 /// </summary>
150 /// <typeparam name="T"> 存储对象类型 </typeparam>
151 /// <param name="argKey"> 键值 </param>
152 /// <param name="entity"> 存储值 </param>
153 /// <param name="argDateExpiration"> 过期时间 </param>
154 /// <returns></returns>
155 public bool Set < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class
156 {
157 if (ContainKey(argKey))
158 {
159 return false ;
160 }
161 return client.Set(argKey, entity, argDateExpiration);
162 }
163
164
165 /// <summary>
166 /// 替换原有缓存
167 /// </summary>
168 /// <param name="argKey"> 键值 </param>
169 /// <param name="argValue"> 存储值 </param>
170 /// <returns></returns>
171 public bool Replace( string argKey, object argValue)
172 {
173 return client.Replace(argKey,argValue);
174 }
175
176 /// <summary>
177 /// 替换原有缓存
178 /// </summary>
179 /// <param name="argKey"> 键值 </param>
180 /// <param name="argValue"> 存储值 </param>
181 /// <param name="argDateExpiration"> 过期时间 </param>
182 /// <returns></returns>
183 public bool Replace( string argKey, object argValue, DateTime argDateExpiration)
184 {
185 return client.Replace(argKey,argValue,argDateExpiration);
186 }
187
188 public bool Replace < T > ( string argKey, T entity) where T : class
189 {
190 return client.Replace(argKey,entity);
191 }
192
193 public bool Replace < T > ( string argKey, T entity, DateTime argDateExpiration) where T : class
194 {
195 return client.Replace(argKey, entity,argDateExpiration);
196 }
197
198 public object Get( string argKey)
199 {
200 return client.Get(argKey);
201 }
202
203 public T Get < T > ( string argKey)
204 {
205 T entity = default (T);
206 entity = (T)client.Get(argKey);
207 return entity;
208 }
209
210 public bool Remove( string argKey)
211 {
212 return client.Delete(argKey);
213 }
214
215 public bool Remove( string argKey, DateTime argDateExpiration)
216 {
217 return client.Delete(argKey,argDateExpiration);
218 }
219
220 public bool Remove()
221 {
222 return client.FlushAll();
223 }
224
225 public bool Remove(ArrayList servers)
226 {
227 return client.FlushAll(servers);
228 }
229 }
230 }
上面的代码没有注释,因为提交不了这么长的代码,去掉了注释。代码大家可以看懂的,这里不做过多的讲解。
学习例子源码下载