memcached是一套分布式的快取系统,当初是Danga Interactive为了LiveJournal所发展的,但被许多软件(如MediaWiki)所使用。这是一套开放源代码软件,以BSD license授权协议发布。[1]
memcached仅支持一些非常简单的命令 比如get(获取某个键值) set(用来设定或保存一个缓存);
其本身是缓存服务器,但本身无法决定缓存任何数据,其缓存机制依赖于服务端和客户端两者必不可少(存储是由服务端进行存储,但存储什么是由客户端进行决定的)
因此客户端要自己提供缓存的键名以及时长、标志位、整个数据大小等等
例如:只存储hello 但只存储60秒
set key 5 60 hello
并告知服务器端,这样存储过了60秒后,由服务端进行清除数据
但是其工作机制非常独特,其缓存功能是基于Lazy模型的:
只要空间未满则不清理
那么问题来了:如果空间过小,而需缓存的内容过大的话,那么导致缓存抖动非常严重,存完即清理其次再去缓存这样会导致命中率下降,而毫无意义
有些时候,有些数据管理不善有可能导致缓存崩溃等
如果memcached崩溃仅导致业务层的影响,最多是速度降低 而不会导致数据层
memcached如何实现缓存的
memcached通过内存进行缓存数据,但并不实现持久缓存
存数数据的下限:
最小为48字节
最大不能超过1MB
但存储的数据大小有可能不一致,比如:
index.html10k
test.jpg34k
那memcached如何在内存中管理缓存数据
假如我们分别存储不同大小的数据以上为例
很显然只要分配一个足够大的空间就可以了,但是在内存中去找对应的数据我们必须要有对应的缓存对象的边界(起始存储位地址和结束存储位地址)将其当做独立的单位来管理
等其缓存失效了,空间会被腾出,时间久了可能会带来碎片,因为存储的都是非常小的数据单元,按理说如果再想高速利用则会困难,所以在这种机制下memcached的存储数据 查询数据等操作都是非常缓慢的
由此,不停快速基于内存的申请、释放反复操作,这种释放本身也消耗大量的资源和时间
因此我们需要一种高效的机制来解决内存的创建和释放的问题
对于memcached来讲首要必须解决这类内存碎片问题,不然由于内存的碎片导致进程运行的非常缓慢
在linux内核中引入了两种机制避免内存碎片
1.buddy system 伙伴系统
为了实现整个内存中以页面方式管理内存的时候有足够大的连续内存空间可用的,在物理内存中,事实上内存的管理和分配在内核级别通常以页面方式分配和使用的
通常是4k大小一个页面,buddy就是为了将这些零碎的、空闲的合并成一个连续的大的内存空间,这样就避免了页面之间产生碎片的,因此,其主要目的是为了避免内存外碎片
2.slab allocator slab分配器
实现将存储小于页面单位的非常小的数据内存结构的时候之前事先分配并随时等待有需求的进程或要存储的对象使用,当我们使用之后它也不会自动消毁结构而是随时重复使用
避免内存内部碎片
最新版本的memcached使用的是增长因子(growth factor)来明确定义起始点开始依次增长
比如:
我们定义增长因子为其2倍
我们存储一个单位为48bytes,那么会分配其48*2 = 96bytes
如果增长因子为1.1倍
那么48+48*1.1
一旦存储空间满了,则会清理,没有存满则不会清理数据
memcached也支持分布式缓存基础概念
memcached也支持分布式缓存,但是彼此之间不会通信,但是一个memcached也不会缓存过多数据,如果将来缓存的数据很大的话,那只能使用多台memcached提供服务
假设这么一个场景:
前端的应用服务器很多,这些服务器角色都需要连接至数据库,为了加速数据库的性能,可对其提供memcached服务器,经过一段时间观察,我们的memcached数据库缓存过多,请求量过大一台机器根本扛不住,这时需要对其扩容。
于是我们又加入了一台memcached,但是memcached服务器之间是不能通信的
所以某一应用服务器A 要缓存数据不能只盯一台memcached,所以我们要让其轮流来提供服务,但是对memcached而言它的分布式算法是在应用程序(客户端)中实现的,而不是取决于服务器自身
客户端是如何分布式调度服务端
需要一定分布式算法,和调度器
(如果memcached非常多的话,完全可以使用第三方调度器进行调度,比如nginx+持久连接)
或一致性哈希算法:
参考:http://blog.csdn.net/kongqz/article/details/6695417
总结:
1、在内存中缓存
2、内存要使用slab allocator将其分配成很多slab trunk,每个trunk用来存储一类数据的,而真正存的数据很有可能不会被精确匹配,而我们需要给其找一个最佳的匹配机制就是用来slab trunk来存储 但是难免会浪费内存空间,但是可以让我们内存分配效率非常高
安装配置memcached服务
Memcached依赖于libeventAPI库,所以首先要安装libevent
[root@testtools]# tar xf libevent-2.0.21-stable.tar.gz
[root@testtools]# cd libevent-2.0.21-stable
[root@testlibevent-2.0.21-stable]# ./configure --prefix=/usr/local/memcached--with-libevent=/usr/local/libevent
[root@testlibevent-2.0.21-stable]# make && make install
安装memcached
[root@testtools]#cd memcached-1.4.15
[root@testmemcached-1.4.15]# ./configure --prefix=/usr/local/memcached--with-libevent=/usr/local/libevent && make && make install
启动memcached
启动之前我们先来看一下memcahced关键的几个参数
关键参数说明
[root@node1bin]# ./memcached -h
-p 监听tcp协议的监听端口
-T 监听UDP协议id监听端口默认都是11211
-s 如果只在本地通信那么可以将其监听在某个套接字上,比如mysql.scok 能够利用共享内存方式进行通信的
-c 最大并发连接数
-l 监听的地址,如果服务器有多块网卡,那么用-l来指定监听的某个网卡上
-d 以一个服务方式运行
-r 设定最大内核大小限制
-u 以某个用户身份运行
-m 以兆为单位指定memcached最大内存可用空间
-t 用于处理入站请求最大的线程数,仅在memcached编译时开启了支持线程才有效,而linux对线程支持是非常有限的,所以不用关心了
-f 设定slab定义预先分配内存空间大小固定的块时使用的增长因子
-n 最小的存储单位是多大,默认是48字节,单位是字节
-P 指定pid文件
-L 视图使用最多的内存空间
-S 启用SSL认证功能
启动memcached
这里先放在前台运行,并观察其增长因子,如下所示:
[root@testbin]# /usr/local/memcached/bin/memcached -m 128 -n 20 -f 1.25 -vv -u nobody
slabclass1: chunksize72 perslab14563
slabclass2: chunksize96 perslab 10922
slabclass3: chunksize120 perslab 8738
slabclass4: chunksize 152 perslab 6898
slabclass5: chunksize192 perslab5461
slabclass6: chunk size240 perslab4369
slabclass7: chunk size304 perslab3449
#################中间略#################
slabclass40: chunk size493552 perslab2
slabclass41: chunk size616944 perslab1
slabclass42: chunk size771184 perslab1
slabclass43: chunksize1048576perslab1
|