【SQL开源代码栏目提醒】:网学会员--在 SQL开源代码编辑为广大网友搜集整理了:memcached代码分析详解 - 计算机教材绩等信息,祝愿广大网友取得需要的信息,参考学习。
memcached分析详解 修订日期 修订内容 版本 修订人 2009-3-13 初始化 江军 目 录 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 / 9 1.
文档目的 1.1. 前言
文档就是简单的把memcached做一个
代码走读和分析起到一个抛砖引玉的作用 目的就是让大家在使用memcached这个工具时多一些对工具的了解从而确定你的程序是否真的需要用memcached来实现不可 短短2个小时也讲不了多少主要是做一个
学习探讨如果大家感兴趣的话后期可以再做培训 牛人真多啊向先行者致敬 2 / 9 2. memcached是什么 memcached广泛应用在大负载高并发的网站上是一种非常成熟的产品称为一项技术也未尝不可。
像 facebookyoutubeyahoosinasohunetease豆瓣等网站均或多或少使用了该项产品。
memcached在以用户为中心的网站上表现尤其突出例如snsblog等
web2.0应用的站点。
这些站点一般来讲特别注重用户体验用户对服务器的响应速度要求很高 用户数据相对比较复杂、关连度比较高需要经常对数据库进行更新和检索。
许多Web应用都将数据保存到RDBMS中应用服务器从中读取数据并在浏览器中显示。
但随着数据量的增大、访问的集中就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。
这时就该memcached大显身手了。
memcached是高性能的分布式内存缓存服务器。
一般使用目的是通过缓存数据库
查询结果减少数据库访问次数以提高动态Web应用的速度、 提高可扩展性。
2.1. memcached的特征 1memcached的服务器客户端通信并不使用复杂的XML等格式 而使用简单的基于文本行的协议。
因此通过telnet 也能在memcached上保存数据、取得数据。
下面是例子。
telnet localhost 8119 Trying 127.0.0.1... Connected to localhost.localdomain 127.0.0.1. Escape character is . set foo 0 0 3 保存命令 bar 数据 3 / 9 STORED 结果 get foo 取得命令 VALUE foo 0 3 数据 bar 数据 协议可以参考 2为了提高性能memcached中保存的数据都存储在memcached内置的内存存储空间中。
由于数据仅存在于内存中因此重启memcached、重启操作系统会导致全部数据消失。
另外内容容量达到指定值之后就基于LRULeast Recently Used算法自动删除不使用的缓存。
memcached本身是为缓存而设计的服务器因此并没有过多考虑数据的永久性问题。
3memcached尽管是“分布式”缓存服务器但服务器端并没有分布式功能。
各个memcached不会互相通信以共享信息。
那么怎样进行分布式呢 这完全取决于客户端的实现。
4 / 9 3. memcached适合的场合 memcached是“分布式”的内存对象缓存系统那么就是说那些不需要“分布”的不需要共享的或者干脆规模小到只有一台服务器的应 用memcached不会带来任何好处相反还会拖慢系统效率因为网络连接同样需要资源即使是UNIX/Windows本地连接也一样。
测试数据显示memcached本地读写速度要比直接.
NET内存数组慢几十倍而APC、共享内存方式都和直接数组差不多。
可见如果只是本地级缓 存使用memcached是非常不划算的。
Memcached在很多时候都是作为数据库前端cache使用的。
因为它比数据库少了很多
SQL解析、磁盘操作等开销而且它是使用内存来管理数据的 所以它可以提供比直接读取数据库更好的性能在大型系统中访问同样的数据是很频繁的memcached可以大大降低数据库压力使系统执行效率提升。
另外memcached也经常作为服务器之间数据共享的存储媒介例如在SSO系统中保存
系统单点
登陆状态的数据就可以保存在memcached中被 多个应用共享。
需要注意的是memcached使用内存管理数据所以它是易失的当服务器重启或者memcached进程中止数据便会丢失所以 memcached不能用来持久保存数据。
很多人的错误理解memcached的性能非常好好到了内存和硬盘的对比程度其实memcached使用 内存并不会得到成百上千的读写速度提高它的实际瓶颈在于网络连接它和使用磁盘的数据库系统相比好处在于它本身非常“轻”因为没有过多的开销和直接的读写方式它可以轻松应付非常大的数据交换量所以经常会出现两条千兆网络带宽都满负荷了memcached进程本身并不占用多少CPU资源的情况。
5 / 9 4. memcached的
代码分析 4.1. main流程 6 / 9 4.2. memcached服务流程TCP 7 / 9 4.3. memcached状态转换和
通信协议处理 需要说明的是这里需要排除所有出错处理.很显然不管是哪种操作下一旦出错信息需要通过conn_write状态往client写入出错信息的那么在string_out时必定转入conn_write状态. 而且很多细节也没有在流程图中给出如统计信息的处理超时后get操作时删除等等.对于在memcache协议中定义的其他操作如 statsversionquitflush_allowndisown等等由于使用很少在流程中没有详细给出可以查看源
代码. 4.4. memcached核心数据结构 1. item结构 item是存储在memcache的key-value对的抽象.由于组织item存放是按照LRU算法组织的.那么在其中有几个成员在修改源
代码时必须注意time是最近访问时间.exptime是item消亡时间.item是一个双向列表.同时还挂在一个Hash table上. 2. conn结构 conn结构是联系上下文的关键对象.对于每个连接的到来都有一个conn结构与其对应并且对应到某个连接状态进入状态转换而完成操作. conn在
程序开始也进行了一次预分配分配200个连接空间.当200个使用完之后便是按需分配到达一个分配一个. conn和itemiovec内核级别缓冲结构关联. 3. slabclass_t结构 8 / 9 slabclass_t保存了分级大小的空间槽以分别适用于不同大小的item存放.取决于两个命令行参数-f和-n.在应用 slabclass_t时定义的是一个数组该数组长度取决于增长的指数级别和初始值大小32chunk_size每个空间槽是不允许大于1M 的也就是1048576. 4. settings结构 系统获取的命令行参数保存的地方. 5. stats结构: 统计信息保存地方可以考虑对其进行操作以适应不同的统计信息处理如获取某个时间段的get命中率等等操作. 4.5. Slab Allocation机制整理内存以便重复使用 1memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。
在该机制出现以前内存的分配是通过对所有记录简单地进行malloc和free来进行的。
但是这种方式会导致内存碎片加重操作系统内存管理器的负担最坏的情况下 会导致操作系统比memcached进程本身还慢。
Slab Allocation的原理相当简单。
将分配的内存分割成各种尺寸的块chunk 并把尺寸相同的块分成组chunk的集合图1。
2memcached根据收到的数据的大小选择最适合数据大小的slab图2。
memcached中保存着slab内空闲chunk的列表根据该
列表选择chunk 然后将数据缓存于其中。
9 / 9 3Slab Allocator解决了当初的内存碎片问题但新的机制也给memcached带来了新的问题。
这个
问题就是由于分配的是特定长度的内存因此无法有效利用分配的内存。
例如将100字节的数据缓存到128字节的chunk中剩余的28字节就浪费了图3。
4memcached在启动时指定 Growth Factor因子通过-f选项 就可以在某种程度上控制slab之间的差异。
默认值为1.25。
但是在该选项出现之前这个因子曾经固定为2称为“powers of 2”策略。
将memcached引入产品或是直接使用默认值进行部署时 最好是重新计算一下数据的预期平均长度调整growth factor 以获得最恰当的设置。
内存是珍贵的资源浪费就太可惜了。
10 / 9 5. memcached的使用优化 在优化memcache的工作之前需要了解memcache体系的
工作流程.一个分布式的memcache的运作是需要三个部分的多台提供 memcache服务的servers简称S一个进行分布式映射的中间层lib其实这个也可以当作客户端的一部分简称L和进行 memcache请求的客户端简称C. 在memcache工作时有以下四个步骤: 1. C通过带有特性化的Key值的命令串向L请求memcache服务L将命令串进行分解并通过对key的某种Hash算法决定S的地址 2. L将分解的Comm Key-Value或者Comm Key向相关的S请求memcache服务. 3. 相关的S根据memcache协议向L返回服务结果. 4. L将结果进行聚集包装后返回给C一个人性化的响应. 从上面的分析可以看出分布式的memcache服务是需要很大的
网络开销的.对于一般的应用而言是否都要进行memcache的优化甚至是否需要 用到memcache都需要进行权衡分析.如果只是本地小规模的应用在数据库可承受的范围内是宁愿采用数据库文件缓存的方式.1.1版本的 memcache走TCP模式在本地应用的处理速度甚至比不上My
sql数据的Unix域套接口的处理速度的一半当然会更加比不上在程序内部直接操作内 存了.虽然1.2版本的memcache已经提供了-s参数指定Unix域套口和-u指定udp模式.而且如果不需要用到分布式的话不推荐使用 memcache除非你的内存足够大到浪费的程度. 优化可以从以下几个方面进行 5.1. 命中率 对于缓存服务而言命中率是至关重要的.命中率的提升可以通过多种
方案实现.其一提高服务获取的内存总 11 / 9 量.这无疑是增加命中的最直接的办法将缓存数 据完全放入数据池中.只要连接不失效就一定命中.其二提高空间利用率这实际上也是另一种方式的增加内存总量.具体实现在下一个方面给出.其三对于 一些很特别的memcache应用可以采用多个memcache服务进行侦听分开处理针对服务提供的频繁度划分服务内存相当于在应用一级别上再来 一次LRU.其四对于整体命中率可以采取有效的冗余策略减少分布式服务时某个server发生服务抖动的情况.如14台机器实现分布式 memcache划分两组服务其中一组13台做一个分布式的memcache一组1台做整个的memcache备份.对于update操作需要进 行两边get操作只需要一遍一旦访问失效则访问备份服务器.这样对于备份服务器需要内存比较大而且只适应于读操作大于写操作的应用中.这可以认 为是RAID3当然也可以采用RAID1完全镜像. 5.2. 空间利用率 对于使用memcache做定长数据缓存服务而言是可以在空间利用率上进行优化.甚至最简单的办法可以不用更改memcache的源码遍可以完成由 -f和-n参数的配合可以做到定长优化不过极可能需要浪费掉预分配的199M内存空间.当然前提是memcache的版本是1.2同时如果使用的是 1.2.0和1.2.1的话需要更改掉一个BUG那就是getopt时将opt串中最后一个”s”改成”n”希望memcache能在以后的版本发 现这个BUG.例如如果key是一个定长id如一个8位的流水号00000001value是一个定长的串如16位的任意字符串对应于一个 chunk_size可以这么计算:chunk_size sizeofitem nkey nsuffix nbytes 32 9 flag的数位长度 2 16的数位长度 2两换行的长度4 17 40 10 16 66那么可以通过 -f 1.000001 -n expr 66 - 32即 -f 1.000001 -n 34 来启动memcache.这种情况下会浪费掉memcache预先分配的200M空间中的199M.从第2个预分配等级到第200个预分配等级将不会用到.然而存在解决办法那就是在编译memcache是加入编译参数-DDONT_PREALLOC_SLABS或者在源
代码中加入define DONT_PREALLOC_SLABS即可只是会去除memcache的预分配内存机制. 如果需要memcache的预分配内存机制那么需要对其源
代码进行修改.修改如下: 引用 1. 在slabs.c中将函数slabs_clsid改成: unsigned int slabs_clsidsize_t size unsigned int res POWER_SMALLEST ifsize0 return 0 res sizepower_largest return res 2. 在item.c中将函数 item_make_header改为: int item_make_headerchar key uint8_t nkey int flags int nbytes char suffix int nsuffix nsuffix sprintfsuffix quot u urnquot flags nbytes - 2 return sizeofitem nkey nsuffix nbytes hashkeynkey0 3. 在item.c中将函数 item_free改为: void item_freeitem it unsigned int ntotal it-gtslabs_clsid 12 / 9 assertit-gtit_flags amp ITEM_LINKED 0 assertit headsit-gtslabs_clsid assertit tailsit-gtslabs_clsid assertit-gtrefcount 0 it-gtslabs_clsid 0 it-gtit_flags ITEM_SLABBED slabs_freeit ntotal 做一个轮流存储的机制使用预分配的内存这样的好处是其他地方不需要做任何修改就可以了当然你可以在源
代码中加入上面的
代码并将它们放在一个自定义的宏后面. 5.3. 加速比 加速比也即事件的处理效率.是否可以修改libevent的事件处理效率需要研究.如果内存空间很大可以将freeconn的数值调大增加预分配的conn内存大小. 5.4. 安全性能 memcache还存在一个比较显著的问题那就是其安全性能.只要了解memcache监听的端口对于能够使用分布式memcache进行数据通信 的网络环境的机器都可以通过memcache协议于memcache服务器进行通信获取或种植数据.不能保证种植进内存里的数据不会被别有用心的人再利用.也不能保证服务器的内存不被漫天遍地的垃圾数据所堆积造成命中极低. memcache的
设计理念在一个轻字如果对每次Client的通讯需要校验身份那么恐怕memcache也就达不到其想要的效果了.存在解决办法 缓解这个问题一般而言需要使用memcache服务的机器可以在Server维持一张红色列表.这张表上的机器便可以获取服务.很显 然memcache并非任意Client都能访问只有信任的机器访问那么为什么不将这些信任的机器放在一个/etc/mem_passwd下呢. 还有memcached走udp时很大几率接受到upd时都会使服务死掉特别是setaddreplace时这个问题需要去考究一下.不过没有时间了. 13 / 9 6. memcached的测试分析 服务器端memcache在命令行运行的参数: memcached –d –m 512 –l ... -u -f 1.00001 –n 16 –c 10000 –vv 6.1. 读写memcache指令测试 6.2. 服务端系统负载 通过自己编写的服务器端对单结点的memcache进行了连接压力测试.其中测试用例的编写是这样的:启用七个客户端每个客户端串行运行1000个 进程每个进程开3000线程每个线程执行10次memcache的读操作或者写操作操作相同.客户端并发连接. 1. 客户端7的环境:IntelR XeonR CPU 5120 1.86GHz4G memory. 2. 服务器端1的环境:IntelR XeonR CPU 5120 1.86GHz4G memory. 3. 网络环境:100M网卡Cisco交换机. 14 / 9 很显然memcache的运行在系统cpu的消耗上占十分少的比重即便是很恐怖的并发连接也不会给系统带来多大的负载因为其磁盘IO free所有操作都在内存中和相应的内存分配机制决定其占用cpu的极少而相反在网络IO上却花费很大的时间. 6.3. 空间分配命中率 由于本地测试的get数据非常固定因此命中率基本为100.在10.68.1.31上运行了一个有前端应用的memcachce服务器运行时间已经有364个多小时了. 因此通过10.68.1.31上的数据说明版本为1.1.13.通过memcache的统计协议可以清楚的看到其命中率高达95.9 15 / 9 16 / 9 7. memcached的中间层客户端编写 省略 17 / 9.