- 浏览: 321625 次
- 来自: ...
文章分类
最新评论
-
梦回秘蓝:
<div class="quote_title ...
什么情况需要 if (log.isDebugEnabled()) {} -
wupy:
一直while的话会不会太耗内存呢?
java socket 长连接 短连接 -
xy2401:
<type-mapping> <sql-t ...
hibernate tools oracle nvarchar2 被映射成Serializable -
xy2401:
xy2401 写道额,原来配置文件可以改啊。。。不过我已经生成 ...
hibernate tools oracle nvarchar2 被映射成Serializable -
郭玉成:
你好, 我已经找到原因了!
java 编译非文本形式的文件
Memcached是“分布式”的内存对象缓存系统,那么就是说,那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源,即使是UNIX本地连接也一样。 在我之前的测试数据中显示,memcached本地读写速度要比直接PHP内存数组慢几十倍,而APC、共享内存方式都和直接数组差不多。可见,如果只是本地级缓存,使用memcached是非常不划算的。
Memcached在很多时候都是作为数据库前端cache使用的。因为它比数据库少了很多SQL解析、磁盘操作等开销,而且它是使用内存来管理数据的,所以它可以提供比直接读取数据库更好的性能,在大型系统中,访问同样的数据是很频繁的,memcached可以大大降低数据库压力,使系统执行效率提升。另外,memcached也经常作为服务器之间数据共享的存储媒介,例如在SSO系统中保存系统单点登陆状态的数据就可以保存在memcached中,被多个应用共享。
需要注意的是,memcached使用内存管理数据,所以它是易失的,当服务器重启,或者memcached进程中止,数据便会丢失,所以memcached不能用来持久保存数据。很多人的错误理解,memcached的性能非常好,好到了内存和硬盘的对比程度,其实memcached使用内存并不会得到成百上千的读写速度提高,它的实际瓶颈在于网络连接,它和使用磁盘的数据库系统相比,好处在于它本身非常“轻”,因为没有过多的开销和直接的读写方式,它可以轻松应付非常大的数据交换量,所以经常会出现两条千兆网络带宽都满负荷了,memcached进程本身并不占用多少CPU资源的情况。
Memcached的工作方式
Memcached是传统的网络服务程序,如果启动的时候使用了-d参数,它会以守护进程的方式执行。创建守护进程由daemon.c完成,这个程序只有一个daemon函数,这个函数很简单
这个函数 fork 了整个进程之后,父进程就退出,接着重新定位 STDIN 、 STDOUT 、 STDERR 到空设备, daemon 就建立成功了。
Memcached 本身的启动过程,在 memcached.c 的 main 函数中顺序如下:
1 、调用 settings_init() 设定初始化参数
2 、从启动命令中读取参数来设置 setting 值
3 、设定 LIMIT 参数
4 、开始网络 socket 监听(如果非 socketpath 存在)( 1.2 之后支持 UDP 方式)
5 、检查用户身份( Memcached 不允许 root 身份启动)
6 、如果有 socketpath 存在,开启 UNIX 本地连接(Sock 管道)
7 、如果以 -d 方式启动,创建守护进程(如上调用 daemon 函数)
8 、初始化 item 、 event 、状态信息、 hash 、连接、 slab
9 、如设置中 managed 生效,创建 bucket 数组
10 、检查是否需要锁定内存页
11 、初始化信号、连接、删除队列
12 、如果 daemon 方式,处理进程 ID
13 、event 开始,启动过程结束, main 函数进入循环。
Memcached 使用一套自定义的协议完成数据交换,它的 protocol 文档可以参考: http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
Memcached的内存管理方式
Memcached有一个很有特色的内存管理方式,为了提高效率,它使用预申请和分组的方式管理内存空间,而并不是每次需要写入数据的时候去malloc,删除数据的时候free一个指针。Memcached使用slab->chunk的组织方式管理内存。
Slab可以理解为一个内存块,一个slab是memcached一次申请内存的最小单位,在memcached中,一个slab的大小默认为1048576字节(1MB),所以memcached都是整MB的使用内存。每一个slab被划分为若干个chunk,每个chunk里保存一个item,每个item同时包含了item结构体、key和value(注意在memcached中的value是只有字符串的)。slab按照自己的id分别组成链表,这些链表又按id挂在一个slabclass数组上,整个结构看起来有点像二维数组。slabclass的长度在1.1中是21,在1.2中是200。
slab有一个初始chunk大小,1.1中是1字节,1.2中是80字节,1.2中有一个factor值,默认为1.25
在1.1中,chunk大小表示为初始大小*2^n,n为classid,即:id为0的slab,每chunk大小1字节,id为1的slab,每chunk大小2字节,id为2的slab,每chunk大小4字节……id为20的slab,每chunk大小为1MB,就是说id为20的slab里只有一个chunk:
void slabs_init(size_t limit) { int i; int size=1; mem_limit = limit; for(i=0; i<=POWER_LARGEST; i++, size*=2) { slabclass[i].size = size; slabclass[i].perslab = POWER_BLOCK / size; slabclass[i].slots = 0; slabclass[i].sl_curr = slabclass[i].sl_total = slabclass[i].slabs = 0; slabclass[i].end_page_ptr = 0; slabclass[i].end_page_free = 0; slabclass[i].slab_list = 0; slabclass[i].list_size = 0; slabclass[i].killing = 0; } /* for the test suite: faking of how much we've already malloc'd */ { char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC"); if (t_initial_malloc) { mem_malloced = atol(getenv("T_MEMD_INITIAL_MALLOC")); } } /* pre-allocate slabs by default, unless the environment variable for testing is set to something non-zero */ { char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC"); if (!pre_alloc || atoi(pre_alloc)) { slabs_preallocate(limit / POWER_BLOCK); } }} |
在1.2中,chunk大小表示为初始大小*f^n,f为factor,在memcached.c中定义,n为classid,同时,201个头不是全部都要初始化的,因为factor可变,初始化只循环到计算出的大小达到slab大小的一半为止,而且它是从id1开始的,即:id为1的slab,每chunk大小80字节,id为2的slab,每chunk大小80*f,id为3的slab,每chunk大小80*f^2,初始化大小有一个修正值CHUNK_ALIGN_BYTES,用来保证n-byte排列 (保证结果是CHUNK_ALIGN_BYTES的整倍数)。这样,在标准情况下,memcached1.2会初始化到id40,这个slab中每个chunk大小为504692,每个slab中有两个chunk。最后,slab_init函数会在最后补足一个id41,它是整块的,也就是这个slab中只有一个1MB大的chunk:
Memcached的NewHash算法
Memcached的item保存基于一个大的hash表,它的实际地址就是slab中的chunk偏移,但是它的定位是依靠对key做hash的结果,在primary_hashtable中找到的。在assoc.c和items.c中定义了所有的hash和item操作。
Memcached使用了一个叫做NewHash的算法,它的效果很好,效率也很高。1.1和1.2的NewHash有一些不同,主要的实现方式还是一样的,1.2的hash函数是经过整理优化的,适应性更好一些。
NewHash的原型参考:http://burtleburtle.net/bob/hash/evahash.html
为了变换方便,定义了u4和u1两种数据类型,u4就是无符号的长整形,u1就是无符号char(0-255)。
具体代码可以参考1.1和1.2源码包。
注意这里的hashtable长度,1.1和1.2也是有区别的,1.1中定义了HASHPOWER常量为20,hashtable表长为hashsize(HASHPOWER),就是4MB(hashsize是一个宏,表示1右移n位),1.2中是变量16,即hashtable表长65536:
typedef unsigned long int ub4; /* unsigned 4-byte quantities */typedef unsigned char ub1; /* unsigned 1-byte quantities */#define hashsize(n) ((ub4)1<<(n))#define hashmask(n) (hashsize(n)-1) |
在assoc_init()中,会对primary_hashtable做初始化,对应的hash操作包括:assoc_find()、assoc_expand()、assoc_move_next_bucket()、assoc_insert()、assoc_delete(),对应于item的读写操作。其中assoc_find()是根据key和key长寻找对应的item地址的函数(注意在C中,很多时候都是同时直接传入字符串和字符串长度,而不是在函数内部做strlen),返回的是item结构指针,它的数据地址在slab中的某个chunk上。
items.c是数据项的操作程序,每一个完整的item包括几个部分,在item_make_header()中定义为:
key:键
nkey:键长
flags:用户定义的flag(其实这个flag在memcached中没有启用)
nbytes:值长(包括换行符号\r\n)
suffix:后缀Buffer
nsuffix:后缀长
一个完整的item长度是键长+值长+后缀长+item结构大小(32字节),item操作就是根据这个长度来计算slab的classid的。
hashtable中的每一个桶上挂着一个双链表,item_init()的时候已经初始化了heads、tails、sizes三个数组为0,这三个数组的大小都为常量LARGEST_ID(默认为255,这个值需要配合factor来修改),在每次item_assoc()的时候,它会首先尝试从slab中获取一块空闲的chunk,如果没有可用的chunk,会在链表中扫描50次,以得到一个被LRU踢掉的item,将它unlink,然后将需要插入的item插入链表中。
注意item的refcount成员。item被unlink之后只是从链表上摘掉,不是立刻就被free的,只是将它放到删除队列中(item_unlink_q()函数)。
item对应一些读写操作,包括remove、update、replace,当然最重要的就是alloc操作。
item还有一个特性就是它有过期时间,这是memcached的一个很有用的特性,很多应用都是依赖于memcached的item过期,比如session存储、操作锁等。item_flush_expired()函数就是扫描表中的item,对过期的item执行unlink操作,当然这只是一个回收动作,实际上在get的时候还要进行时间判断:
/* expires items that are more recent than the oldest_live setting. */void item_flush_expired() { int i; item *iter, *next; if (! settings.oldest_live) return; for (i = 0; i < LARGEST_ID; i++) { /* The LRU is sorted in decreasing time order, and an item's timestamp * is never newer than its last access time, so we only need to walk * back until we hit an item older than the oldest_live time. * The oldest_live checking will auto-expire the remaining items. */ for (iter = heads[i]; iter != NULL; iter = next) { if (iter->time >= settings.oldest_live) { next = iter->next; if ((iter->it_flags & ITEM_SLABBED) == 0) { item_unlink(iter); } } else { /* We've hit the first old item. Continue to the next queue. */ break; } } }} |
Memcached客户端
Memcached是一个服务程序,使用的时候可以根据它的协议,连接到memcached服务器上,发送命令给服务进程,就可以操作上面的数据。为了方便使用,memcached有很多个客户端程序可以使用,对应于各种语言,有各种语言的客户端。基于C语言的有libmemcache、APR_Memcache;基于Perl的有Cache::Memcached;另外还有Python、Ruby、Java、C#等语言的支持。PHP的客户端是最多的,不光有mcache和PECL memcache两个扩展,还有大把的由PHP编写的封装类,下面介绍一下在PHP中使用memcached的方法:
mcache扩展是基于libmemcache再封装的。libmemcache一直没有发布stable版本,目前版本是1.4.0-rc2,可以在这里找到。libmemcache有一个很不好的特性,就是会向stderr写很多错误信息,一般的,作为lib使用的时候,stderr一般都会被定向到其它地方,比如Apache的错误日志,而且libmemcache会自杀,可能会导致异常,不过它的性能还是很好的。
mcache扩展最后更新到1.2.0-beta10,作者大概是离职了,不光停止更新,连网站也打不开了(~_~),只能到其它地方去获取这个不负责的扩展了。解压后安装方法如常:phpize & configure & make & make install,一定要先安装libmemcache。使用这个扩展很简单:
<?php$mc = memcache(); // 创建一个memcache连接对象,注意这里不是用new!$mc->add_server('localhost', 11211); // 添加一个服务进程$mc->add_server('localhost', 11212); // 添加第二个服务进程$mc->set('key1', 'Hello'); // 写入key1 => Hello$mc->set('key2', 'World', 10); // 写入key2 => World,10秒过期$mc->set('arr1', array('Hello', 'World')); // 写入一个数组$key1 = $mc->get('key1'); // 获取'key1'的值,赋给$key1$key2 = $mc->get('key2'); // 获取'key2'的值,赋给$key2,如果超过10秒,就取不到了$arr1 = $mc->get('arr1'); // 获取'arr1'数组$mc->delete('arr1'); // 删除'arr1'$mc->flush_all(); // 删掉所有数据$stats = $mc->stats(); // 获取服务器信息var_dump($stats); // 服务器信息是一个数组?> |
这个扩展的好处是可以很方便地实现分布式存储和负载均衡,因为它可以添加多个服务地址,数据在保存的时候是会根据hash结果定位到某台服务器上的,这也是libmemcache的特性。libmemcache支持集中hash方式,包括CRC32、ELF和Perl hash。
PECL memcache是PECL发布的扩展,目前最新版本是2.1.0,可以在pecl网站得到。memcache扩展的使用方法可以在新一些的PHP手册中找到,它和mcache很像,真的很像:
<?php$memcache = new Memcache;$memcache->connect('localhost', 11211) or die ("Could not connect");$version = $memcache->getVersion();echo "Server's version: ".$version."\n";$tmp_object = new stdClass;$tmp_object->str_attr = 'test';$tmp_object->int_attr = 123;$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");echo "Store data in the cache (data will expire in 10 seconds)\n";$get_result = $memcache->get('key');echo "Data from the cache:\n";var_dump($get_result);?> |
这个扩展是使用php的stream直接连接memcached服务器并通过socket发送命令的。它不像libmemcache那样完善,也不支持add_server这种分布操作,但是因为它不依赖其它的外界程序,兼容性要好一些,也比较稳定。至于效率,差别不是很大。
另外,有很多的PHP class可以使用,比如MemcacheClient.inc.php,phpclasses.org上可以找到很多,一般都是对perl client API的再封装,使用方式很像
从C client来说,APR_Memcache是一个很成熟很稳定的client程序,支持线程锁和原子级操作,保证运行的稳定性。不过它是基于APR的(APR将在最后一节介绍),没有libmemcache的应用范围广,目前也没有很多基于它开发的程序,现有的多是一些Apache Module,因为它不能脱离APR环境运行。但是APR倒是可以脱离Apache单独安装的,在APR网站上可以下载APR和APR-util,不需要有Apache,可以直接安装,而且它是跨平台的。
BSM_Memcache是我在BS.Magic项目中开发的一个基于APR_Memcache的PHP扩展,说起来有点拗口,至少它把APR扯进了PHP扩展中。这个程序很简单,也没做太多的功能,只是一种形式的尝试,它支持服务器分组。
和mcache扩展支持多服务器分布存储不同,BSM_Memcache支持多组服务器,每一组内的服务器还是按照hash方式来分布保存数据,但是两个组中保存的数据是一样的,也就是实现了热备,它不会因为一台服务器发生单点故障导致数据无法获取,除非所有的服务器组都损坏(例如机房停电)。当然实现这个功能的代价就是性能上的牺牲,在每次添加删除数据的时候都要扫描所有的组,在get数据的时候会随机选择一组服务器开始轮询,一直到找到数据为止,正常情况下一次就可以获取得到。
BSM_Memcache只支持这几个函数:
zend_function_entry bsm_memcache_functions[] ={ PHP_FE(mc_get, NULL) PHP_FE(mc_set, NULL) PHP_FE(mc_del, NULL) PHP_FE(mc_add_group, NULL) PHP_FE(mc_add_server, NULL) PHP_FE(mc_shutdown, NULL) {NULL, NULL, NULL}}; |
mc_add_group函数返回一个整形(其实应该是一个object,我偷懒了~_~)作为组ID,mc_add_server的时候要提供两个参数,一个是组ID,一个是服务器地址(ADDR:PORT)。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2227366
发表评论
-
SSL and Varnish
2011-08-09 13:55 1116We setup all varnish boxes wher ... -
PlentyOfFish 网站架构学习 - zt
2008-04-03 15:22 1235采取 Windows 技术路线的 Web 2.0 站点并不多, ... -
性能扩展问题要趁早 - zt
2008-04-03 13:49 1063与国内的 Web 2.0 Startup 技术人员相比,国外技 ... -
高性能服务器设计 - zt
2008-04-03 10:26 1674先后查看了haproxy,l7sw ... -
Yupoo! 的网站技术架构 - zt
2008-04-02 21:09 1346又有机会爆料国内 Web 2.0 网站的架构了。这次是 Yup ... -
说说大型高并发高负载网站的系统架构 - zt
2008-04-02 21:05 980一个小型的网站,比如个人网站,可以使用最简单的html静态页面 ... -
使用开源软件,设计高性能可扩展互动网站 - zt
2008-04-02 20:57 983上次我们以LiveJournal为 ... -
从LiveJournal后台发展看 大型网站系统架构以及性能优化方法 - zt
2008-04-02 20:35 1573一、LiveJournal发展历程Li ... -
新浪发起的UNIX开源软件项目memcachedb - zt
2008-02-24 17:24 2179Memcachedb = memcache + Berkele ... -
Memcached学习摘要 - zt
2008-03-29 01:08 2707过期机制: memcached的item ... -
Yahoo!社区架构 - zt
2008-02-26 21:47 1368旧金山举行的 QCon 会议 ... -
Tailrank 网站架构 - zt
2008-02-26 21:48 803每天数以千万计的 Blog ... -
Web缓存加速指南 - zt
2008-02-26 21:54 883这是一篇知识性的文档 ... -
Digg 网站架构 - zt
2008-02-26 21:57 987国庆期间又收集了一些关于网站架构的信息。一直没有进行系统的整理 ... -
WikiPedia 技术架构学习分享 - zt
2008-02-26 21:56 1132维基百科(WikiPedia.org)位 ... -
Twitter 的架构扩展: 100 倍性能提升 - zt
2008-02-26 21:58 1115Twitter 是我最近一段时间用的最多的网络服务之一.还记得 ... -
最便宜的高负载网站架构 - zt
2008-02-26 22:20 9291, LVS做前端四层均衡负载基于IP虚拟分发的规则,不同于a ... -
分析mixi.jp and Yeejee.com:用开源搭建的可扩展大型SNS网站 - zt
2008-02-26 22:23 1569分析mixi.jp and Yeejee.com: ... -
开发大型高负载类网站应用的几个要点 - zt
2008-02-26 22:26 1017看了一些人的所谓大型项目的方法,我感觉都是没有说到点子上,有点 ... -
FeedBurner:基于MySQL和JAVA的可扩展Web应用 - zt
2008-02-26 22:32 1071FeedBurner(以下简称FB,呵呵)我想应该是大家耳熟能 ...
相关推荐
tar -zxvf pecl-memcache-4.0.4.tar.gz && cd /root/pecl-memcache-4.0.4 && /usr/local/php7/bin/phpize && ./configure --with-php-config=/usr/local/php7/bin/php-config && make && make install
赠送jar包:netty-codec-memcache-4.1.73.Final.jar; 赠送原API文档:netty-codec-memcache-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-memcache-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:...
6. `memcache_increment()` 和 `memcache_decrement()`:对整数值的键进行加减操作。 **四、Memcache在实际应用中的优势** 1. **性能提升**:通过将常用数据缓存到内存中,避免了频繁的数据库查询,极大地提高了...
$memcache->connect('localhost', 11211); // 默认的Memcache服务器端口是11211 $memcache->set('key', 'value', 0, 60); // 存储键值对,第二个参数为0表示永不过期,第三个参数为过期时间(秒) $stored_value ...
PHP7-memcache-dll-master.zip 是一个针对PHP 7.0及以上版本的Memcache扩展插件包。Memcache是一款广泛使用的开源分布式内存对象缓存系统,它能够提高Web应用程序的性能,通过将数据存储在内存中,减少对数据库的...
赠送jar包:netty-codec-memcache-4.1.74.Final.jar; 赠送原API文档:netty-codec-memcache-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-memcache-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:...
赠送jar包:netty-codec-memcache-4.1.73.Final.jar; 赠送原API文档:netty-codec-memcache-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-memcache-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:...
赠送jar包:netty-codec-memcache-4.1.74.Final.jar; 赠送原API文档:netty-codec-memcache-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-memcache-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:...
标题中的"window-php7.1-memcache-dll"指的是在Windows操作系统环境下,与PHP 7.1版本兼容的Memcache扩展的动态链接库(DLL)文件。这个扩展允许PHP程序连接并操作Memcache服务器,以实现高效的数据缓存。 Memcache...
无需php-memcache扩展支持,引入单个文件即可连接memcached服务。 使用方法: $mc = new memcached(array( 'servers' => array('127.0.0.1:11211'), 'debug' => false, 'compress_threshold' => 10240, '...
memcache.dll 跟PHP版本关联有2个参数,一个是PHP Extension Build 例如:API20151012,NTS,VC14 一个是Architecture 例如:x86 所以我们选择的dll文件应该是 vc14 x86 nts 7.0版
《PyPI上的nexus-memcache-0.3.6:深入理解缓存与数据库集成》 在Python的生态系统中,PyPI(Python Package Index)是开发者获取和分享开源软件包的重要平台。本文将围绕PyPI上的一款名为“nexus-memcache”的库...
$memcache->set('key', 'value', 0, 3600); // 存储数据 $data = $memcache->get('key'); // 获取数据 echo $data; // 输出:value $memcache->close(); // 关闭连接 ?> ``` 以上就是Windows环境下...
标题中的“PHP7-memcache-dll-4.0.4.zip”指的是一个适用于PHP7的Memcache扩展的DLL动态链接库文件,版本为4.0.4的压缩包。这个压缩包通常包含了PHP与Memcache服务器通信所需的所有组件,以便在PHP7环境下启用...
离线安装包,亲测可用
在`memcacheclient-2.0`中,开发团队对连接池进行了深度优化,确保了连接的正确回收和复用,减少了系统资源的消耗,提升了服务的可靠性。 其次,另一个修复的关键Bug可能涉及到数据一致性问题。在分布式缓存环境中...
【maven-spring-memcache】项目是一个关于如何在Spring框架中集成并使用Memcache作为缓存技术的示例。Memcache是一种广泛使用的分布式内存对象缓存系统,它能够提高Web应用程序的性能,通过将数据存储在内存中,减少...
10-编译php-memcache扩展.wmv
在实际开发中,Memcache可以与其他技术结合使用,如Laravel框架中的Cache服务,或者作为WordPress等CMS系统的缓存解决方案。同时,开发者需要注意Memcache的内存管理机制,合理设置缓存过期时间和大小,以避免内存...
压缩包文件名“PHP7-memcache-dll-master”可能表示这是一个包含所有相关版本(可能是PHP7.0和PHP7.1)的主文件集合,或者可能指代源代码仓库的主分支,这通常意味着用户可以在这里找到最新、最完整的memcache.dll...