memcached源代码分析

合集下载

pythonmemcache简单操作

pythonmemcache简单操作

pythonmemcache简单操作python memcache 简单操作 (用于web前端优化,减少读库次数)2013-05-21 09:29:11| 分类: Python | 标签: |举报 |字号大中小订阅Memcached官网简单介绍:memcached很强大,它可以支持分布式的共享内存缓存,大型站点都用它。

对小站点来说,有足够内存的话,使用它也可以得到超赞的效果。

使用目的:由前面的介绍看到,大家使用它都是为了速度,不过我却是为了解决Session在不同浏览器中偶尔丢失的数据。

其实也不能怪浏览器啦,主要是我需要一个dict类型的session,哈哈。

安装Linux安装包对于大多数Linux发行版本来说,可以使用官方推荐的方法:Debian/Ubuntuapt-get install memcachedRedhat/Fedora/CentOSyum install memcached源码安装(CentOS 5.5)1、下载libevent(依赖)和memcached分别到以下引用地址下载最新版本:引用地址/~provos/libevent/引用地址:/p/memcached/downloads/list2、安装ibevent(依赖)和memcachedlibevent(目前最新是libevent-2.0.10-stable.tar.gz,请注意版本号)tar xvf libevent-2.0.10-stable.tar.gzcd libevent-2.0.10-stable./configure --prefix=/usr/local/libevent/makemake install接着,ls /usr/local/libevent/lib,将查看到的第一个类似libevent-X.X.so.Xln -s /usr/local/libevent/lib/libevent-2.0.so.5 /lib/libevent-2.0.so.5memcached (目前最新是1.4.5,请注意版本号)tar zxvf memcached-1.4.5.tar.gzcd memcached-1.4.5./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent/makemake install3、启动memcached启动参数说明(这是我是复制粘贴的,如有错误请指正):-d 选项是启动一个守护进程-m 是分配给Memcache使用的内存数量,单位是MB,默认64MB-M return error on memory exhausted (rather than removing items)-u 是运行Memcache的用户,如果当前为root 的话,需要使用此参数指定用户-l 是监听的服务器IP地址,默认为所有网卡-p 是设置Memcache的TCP监听的端口,最好是1024以上的端口-c 选项是最大运行的并发连接数,默认是1024-P 是设置保存Memcache的pid文件-f chunk size growth factor (default: 1.25)-I Override the size of each slab page. Adjusts max item size(1.4.2版本新增)例子:/usr/local/memcached/bin/memcached -d -m 100 -c 1000 -u root -p 11211可以启动多个守护进程,但是端口不能重复。

memcached编译

memcached编译

memcached编译
要编译Memcached,首先你需要确保你的系统中安装了编译Memcached所需的依赖项。

通常情况下,你需要安装开发工具包和
相关的库文件。

接下来,你可以按照以下步骤进行编译:
1. 下载Memcached源代码,你可以从Memcached官方网站或者GitHub上获取Memcached的源代码。

下载后解压到你选择的目录中。

2. 进入解压后的Memcached目录,使用终端或命令行工具进入
解压后的Memcached目录。

3. 运行配置脚本,运行`./configure`命令来配置Memcached
的编译选项。

你可以使用`--help`参数来查看可用的配置选项。

例如,你可以指定安装路径等选项。

4. 编译,运行`make`命令来编译Memcached。

这将会生成可执
行文件。

5. 安装,运行`make install`命令来安装编译好的Memcached
可执行文件和相关的文件到系统中。

你可能需要使用`sudo`命令来
获取足够的权限进行安装。

完成上述步骤后,你就成功地编译并安装了Memcached。

你可以通过运行`memcached`命令来启动Memcached服务器。

记得查看Memcached的文档以获取更多详细的信息和配置选项。

希望这些步骤可以帮助你成功编译Memcached。

Memcached 原理剖析

Memcached 原理剖析

余问题都解决了,空间利用率会大大提升。
修改 slabs_clsid 函数,让它直接返回一个定值(比如 1 )
unsigned int slabs_clsid(size_t size) {return 1;}
修改slabs_init函数,去掉循环创建所有classid属性的部分,直接添加
slabclaபைடு நூலகம்s[1]:
• 数据存储方式:Slab Allocation • 数据过期方式:Lazy Expiration + LRU
7
Memcache原理分析
数据存储方式:Slab Allocation
Slab Alloction 构造图
Slab Allocator的基本原理是按照预先 规定的大小,将分配的内存分割成特定 长度的块,以完全解决内存碎片问题。
Memcached 入门
作者:
2009-01
Tech Talk 目录索引
Memcache是什么 Memcache,ehcache的比较 Memcache原理分析 Memcache安装和基本配置 Memcache的在大型网站中的使用策略 Memcache的一些经验和技巧 Memcache一致性算法(consistent hasing)
一个id,在数据量非常大的情况下,slab链会很长(因为所有数据都挤在一条
链上了),遍历起来的代价比较高。
前面介绍了三种空间冗余,设置chunk长度等于item长度,解决了第一种空间
浪费问题,不预申请空间解决了第二种空间浪费问题,那么对于第一种问题
(slab内剩余)如何解决呢,这就需要修改POWER_BLOCK常量,使得每一
15
Memcache原理分析:

Memcached源码剖析笔记

Memcached源码剖析笔记

Memcached源码剖析笔记XguruMemcached是一个自由、源码开放、高性能、分布式内存对象缓存系统,目的在于通过减轻数据库负载来使动态Web应用程序提速。

