• 1. Memcache培训 李岩 2011年5月8日
  • 2. Memcache概念memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性
  • 3. Memcache概念Web servers如apache 应用程序如tomcat
  • 4. Memcache读取写入读取 读取操作的顺序是从 Web 层获取请求(需要执行一次数据库查询)并检查之前在缓存中存储的查询结果。如果我找到所需的值,则返回它。如果未找到,则执行查询并将结果存储在缓存中,然后再将结果返回给 Web 层。 写入 将数据写入到数据库中时,首先需要执行数据库写入操作,然后将之前缓存的任何受此写入操作影响的结果设定为无效。此过程有助于防止缓存和数据库之间出现数据不一致性。
  • 5. 启动memcachedmemcached -p 11211 -m 1024m –vv 前台启动memcached,监听TCP端口11211最大内存使用量为1024M memcached -p 11211 -m 1024m –d 后台启动memcached,其他同上 许多语言都实现了连接memcached的客户端 以Perl的memcached客户端Cache::Memcached为例
  • 6. Cache::Memcached连接服务端my $key = "foo"; my $value = "bar"; my $expires = 3600; # 1 hour my $memcached = Cache::Memcached>new({ servers => ["127.0.0.1:11211"], compress_threshold => 10_000 }); $memcached>add($key, $value, $expires); my $ret = $memcached>get($key); print "$ret\n"; servers 指定memcached服务器和端口 compress_threshold 数据压缩时使用的值
  • 7. Memcached操作数据my $add = $memcached>add( '键', '值', '期限' ); my $replace = $memcached>replace( '键', '值', '期限' ); my $set = $memcached>set( '键', '值', '期限' ); add仅当存储空间中不存在键相同的数据时才保存 replace 仅当存储空间中存在键相同的数据时才保存 set 与add和replace不同,无论何时都保存 my $val = $memcached>get('键'); my $val = $memcached>get_multi('键1', '键2', '键3', '键4', '键5'); $memcached>delete('键', '阻塞时间(秒)');
  • 8. memcached的内存存储Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成各种尺寸的块(chunk),并把尺寸相同的块分成组(chunk的集合)
  • 9. Slab Allocation的主要术语Page 分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。 Chunk 用于缓存记录的内存空间。 Slab Class 特定大小的chunk的组。
  • 10. 在Slab中缓存记录的原理memcached根据收到的数据的大小,选择最适合数据大小的slab, memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。清memcache缓存
  • 11. Slab Allocator的缺点由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了
  • 12. 使用Growth Factor进行调优memcached在启动时指定Growth Factor因子(通过f选项),就可以在某种程度上控制slab之间的差异。默认值为1.25。 memcached -f 2 –vv,下面是启动后的verbose输出: slab class 1: chunk size 128 perslab 8192 slab class 2: chunk size 256 perslab 4096 slab class 3: chunk size 512 perslab 2048 slab class 4: chunk size 1024 perslab 1024 slab class 5: chunk size 2048 perslab 512 slab class 6: chunk size 4096 perslab 256 slab class 7: chunk size 8192 perslab 128 slab class 8: chunk size 16384 perslab 64 slab class 9: chunk size 32768 perslab 32 slab class 10: chunk size 65536 perslab 16 slab class 11: chunk size 131072 perslab 8 slab class 12: chunk size 262144 perslab 4 slab class 13: chunk size 524288 perslab 2
  • 13. 使用Growth Factor进行调优来看看现在的默认设置(f=1.25)时的输出: slab class 1: chunk size 88 perslab 11915 slab class 2: chunk size 112 perslab 9362 slab class 3: chunk size 144 perslab 7281 slab class 4: chunk size 184 perslab 5698 slab class 5: chunk size 232 perslab 4519 slab class 6: chunk size 296 perslab 3542 slab class 7: chunk size 376 perslab 2788 slab class 8: chunk size 472 perslab 2221 slab class 9: chunk size 592 perslab 1771 slab class 10: chunk size 744 perslab 1409 可见,组间差距比因子为2时小得多,更适合缓存几百字节的记录,将memcached引入产品,或是直接使用默认值进行部署时,最好是重新计算一下数据的预期平均长 度,调整growth factor,以获得最恰当的设置。
  • 14. 查看memcached的内部状态telnet 主机名 端口号 #telnet 127.0.0.1 11211连接本机memcached stats #查看memcached状态 stats slabs #查看缓存记录信息 quit #退出telnet
  • 15. memcached的内部状态pid memcache服务器的进程ID uptime 服务器已经运行的秒数 time 服务器当前的unix时间戳 version memcache版本 rusage_user 进程的累计用户时间 rusage_system 进程的累计系统时间 curr_items 服务器当前存储的items数量 total_items 从服务器启动以后存储的items总数量 bytes 当前服务器存储items占用的字节数 curr_connections 当前打开着的连接数 total_connections 从服务器启动以后曾经打开过的连接数 connection_structures 服务器分配的连接构造数
  • 16. memcached的内部状态cmd_get get命令(获取)总请求次数 cmd_set set命令(保存)总请求次数 get_hits 总命中次数 get_misses 总未命中次数 evictions 为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items) bytes_read 总读取字节数(请求字节数) bytes_written 总发送字节数(结果字节数) limit_maxbytes 分配给memcache的内存大小(字节) threads 当前线程数
  • 17. memcached的缓存性能结合这些值,我们可以确定缓存的利用率如何 get_hits找到名称/值对的次数 get_misses未找到名称/值对的次数 初次启动缓存时,可以看到 get_misses 会自然地增加,但在经过一定的使用量之后,这些 get_misses 值应该会逐渐趋于平稳 — 这表示缓存主要用于常见的读取操作。如果您看到 get_misses 继续快速增加,而 get_hits 逐渐趋于平稳,则需要确定一下所缓存的内容是什么。您可能缓存了错误的内容 确定缓存效率的另一种方法是查看缓存的命中率(hit ratio)。缓存命中率表示执行 get 的次数与错过 get 的次数的百分比。要确定这个百分比,需要再次运行 stats 命令,用 get_hits 的数值除以 cmd_gets,比率越高越好。查看统计数据并不时测量它们可以很好地判定缓存策略的效率
  • 18. Memcached基本命令 基本 memcached 命令执行最简单的操作。这些命令和操作包括: set add replace get delete 前三个命令是用于操作存储在 memcached 中的键值对的标准修改命令。它们都非常简单易用,且都使用语法 command
  • 19. Memcached基本命令 最后两个基本命令是 get 和 delete 。这些命令相当容易理解,并且使用了类似的语法: command 参数 用法 key key 用于查找缓存值 flags 可以包括键值对的整型参数,客户机使 用它存储关于键值对的额外信息 expiration time 在缓存中保存键值对的时间长度(以秒 为单位,0 表示永远) bytes 在缓存中存储的字节点 value 存储的值(始终位于第二行)
  • 20. set命令举例 set 命令用于向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。 set userId 0 0 5 12345 STORED 如果使用 set 命令正确设定了键值对,服务器将使用单词 STORED 进行响应。本示例向缓存中添加了一个键值对,其键为 userId ,其值为 12345 。并将过期时间设置为 0,这将向 memcached 通知您希望将此值存储在缓存中直到删除它为止。
  • 21. add命令举例 add 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。如果缓存中已经存在键,则之前的值将仍然保持相同,并且您将获得响应 NOT_STORED 。 set userId 0 0 5 12345 STORED add userId 0 0 5 55555 NOT_STORED
  • 22. 高级命令举例gets gets 命令的功能类似于基本的 get 命令。两个命令之间的差异在于,gets 返回的信息稍微多一些:64 位的整型值非常像名称/值对的 “版本” 标识符。 set userId 0 0 5 12345 STORED get userId VALUE userId 0 5 12345 END gets userId VALUE userId 0 5 4 12345 END
  • 23. 高级命令举例gets gets 命令将返回一个额外的值 — 在本例中是整型值 4,用于标识名称/值对。如果对此名称/值对执行另一个 set 命令,则 gets 返回的额外值将会发生更改,以表明名称/值对已经被更新。 set userId 0 0 5 33333 STORED gets userId VALUE userId 0 5 5 33333 END
  • 24. 高级命令举例cas cas (check 和 set)是一个非常便捷的 memcached 命令,用于设置名称/值对的值(如果该名称/值对在您上次执行 gets 后没有更新过)。它使用与 set 命令相类似的语法,但包括一个额外的值:gets 返回的额外值。 set userId 0 0 5 55555 STORED gets userId VALUE userId 0 5 6 55555 END cas userId 0 0 5 6 33333 STORED 如您所见,我使用额外的整型值 6 来调用 gets 命令,并且操作运行非常顺序
  • 25. 高级命令举例cas set userId 0 0 5 55555 STORED gets userId VALUE userId 0 5 8 55555 END cas userId 0 0 5 6 33333 EXISTS 注意,我并未使用 gets 最近返回的整型值,并且 cas 命令返回 EXISTS 值以示失败。从本质上说,同时使用 gets 和 cas 命令可以防止您使用自上次读取后经过更新的名称/值对
  • 26. Memcache清除缓存telnet ip port flush_all 或 echo "flush_all" |nc IP port #清memcache缓存
  • 27. Memcache删除机制memcached不会释放已分配的内存。记录超时后,客户端就无法再看见该记录,其存储空间即可重复使用。 memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。 Least Recently Used(LRU) 最近最少使用 当memcached的内存空间不足时,就从最近未被使用的记录中搜索,并将其空间分配给新的记录
  • 28. memcached的分布式下面假设memcached服务器有node1~node3三台,应用程序要保存键名为“tokyo”、“kanagawa”、“chiba”、“saitama”、“gunma”的数据。
  • 29. memcached的分布式首先向memcached中添加“tokyo”。将“tokyo”传给客户端程序库后,客户端实现的算法就会根据“键”来决定保存数据的memcached服务器。服务器选定后,即命令它保存“tokyo”及其值。
  • 30. memcached的分布式同样,“kanagawa”、“chiba”、“saitama”、“gunma”都是先选择服务器再保存。 接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。函数库通过与数据保存时相同的算法,根据“键”选择服务器。使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。只要数据没有因为某些原因被删除,就能获得保存的值。
  • 31. memcached的分布式
  • 32. Cache::Memcached的分布式算法Cache::Memcached的分布式方法简单来说,就是“根据服务器台数的余数进行分散”。求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。 my @nodes = ('node1','node2','node3'); my @keys = ('tokyo', 'kanagawa', 'chiba', 'saitama', 'gunma'); foreach my $key (@keys) {my $crc = crc32($key); # CRC値 my $mod = $crc % ( $#nodes + 1 ); my $server = $nodes[ $mod ]; # 根据余数选择服务器 printf "%s => %s\n", $key, $server; 首先求得字符串的CRC值,根据该值除以服务器节点数目得到的余数决定服务器