目录1.背景 (3)2.memcached的安装 (4)3.memcached的配置 (5)4.memcached的使用 (6)4.1.存储命令 (7)4.2.读取命令 (8)4.3.删除命令 (8)4.4.高级命令 (9)4.5.其他命令 (10)5.Memcached内部工作机制 (11)5.1.Memcached基本的数据结构 (11)5.2.基本设计概念和处理流程 (12)5.3.内部Hash机制 (15)5.3.1.Hash函数及冲突解决 (15)5.3.2.HashTable主要函数 (15)5.4.slab内存处理机制 (17)5.4.1.slab主要函数 (17)5.4.2.slab机制中所采用的LRU算法 (19)5.5.控制item各种函数 (20)5.6.守护进程机制 (22)5.7.Socket处理机制 (23)15.7.1.Unix域协议 (23)5.7.2.TCP/UDP协议 (24)5.8.多线程处理机制 (25)5.9.事件处理机制 (25)6.未完善之处 (27)7.参考文献 (28)21.背景Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。

它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。

Memcached基于一个存储键/值对的hashmap。

Memcached是一个自由、源码开放、高性能、分布式内存对象缓存系统,目的在于通过减轻数据库负载来使动态Web应用程序提速。

Memcached是一个在内存中对任意的数据(比如字符串,对象等)所使用的key-value 存储。

数据可以来自数据库调用,API调用,或者页面渲染的结果。

memcached源码分析一-slab

memcached源码分析一-slab

memcached源码分析⼀-slabSlab作为⼀种内存管理⽅案,其作⽤主要有以下2点:a) 避免频繁的内存分配释放造成的内存碎⽚b) 减少内存分配操作产⽣的性能开销Linux内核数据结构中也有slab的设计,Linux提供了⼀套接⼝,使⽤这套接⼝可以动态创建与释放⼀个slab结构,该slab的chunk⼤⼩通过接⼝指定,创建成功后就可以从该slab中动态申请与释放chunk⼤⼩的内存⽤于存储⽬标数据,例如内核中⽤于表⽰进程的结构体task_struc 就是使⽤的slab⽅式进⾏管理。

memcached与linux内核不同,memcached中在程序启动时即初始化⼀个slabclass_t的全局数组,每⼀个slabclass_t结构的chunk⼤⼩不同,构成⼀个全局slab池。

memcached中的slab相关操作源码主要集中在源⽂件slabs.c中,下⾯对它进⾏分析。

1. 结构体slabclass_t以下是memcached中对slabclass_t的定义,typedef struct {unsigned int size; /* sizes of items */unsigned int perslab; /* how many items per slab */void *slots; /* list of item ptrs */unsigned int sl_curr; /* total free items in list */unsigned int slabs; /* how many slabs were allocated for this class */void **slab_list; /* array of slab pointers */unsigned int list_size; /* size of prev array */size_t requested; /* The number of requested bytes */} slabclass_t;slabclass_t对内存的组织可以粗略的⽤图1-1表⽰,图1-1 slabclass_t内存组织⽅式slab_list是⼀个可以动态分配的数组,数组⼤⼩以list_size表⽰,数组中已存储元素数⽬以slabs表⽰,数组中每⼀个元素都表⽰⼀个page ⼤⼩的可⽤内存(page也称为slab)。

Python中的Memcached缓存

Python中的Memcached缓存

Python中的Memcached缓存Memcached是一款高性能的分布式内存对象缓存系统。

它的主要功能是将数据存储在内存中,从而提高数据访问速度。

作为一款大型网站所必不可少的缓存工具,Memcached在Python 中的应用极度广泛。

在这篇论文中,我们将深入探讨Memcached在Python中的应用,分析其优点和缺点,并提出一些最佳实践,以帮助开发人员更好地利用Memcached提升应用的性能和用户体验。

一、Memcached的优点1.高速缓存Memcached是一款基于内存的缓存系统,它可以实现非常快速的缓存访问速度。

由于数据存储在内存中,所以它的响应速度相当快,甚至可以达到微秒级别。

在大型网站前端中,常使用Memcached来缓存一些静态或不怎么变化的数据,如网站配置信息、静态页面等。

通过缓存这些数据,可以减少对数据库等后端系统的请求,从而提高网站的性能。

2.可扩展性Memcached是一款分布式缓存系统,它可以将缓存数据分散存储在多台机器的内存中,从而实现更大的存储容量和更高的并发处理能力。

在高并发的情况下,系统可以简单地通过增加或减少服务器数量来扩展缓存能力。

此外,Memcached还具有自动数据平衡和故障转移等功能,可以实现高可用性和灵活性。

3.支持多种语言Memcached支持多种语言,包括Python、Java、PHP等,可以方便地嵌入到各种应用程序中,快速提高应用程序的性能。

在Python中,Memcached是一种常见的缓存解决方案,可以通过安装对应的Python模块,轻松地集成到应用程序中。

二、Memcached的缺点1.容量限制由于Memcached是一款基于内存的缓存系统,所以它的缓存容量是有限的。

在实际应用中,需要根据业务需求和服务器硬件条件等因素综合考虑,设置合适的缓存容量,避免因容量不足而导致缓存失效。

2.数据不持久化Memcached只是一款内存缓存系统,它并不支持数据持久化。

memcached字符编码

memcached字符编码

memcached字符编码Memcached 是一款开源的高性能分布式内存对象缓存系统,它主要用于缓存数据库查询结果、API调用结果或其他计算成本高的操作的结果,从而提高应用程序的性能和响应速度。

在 Memcached 中,字符编码主要涉及两个方面,存储数据时的编码和读取数据时的解码。

1. 存储数据时的编码:当我们向 Memcached 存储数据时,通常是以字符串的形式进行存储。

Memcached 默认使用的字符编码是 ASCII 编码,它是一种基于拉丁字母的字符编码标准,支持英文字母、数字和一些特殊字符。

ASCII 编码每个字符占用一个字节的存储空间。

另外,Memcached 也支持使用其他字符编码存储数据,如UTF-8 编码。

UTF-8 是一种可变长度的 Unicode 字符编码,它可以表示世界上几乎所有的字符。

UTF-8 编码中,英文字母和数字仍然只占用一个字节的存储空间,而中文、日文、韩文等非拉丁字符则占用多个字节的存储空间。

2. 读取数据时的解码:当我们从 Memcached 中读取数据时,Memcached 会将存储的字符串数据解码成对应的字符编码。

如果存储时使用的是 ASCII编码,那么读取时就会解码成 ASCII 编码的字符串。

同理,如果存储时使用的是 UTF-8 编码,那么读取时就会解码成 UTF-8 编码的字符串。

在读取数据时,我们的应用程序需要根据具体的需求和使用的编程语言,将解码后的字符串再进行进一步的处理和转换。

例如,在使用 Python 进行开发时,可以使用内置的字符串处理函数来处理解码后的字符串。

需要注意的是,Memcached 本身并不关心存储的数据的具体编码方式,它只是将数据当作二进制的字节流进行存储和读取。

因此,在使用 Memcached 存储和读取数据时,我们需要确保应用程序和Memcached 之间的数据编码方式是一致的,以避免出现乱码或数据解析错误的情况。

memcache slab模块源码解读

memcache slab模块源码解读

memcache slab模块源码解读slab模块简介由于采用常用的malloc和free函数会造成内存碎片比较多,所以memcache采用的是自己写的slab内存管理模块来管理内存,特点如下:∙系统中用不同大小的chunk(struct item)来存数据,对某个需要缓存的数据,找到最适合大小的item来保存∙系统中分为多个slabclass,每个slabclass有一个或多个slab,每个slab 里面包含多个大小相同的itemslab结构体关系图我们从某个slabclass来看其与slab、item之间的关系从图中可以看出,每个slabclass对应一个或多个slab,在slabclass_t结构体里面有个slab_list数组,其指向的是每个slab内存块的首地址(在这里,特别说明一下,slab是一段连续的内存空间,和操作系统中的内存页有点类似,memcache没有专门的一个结构体来描述它,只要其首地址来比较某个slab),而每个slab中有多个chunk(struct item)数据块用来存数据整个系统的slab初始化过程在memcache模块初始化的时候,首先调用的函数是slab_init,其源码如下:/*** Determines the chunk sizes and initializes the slab class descriptors* accordingly.*/void slabs_init(const size_t limit, const double factor, const bool prealloc) {int i = POWER_SMALLEST - 1;unsigned int size = sizeof(item) + settings.chunk_size;mem_limit = limit;if (prealloc) {/* Allocate everything in a big chunk with malloc */mem_base = malloc(mem_limit);if (mem_base != NULL) {mem_current = mem_base;mem_avail = mem_limit;} else {fprintf(stderr, "Warning: Failed to allocate requested memory in" " one large chunk.\nWill allocate in smaller chunks\n"); }}memset(slabclass, 0, sizeof(slabclass));while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) { /* Make sure items are always n-byte aligned */if (size % CHUNK_ALIGN_BYTES)size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);slabclass[i].size = size;slabclass[i].perslab = settings.item_size_max / slabclass[i].size;size *= factor;if (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n", i, slabclass[i].size, slabclass[i].perslab);}}power_largest = i;slabclass[power_largest].size = settings.item_size_max;slabclass[power_largest].perslab = 1;if (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);}/* 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 = (size_t)atol(t_initial_malloc);}}if (prealloc) {slabs_preallocate(power_largest);}}我们来分析这个函数:1.首先申请mem_limit大小的内存块2.while循环中对管理item大小不同的slabclass_t结构体进行初始化3.调用slabs_preallocate对分配mem_limit大小的内存块进行具体的处理下面,我们来看slabs_preallocate的代码:static void slabs_preallocate (const unsigned int maxslabs) {int i;unsigned int prealloc = 0;/* pre-allocate a 1MB slab in every size class so people don't getconfused by non-intuitive "SERVER_ERROR out of memory"messages. this is the most common question on the mailinglist. if you really don't want this, you can rebuild withoutthese three lines. */for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) {if (++prealloc > maxslabs)return;if (do_slabs_newslab(i) == 0) {fprintf(stderr, "Error while preallocating slab memory!\n""If using -L or other prealloc options, max memory must be " "at least %d megabytes.\n", power_largest);exit(1);}}}从代码可以看出:1.slabs_preallocate会对所有的slabclass_t进行分配slab的操作(这里需要注意的是,初始化的时候默认每个slabclass是只有一个slab的),即do_slabs_newslab函数下面就进接着看do_slabs_newslab函数static int do_slabs_newslab(const unsigned int id) {slabclass_t *p = &slabclass[id];int len =? settings.item_size_max: p->size * p->perslab;char *ptr;if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) ||(grow_slab_list(id) == 0) ||((ptr = memory_allocate((size_t)len)) == 0)) {MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id);return 0;}memset(ptr, 0, (size_t)len);split_slab_page_into_freelist(ptr, id);p->slab_list[p->slabs++] = ptr;mem_malloced += len;MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id);return 1;}do_slabs_newslab函数的功能就是为某个slabclass新分配一个slab大小的内存块1.当memcache分配一个新的slab时会造成所使用的内存超过对定的mem_limit大小时,则会提示内存不够分配2.当mem_limit大小的内存够分配的时候,则调用grow_slab_list来根据需要扩充struct slabclass_t中void **slab_list数组的大小,然后就是用memory_allocate函数分配一个slab内存块3.然后调用split_slab_page_into_freelist函数把slab内存块分成若干个item,然后把这些空闲的item都插入到slabclass_t中的void *slots指向的链表中4.把新分配的slab的首地址添加到'slabclass_t`数组中去5.跟新memcache已申请的内存大小mem_malloced这样memcache的slab模块的初始化工作就完成了item相关操作在整个memcache内存管理slab系统初始化完成后,就进入了memcahe的运行阶段,这时候,会涉及到的一些操作是(在文件items.c中)∙item的分配∙item的释放∙item获取∙item链接到队列(当一个item被set的时候,会链接到队列)∙item从队列中取消链接下面我们会依次序来说上述的几个操作:item的分配item的分配对应于do_item_alloc先给出do_item_alloc的程序流程图然后贴出代码item *do_item_alloc(char *key, const size_t nkey, const int flags,const rel_time_t exptime, const int nbytes,const uint32_t cur_hv) {uint8_t nsuffix;item *it = NULL;char suffix[40];size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix); if (e_cas) {ntotal += sizeof(uint64_t);}unsigned int id = slabs_clsid(ntotal);if (id == 0)return 0;mutex_lock(&cache_lock);/* do a quick check if we have any expired items in the tail.. */int tries = 5;int tried_alloc = 0;item *search;void *hold_lock = NULL;rel_time_t oldest_live = settings.oldest_live;search = tails[id];/* We walk up *only* for locked items. Never searching for expired.* Waste of CPU for almost all deployments */for (; tries > 0 && search != NULL; tries--, search=search->prev) {uint32_t hv = hash(ITEM_key(search), search->nkey, 0);/* Attempt to hash item lock the "search" item. If locked, no* other callers can incr the refcount*//* FIXME: I think we need to mask the hv here for comparison? */if (hv != cur_hv && (hold_lock = item_trylock(hv)) == NULL)continue;/* Now see if the item is refcount locked */if (refcount_incr(&search->refcount) != 2) {refcount_decr(&search->refcount);/* Old rare bug could cause a refcount leak. We haven't seen* it in years, but we leave this code in to prevent failures* just in case */if (search->time + TAIL_REPAIR_TIME < current_time) {itemstats[id].tailrepairs++;search->refcount = 1;do_item_unlink_nolock(search, hv);}if (hold_lock)item_trylock_unlock(hold_lock);continue;}/* Expired or flushed *//**检查LRU尾部的item是否超时,如果超时直接,返回这个item即可**/if ((search->exptime != 0 && search->exptime < current_time)|| (search->time <= oldest_live && oldest_live <= current_time)) {itemstats[id].reclaimed++;if ((search->it_flags & ITEM_FETCHED) == 0) {itemstats[id].expired_unfetched++;}it = search;slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal); do_item_unlink_nolock(it, hv);/* Initialize the item block: */it->slabs_clsid = 0;} else if ((it = slabs_alloc(ntotal, id)) == NULL) { /*尝试去slab中申请一个新的item*/tried_alloc = 1;if (settings.evict_to_free == 0) {/*如果在slab中申请失败,并且不允许LRU 替换策略*/itemstats[id].outofmemory++;} else {/*如果在slab申请失败,但是允许LRU策略,那么就从LRU队尾取出一个item*/itemstats[id].evicted++;itemstats[id].evicted_time = current_time - search->time;if (search->exptime != 0)itemstats[id].evicted_nonzero++;if ((search->it_flags & ITEM_FETCHED) == 0) {itemstats[id].evicted_unfetched++;}it = search;slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal);do_item_unlink_nolock(it, hv);/* Initialize the item block: */it->slabs_clsid = 0;/* If we've just evicted an item, and the automover is set to* angry bird mode, attempt to rip memory into this slab class. * TODO: Move valid object detection into a function, and on a* "successful" memory pull, look behind and see if the next alloc * would be an eviction. Then kick off the slab mover before the * eviction happens.*/if (settings.slab_automove == 2)slabs_reassign(-1, id);}}refcount_decr(&search->refcount);/* If hash values were equal, we don't grab a second lock */if (hold_lock)item_trylock_unlock(hold_lock);break;}if (!tried_alloc && (tries == 0 || search == NULL))it = slabs_alloc(ntotal, id);if (it == NULL) {itemstats[id].outofmemory++;mutex_unlock(&cache_lock);return NULL;}assert(it->slabs_clsid == 0);assert(it != heads[id]);/* Item initialization can happen outside of the lock; the item's already * been removed from the slab LRU.*/it->refcount = 1; /* the caller will have a reference */mutex_unlock(&cache_lock);it->next = it->prev = it->h_next = 0;it->slabs_clsid = id;DEBUG_REFCNT(it, '*');it->it_flags = e_cas ? ITEM_CAS : 0;it->nkey = nkey;it->nbytes = nbytes;memcpy(ITEM_key(it), key, nkey);it->exptime = exptime;memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);it->nsuffix = nsuffix;return it;}请注意:我刚开始读这段代码的时候有个最不清楚的地方就是那个for循环好像执行了5次,如果这5次for循环都没找到过期的item,那么岂不是会调用slab_alloc函数5次,重复分配了5次item吗?答案:后来仔细一看,原来在for循环的最后一行代码有个break语句,那么这就说明其实for循环里面的语句最多执行一次,也就不会有上面的问题了。

Memcached 源码分析--命令流程分析

Memcached 源码分析--命令流程分析

Memcached 源码分析--命令流程分析一、执行命令首先是启动memcached 自带参数如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">-p <num> 设置TCP端口号(默认设置为: 11211)-U <num> UDP监听端口(默认: 11211, 0 时关闭)-l <ip_addr> 绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)-c <num> max simultaneous connections (default: 1024)-d 以daemon方式运行-u <username> 绑定使用指定用于运行进程<username>-m <num> 允许最大内存用量,单位M (默认: 64 MB)-P <file> 将PID写入文件<file>,这样可以使得后边进行快速进程终止, 需要与-d 一起使用</span>#$: ./usr/local/bin/memcached -d -u root -l 192.168.10.156 -m 2048 -p 12121客户端通过网络方式连接:telnet 192.168.10.156 12121然后就可以操作命令、常见命令如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">setaddreplacegetdelete</span>格式如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">command <key> <flags> <expiration time> <bytes><value>参数说明如下:command set/add/replacekey key 用于查找缓存值flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)bytes 在缓存中存储的字节点value 存储的值(始终位于第二行)</span>二、命令执行流程代码分析首先看一下工作线程中的命令数据结构:/*** The structure representing a connection into memcached.*/typedef struct conn conn;非常重要的几个参数:char * rbuf:用于存储客户端数据报文中的命令。

Memcached内存管理源码阅读

Memcached内存管理源码阅读

Memcached内存管理源码阅读meache能举行迅速地查找和良好的内存管理,得益于良好的hash查找和内存管理技巧.这两项功能主要由assoc.c和slab.c这两个文件来实现. 下面具体地分析一下每行代码实现slab.cdefine POWER_SMALLEST1 //slabclass数组的最小下标(slabclass 主要是来保存分配好的内存)define POWER_LARGEST 200 //slabclass数组的最大下标define POWER_BLOCK 1048576 //每一个chunk的最大值defineCHUNK_ALIGN_BYTES 8 //内存对其define DONT_PREALLOC_SLABS //不采纳事前分配内存/* powers-of-N alloion suctures *//*管理内存的主要数据结构, 搞清晰这个数据结构对囫囵内存的用法,分配,释放都很重要*/typef struct { unsigned int size; /* sizes of items */ //该结构保存的item的size大小,即最多能保存多大的数据 unsigned int perslab; /* how many items per slab */ //分配好一个slab 后,该slab可以存储多少个大小size的 vo **slots; /* list of item ptrs */ //回收回归后,内存的数组 unsigned int sl_total; /* size of previous array */ //目前总共有多少个空余的内存块 unsigned int sl_curr; /* first slot */ //目前已经用法到了多少个内存块void *end_page_ptr; /* pointer to nt free item at end of page, or 0 */ //每个slab中,可用法的地址 unsigned int end_page_free; /* number of items remaining at end of last alloced page */ //该slab中,可用法的内存块大小 unsigned int slabs; /* how many slabs were ald for this class */ //已经用法slab void **slab_list; /* array of slab pointers */ //保存每个slab的起始地址unsigned int list_size; /* size of prev array */ //总共有多少个slab unsigned int ing; /* index+1 of dying slab, or zero if none */} slabclass_t;ic slabclass_t slabclass[POWER_LARGEST + 1]; //核心的slabclass变量, 保存全部的内存static size_tmem_limit = 0; //限制memcache内存的用法的大小static size_t第1页共2页。

Memcache所有方法及参数详解

Memcache所有方法及参数详解

Memcache所有⽅法及参数详解memcache函数所有的⽅法列表如下:参考/manual/zh/function.Memcache-add.phpMemcache::add - 添加⼀个值,如果已经存在,则返回falseMemcache::addServer - 添加⼀个可供使⽤的服务器地址Memcache::close - 关闭⼀个Memcache对象Memcache::connect - 创建⼀个Memcache对象memcache_debug - 控制调试功能Memcache::decrement - 对保存的某个key中的值进⾏减法操作Memcache::delete - 删除⼀个key值Memcache::flush - 清除所有缓存的数据Memcache::get - 获取⼀个key值Memcache::getExtendedStats - 获取进程池中所有进程的运⾏系统统计Memcache::getServerStatus - 获取运⾏服务器的参数Memcache::getStats - 返回服务器的⼀些运⾏统计信息Memcache::getVersion - 返回运⾏的Memcache的版本信息Memcache::increment - 对保存的某个key中的值进⾏加法操作Memcache::pconnect - 创建⼀个Memcache的持久连接对象Memcache::replace -对⼀个已有的key进⾏覆写操作Memcache::set - 添加⼀个值,如果已经存在,则覆写Memcache::setCompressThreshold - 对⼤于某⼀⼤⼩的数据进⾏压缩Memcache::setServerParams - 在运⾏时修改服务器的参数Memcache::add⽤法bool Memcache::add ( string $key , mixed $var [, int $flag [, int $expire ]] )说明:如果key不存在的时候,使⽤这个函数来存储var的值。

Memcached命令详细解释

Memcached命令详细解释
-rwxr-xr-x 1 root root 202029 Nov 15 23:07 /usr/local/bin/memcached
windows下的安装
下载windows下的memcached程序:/memcached-win32/
解压之后双击安装即可。安装完毕可以在控制面板–》管理工具–》服务中看到已安装的服务信息:
1)安装libevent
cd /opt/install
tar zxvf libevent-1.4.12-stable.tar.gz
cd libevent-1.4.12-stable
./configure
make
make install
2)安装memcached,将软件上传到/opt文件夹下
VALUE userid 0 5 10
54321
END
#修改版本号位10的key=userid数据
cas userid 0 0 5 10
55555
#修改成功
STORED
#删除key=userid的数据
delete userid
#删除成功
DELETED
3)添加开机自启服务,在/etc/rc.local文件中加载启动命令,参数需要根据实际情况指定,如
管理说明
1)启动参数说明
如下命令是root用户以守护进程的形式启动 memcached,为其分配 256M 内存
memcached -d -m 256 -u root –c 10240
memcached -d -m 2048 -u root -c 10240
主要启动参数说明
-d
2)管理参数说明

memcached 参数

memcached 参数

memcached参数
Memcached是一种高性能的分布式内存缓存系统,它常用于提升Web应用程序的性能和可扩展性。

以下是一些常见的Memcached参数和其作用的简要说明:
1.`-p`或`--port`:指定Memcached服务器监听的端口号,默认为11211。

2.`-l`或`--listen`:指定Memcached服务器监听的IP地址,默认为所有可用地址。

3.`-m`或`--memory`:指定分配给Memcached的内存容量,以MB为单位。

4.`-c`或`--connections`:指定Memcached服务器可以同时处理的最大连接数。

5.`-t`或`--threads`:指定Memcached服务器使用的线程数。

6.`-k`或`--lock-memory`:锁定分配给Memcached的内存,防止其他进程使用。

7.`-M`或`--disable-eviction`:禁用缓存淘汰机制,即不会自动删除过期或较少使用的数据。

8.`-I`或`--max-item-size`:设置Memcached中每个存储项的最大大小,默认为1MB。

9.`-f`或`--factor`:设置缓存大小增长的因子,用于动态扩展内存。

10.`-n`或`--min-threads`:指定空闲线程的最小数量,用于处理请求。

11.`-R`或`--max-requests`:限制每个连接的最大请求数。

12.`-B`或`--binary-protocol`:启用Memcached的二进制协议。

Memcache 1.2.0 源码分析报告

Memcache 1.2.0 源码分析报告

Memcache 1.2.0源码分析报告Kingkai/10.9.26概述Memcache在系统中扮演的角色往往是分布式Cache。

但两个主要的概念首先需要澄清:1.Memcache本身不支持分布式的流量分发,负载均衡等。

这些工作均是由php扩展,perl扩展等完成。

2.Memcache本身是一个单进程单线程的模块。

Memcache代码总量在3000行左右,思路清晰,设计精巧,是业余阅读的上等选择。

Memcache在日志,save/load方面的弱点可以通过二次开发来弥补。

Memcache在多线程方面,则不容易进行二次开发,那将破坏相当多的内部设计。

数据结构:Slab结构体意义typedef struct {unsigned int size; //该ID槽中的slab里item的大小unsigned int perslab; //一个slab里可以包含多少个itemvoid **slots; //指向空闲的item,空闲由于delete等操作造成unsigned int sl_total; //当前slot可以支持的最大空闲item数量unsigned int sl_curr; //当前空闲item下标,需要时可以直接获取,在add,set 等操作时优先采用空闲的itemvoid *end_page_ptr; //指向当前slab里下一个空闲的item,如果没有,则为0 unsigned int end_page_free; //当前slab里还剩余多少个itemunsigned int slabs; //当前这个ID槽中已经分配出去的slab数量void **slab_list; //指向已分配出的slab头指针unsigned int list_size; //slab_list可以支持的slab个数unsigned int killing; /* index+1 of dying slab, or zero if none */} slabclass_t;typedef struct _stritem {struct _stritem *next; //同一个slab ID中的下一个itemstruct _stritem *prev; //同一个slab ID中的上一个itemstruct _stritem *h_next; //同一个hash 桶中的下一个itemrel_time_t time; /* least recent access */rel_time_t exptime; //即最终使得该节点失效的时间点int nbytes; //value部分的大小unsigned short refcount; //被引用的计数unsigned char nsuffix; //nsuffix部分的大小unsigned char it_flags; //该节点当前的状态,如DELETED或LINKEDunsigned char slabs_clsid; //属于哪一个slab IDunsigned char nkey; //key部分的大小void * end[0]; //尾部填充/* then null-terminated key *//* then " flags length\r\n" (no terminating null) *//* then data with terminating \r\n (no terminating null; it's binary!) */} item;尾部填充宏:#define ITEM_key(item) ((char*)&((item)->end[0]))#define ITEM_suffix(item) ((char*) &((item)->end[0]) + (item)->nkey)#define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey + (item)->nsuffix)#define ITEM_ntotal(item) (sizeof(struct _stritem) + (item)->nkey + (item)->nsuffix + (item)->nbytes)内存管理:命令格式:可以支持的操作包括add,set,replace,get,delete等。

PHP内存缓存Memcached类实例

PHP内存缓存Memcached类实例

PHP内存缓存Memcached类实例PHP内存缓存Memcached类实例PHP内存缓存Memcached类,以实例形式分析了PHP内存缓存Memcached的实现方法,是php操作memcached的典型应用,非常具有实用价值,需要的朋友可以参考下。

具体实现方法如下:复制代码代码如下:<?PHPclass MemcacheModel {private $mc = null;/*** 构造方法,用于添加服务器并创建memcahced对象*/function __construct(){$params = func_get_args();$mc = new Memcache;//如果有多个memcache服务器if( count($params) > 1){foreach ($params as $v){call_user_func_array(array($mc, 'addServer'), $v);}//如果只有一个memcache服务器} else {call_user_func_array(array($mc, 'addServer'), $params[0]);}$this->mc=$mc;}/*** 获取memcached对象* @return object memcached对象*/function getMem(){return $this->mc;}/*** 检查mem是否连接成功* @return bool 连接成功返回true,否则返回false*/function mem_connect_error(){$stats=$this->mc->getStats();if(emptyempty($stats)){return false;}else{return true;}}private function addKey($tabName, $key){$keys=$this->mc->get($tabName);if(emptyempty($keys)){$keys=array();}//如果key不存在,就添加一个if(!in_array($key, $keys)) {$keys[]=$key; //将新的key添加到本表的keys中$this->mc->set($tabName, $keys, MEMCACHE_COMPRESSED, 0);return true; //不存在返回true}else{return false; //存在返回false}}/*** 向memcache中添加数据* @param string $tabName 需要缓存数据表的表名* @param string $sql 使用sql作为memcache的key* @param mixed $data 需要缓存的数据*/function addCache($tabName, $sql, $data){$key=md5($sql);//如果不存在if($this->addKey($tabName, $key)){$this->mc->set($key, $data, MEMCACHE_COMPRESSED, 0); }}/*** 获取memcahce中保存的`数据* @param string $sql 使用SQL的key* @return mixed 返回缓存中的数据*/function getCache($sql){$key=md5($sql);return $this->mc->get($key);}/*** 删除和同一个表相关的所有缓存* @param string $tabName 数据表的表名*/function delCache($tabName){$keys=$this->mc->get($tabName);//删除同一个表的所有缓存if(!emptyempty($keys)){foreach($keys as $key){$this->mc->delete($key, 0); //0 表示立刻删除}}//删除表的所有sql的key$this->mc->delete($tabName, 0);}/*** 删除单独一个语句的缓存* @param string $sql 执行的SQL语句*/function delone($sql){$key=md5($sql);$this->mc->delete($key, 0); //0 表示立刻删除}}>希望本文所述对大家的PHP程序设计有所帮助。

Linux通过源代码安装Memcached

Linux通过源代码安装Memcached

Linux通过源代码安装Memcached目录1. 查询系统是否安装Memcached的依赖库libevent (1)2. 下载软件 (1)3. 安装 (1)3.1 安装libevent(memcached依赖libevent) (1)3.2 安装memcached (2)3.3 启动Memcache的服务器 (2)3.4 测试Memcached (4)4. 设置开机自启动 (5)4.1 建立启动脚本 (5)4.2 给脚本设置权限 (7)4.4 建立为系统服务 (8)1.查询系统是否安装Memcached的依赖库libevent#rpm –qa | grep libevent#rpm -e libevent-1.4.13-4.el6.x86_64 --nodeps(由于系统自带的版本旧,忽略依赖强制删除)2.下载软件memcached最新版下载地址/files/memcached-1.4.24.tar.gz libevent(memcached依赖libvent)最新稳定版下载地址:/project/levent/libevent/libevent-2.0/libevent-2.0.22-stable.tar.gz 并将它们上传到服务器/home目录3. 安装3.1 安装libevent(memcached依赖libevent)打开终端,切换到root用户,先安装libevent(memcached依赖libevent)#cd /home#tar -zxvf libevent-2.0.22-stable.tar.gz#cd /home/libevent-2.0.22-stable#./configure --prefix=/usr/local/libevent (指定安装到/usr/local/libevnt目录里)#make#make install检查libevent是否安装成功#ls -al /usr/local/libevent/lib | grep libevent3.2 安装memcached需要指定libevent的安装位置,不指定libevent的安装位置会引起memcached启动时找不到相关libevent-2.0.so.5文件地址#cd /home#tar -xvf memcached-1.4.24.tar.gz#cd /home/memcached-1.4.24#./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent/makemake install测试是否成功安装memcached:#ls -al /usr/local/memcached/bin/mem*3.3 启动Memcache的服务器/usr/local/memcached/bin/memcached -d -m 4096 -u root –c 1024 -p 11211 -P /var/run/memcached.pid参数说明:-p 监听的TCP端口(默认: 11211) , 最好是1024以上的端口-U 监听的UDP端口(默认: 11211, 0表示不监听)-s 用于监听的UNIX套接字路径(禁用网络支持)-a UNIX套接字访问掩码,八进制数字(默认:0700)-l 监听的IP地址。

memcached refcount 个人见解

memcached refcount 个人见解

在多线程环境中,前面memcached item锁粒度中可以看出在thread.c中那些item_get,item_link等,对item的一些基本操作都会根据锁的类型(分段锁或者是全局锁),严格的保证在多线程环境中的原子性,但是memcached中通过libevent得到的客户端请求,然后处理命令,函数是process_command,可以看到这个函数是不加锁的,也就是说通过原子操作调用了item_get操作后得到了item,对item后会对他进行一系列操作都是不加锁的,这样如果两个线程在先后都得到了同一个item,一个是删除item,一个是读取item,删除的item的操作在时间点上先到达,那么直接释放item的空间给slab会产生问题。

个人认为通过item的refcount变量控制item,refcount主要是保证在多线程环境中item的内存空间,不被其他操作同一item的线程释放空间,我认为这个变量的值含义是:表示有多个线程的多少个地方引用着这块item空间,可想而知,在函数中取得了item,表示了有一个线程的函数引用了这块item内存区域。

在函数退出后,lru和hash表中会同时引用这块空间,例如有3个线程同时引用这个item,1个从lru中取得这个item,另外两个从hash结构中取出item,那么这个refcount应该是3.在函数调用后应该是释放占用的这个refcount引用,通过调用item_remove函数,使得refcount减1.通过前面描述我们可以知道,正常情况下如果一个item被插入到了hash,lru中后,函数退出后,refcount=1,表示hash结构和lru队列依然对这块item内存区域保持引用,使得其他线程不能释放这块item内存。

对item的refcount操作是原子操作,代码:thread.c1. 85 unsigned short refcount_incr(unsigned short *refcount){2. 86 #ifdef HAVE_GCC_ATOMICS //GCC内建原子操作3. 87 return __sync_add_and_fetch(refcount, 1);4. 88 #elif defined(__sun)5. 89 return atomic_inc_ushort_nv(refcount);6. 90 #else7. 91 unsigned short res;8. 92 mutex_lock(&atomics_mutex);//通过信号量实现原子性9. 93 (*refcount)++;//refcount加110. 94 res =*refcount;11. 95 mutex_unlock(&atomics_mutex);12. 96 return res;13. 97 #endif14. 98 }这样在多线程环境下,refcount_incr和refcount_decr都是原子性操作。

memcached代码分析详解

memcached代码分析详解

memcached分析详解目录1.文档目的 (1)1.1.前言 (1)2.memcached是什么 (2)2.1. memcached的特征 (2)3.memcached适合的场合 (4)4.memcached的代码分析 (5)4.1. main流程 (5)4.2. memcached服务流程(TCP) (6)4.3. memcached状态转换和通信协议处理 (7)4.4. memcached核心数据结构 (7)4.5. Slab Allocation机制:整理内存以便重复使用 (8)5.memcached的使用优化 (10)5.1. 命中率 (10)5.2. 空间利用率 (11)5.3. 加速比 (12)5.4. 安全性能 (12)6.memcached的测试分析 (13)6.1. 读写memcache指令测试 (13)6.2. 服务端系统负载 (13)6.3. 空间分配,命中率 (14)7.memcached的中间层客户端编写 (16)8.libevent简介 (17)9.memcached应用 (18)10.结束语 (20)1. 文档目的1.1. 前言文档就是简单的把memcached做一个代码走读和分析,起到一个抛砖引玉的作用;目的就是让大家在使用memcached这个工具时,多一些对工具的了解,从而确定你的程序是否真的需要用memcached来实现不可;短短2个小时也讲不了多少,主要是做一个学习探讨,如果大家感兴趣的话后期可以再做培训牛人真多啊,向先行者致敬!2. memcached是什么memcached广泛应用在大负载高并发的网站上,是一种非常成熟的产品(称为一项技术也未尝不可)。

像facebook,youtube,yahoo,sina,sohu,netease,豆瓣等网站均或多或少使用了该项产品。

memcached在以用户为中心的网站上,表现尤其突出,例如sns,blog等web2.0应用的站点。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Part2
Part2
Memcached的线程关系
typedef struct { pthread_t thread_id; struct event_base *base; struct event notify_event; int notify_receive_fd; int notify_send_fd; CQ new_conn_queue; } LIBEVENT_THREAD; void thread_init(int nthreads, struct event_base *main_base) { threads[i].notify_receive_fd = fds[0]; threads[i].notify_send_fd = fds[1]; setup_thread(&threads[i]); for (i = 1; i < nthreads; i++) { create_worker(worker_libevent, &threads[i]); } } static void setup_thread(LIBEVENT_THREAD *me) { if (! me->base) me->base = event_init(); event_set(&me->notify_event, me->notify_receive_fd, EV_READ | EV_PERSIST, thread_libevent_process, me); event_base_set(me->base, &me->notify_event); if (event_add(&me->notify_event, 0) == -1) { fprintf(stderr, "Can't monitor libevent notify pipe\n"); exit(1); } cq_init(&me->new_conn_queue); }
使用memcached的公司
Part2
预备知识
libevent简介 线程池模型简介
Part2
libevent是一个开源的、跨平台的事件处理函数库。 它封装了网络、信号以及定时器的事件,以及附带了一些缓冲区管理功能,非常适合用 来处理server的底层IO。对于网络事件,他封装了epoll, select, kqueue(BSD)等模 型,性能非常好。 下面是使用libevent的一个简单例子:
static int server_socket(const int port, const bool is_udp) { socket(); bind() listen(); conn_new(sfd, conn_listening, EV_READ | EV_PERSIST, 1, false, main_base); } conn *conn_new(const int sfd, const int init_state, const int event_flags, const int read_buffer_size, const bool is_udp, struct event_base *base) { conn *c = conn_from_freelist(); event_set(&c->event, sfd, event_flags, event_handler, (void *)c); event_base_set(base, &c->event); c->ev_flags = event_flags; event_add(&c->event, 0) ; } //主线程和worker线程的公有事件处理回调函数 void event_handler(const int fd, const short which, void *arg) { conn *c; c = (conn *)arg; assert(c != NULL); c->which = which; drive_machine(c); //处理具体的事件 return; }
Libevent由于所有的事件都是由一个event_base对象来管理,是一个全局对象因此不支 持多线程。Memcached给每个线程创建了一个event_base对象,每个线程自己管理 自己的网络IO
Part2
static void delete_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 5, .tv_usec = 0}; static bool initialized = false; if (initialized) { evtimer_del(&deleteevent); } else { initialized = true; } evtimer_set(&deleteevent, delete_handler, 0); event_base_set(main_base, &deleteevent); evtimer_add(&deleteevent, &t); run_deferred_deletes(); } void do_run_deferred_deletes(void) { for (i = 0; i < delcurr; i++) { item *it = todelete[i]; if (item_delete_lock_over(it)) { it->it_flags &= ~ITEM_DELETED; do_item_unlink(it); do_item_remove(it); } else { todelete[j++] = it; } } delcurr = j; }
static void thread_libevent_process(int fd, short which, void *arg) { read(fd, buf, 1); item = cq_peek(&me->new_conn_queue); conn_new(item->sfd, item->init_state, item->event_flags, item->read_buffer_size/*2048*/, item->is_udp, me->base); }
Memcached源代码分析
looloochen 2009-7-20
P在用memcached Memcached的适用场合
Part 1
简介
memcached是高性能的,分布式的内存对象缓存系统,常常用于在应用 中减少数据库负载,提升访问速度。 memcached由Danga Interactive公司开发,是一个开源软件。 memcached一般作为数据库的前端cache使用,用于减少磁盘的访问, 它的数据都以key-value的形式存储,访问数据很简单,不像db解析 SQL,一条简单的命令即可存取数据。 可以使用unix域套接字,tcp以及udp协议访问memcached,因此使用 memcached是有代价的,如果想要缓存的数据不需要被共享,那么本 地缓存可能更适用一些。
static void drive_machine(conn *c) { while (!stop) { switch(c->state) { case conn_listening: //只有主线程才会有的事件 sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen); dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, false); break; case conn_read: if (try_read_command(c) != 0) { continue; } if (try_read_network(c)) != 0) { continue; } update_event(c, EV_READ | EV_PERSIST); break; case conn_nread: complete_nread(c); break; res = read(c->sfd, c->ritem, c->rlbytes); if (res > 0) { c->ritem += res; c->rlbytes -= res; break; } if (res == 0) { /* end of stream */ conn_set_state(c, conn_closing); break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { conn_set_state(c, conn_closing); break; } stop = true; break; } //其它错误,关闭socket conn_set_state(c, conn_closing); break; case conn_swallow: ... case conn_write: ... case conn_mwrite: ... ... case conn_closing: if (c->udp) conn_cleanup(c); else conn_close(c); stop = true; break; } } return; }
struct event_base *base = event_init(); event_set(&event, fd, EV_READ, callback_fun, arg); event_base_set(base, &event); event_add(&, 0); event_base_loop(base, 0); 它的功能相当于: While(1) { FD_SET(fd, rd_set); select(max_fd + 1, rd_set, NULL, NULL, tv); for(int i = 0; i < max_fd; ++i) if(FD_ISSET(i, rd_set)) callback_fun(fd, arg); }
相关文档
最新文档