第4章 Memcached 服务器维护与监控指南
Server Guide维护维护监控服务器健康状况
Memcached 提供大量统计计数器。大多数只是累计值,但有些可以用作提醒管理员的警告信号。网上有很多工具和类 top 程序可以帮你消化这些信息。
发起命令
监控脚本最好偶尔向服务器发起 test set/get/delete 操作,并记录每次响应耗时。如果连接慢,可能是连接数或网络出了问题;如果响应慢,服务器可能在 swap 或者状态不佳。你本该严格监控服务器健康,但多加一层监控也是值得的。
重要统计项
以下统计项可以通过向 memcached 服务器发送简单的 stats 命令获取。
curr_connections
列出当前连接的客户端数量。注意别让这个数字太接近最大连接数设置(-c)。
listen_disabled_num
名字有点晦涩,统计的是 memcached 达到连接上限的次数。达到最大连接数后,memcached 会禁用监听器,新连接进入队列等待;一旦有连接断开,监听器被唤醒,重新开始接受连接。
这个计数器每增加一次,就说明新连接开始出现延迟。务必让它保持在零或接近零。
accepting_conns
与上面的 listen_disabled_num 相关。如果你已经连上了 memcached,可以通过检查这个值是 1 还是 0,判断它是否达到了最大连接数。
limit_maxbytes
有时最好确认一下你以为的启动配置和实际启动配置是否一致。检查 limit_maxbytes 可以验证 -m 参数是否生效。使用 init 脚本的人偶尔会配置错误,导致 memcached 以默认值启动。
cmd_flush
虽然不完全算服务器健康指标,但值得常规监控。每次有人执行 flush_all 命令,缓存中的所有条目都会失效,这个计数器也会加一。有时调试代码或一知半解的人会把脚本或回调留在后台运行,不断“清空”整个缓存。在生产环境盯着这个值,一旦开始变动就报警——除非你确实是有意为之。
stats sizes
如果 memcached 以 -o track_sizes 启动,内部会做一些额外统计,更细致地展示存储数据的大小分布。
运行 stats sizes 可以看出你的条目与 slab class 的匹配程度。
警告:如果你的 memcached 版本较老(1.4.27 之前),这个命令在扫描所有条目时可能导致缓存卡死。可能非常危险!
Slab 不均衡
一个更复杂的问题是:各 slab 分配到的内存量与实际数据想去的 slab 之间不匹配。算法其实很简单,只是描述起来绕:
监控全局的 'evictions' 统计项。如果开始上涨(也可以直接跳到第 2 步)。
监控 stats items 中的 evicted 和 evicted_nonzero 统计项。evicted_nonzero 表示对象被提前逐出,且没有设置无限过期时间。这些信息是按 slab 统计的。
从 stats slabs 读取 total_pages 统计项,与上面的 evicted 数据对照。
如果逐出最多的 slab 恰好也是页数最多的 slab,那你可能真的内存不足了。
或者(也许更重要),把每个 slab 的命中率与页数做关联分析。
如果逐出最多的 slab 和页数分布对不上,你需要重启 memcached,让它重新分配内存。
较新版本的 memcached(1.4.25 及以后)内置了调优良好的自动化机制来修复这个问题,无需重启。详情参见发布说明和 https://github.com/memcached/memcached/blob/master/doc/protocol.txt。
应用健康统计
监控这些统计项可以让你了解 memcached 的可用内存如何变化、应用行为如何影响效率。
全局命中率
命中率定义为:get_hits / (get_hits + get_misses)。这个值越高,说明应用越常命中缓存结果,而不是扑空。注意这个值是否高于你的预期,并观察它随时间或应用发版的变化。
按 slab 的命中率
虽然无法精确计算每个 slab 的命中率——“get miss”并不知道丢失的条目可能有多大——但可以通过 stats slabs 按 slab 监控 get_hits 和 cmd_set 的数量。注意 get_hits 通常应高于 cmd_set(读多于写往往才是你想要的状态),并留意随时间的变化。
逐出(Evictions)
如果一个条目还有存活时间,但在分配新条目时恰好位于 LRU 链表尾部,它就会被从缓存中“逐出”。memcached 会尝试从尾部找找有没有已过期的条目,但并不保证找到。
stats items 显示每个 slab 的逐出情况。'evicted' 是该 slab 被提前逐出的条目总数,'evicted_nonzero' 是其中没有无限过期时间的条目数,'evicted - evicted_nonzero' 则是被永久存储却被逐出的条目数。
'evicted_time' 记录了最后一个被逐出的条目距离上次被访问过了多少秒。如果这个数字很小,说明你正在逐出最近刚用过的条目。
表象可能骗人
你看到命中率低、逐出率高,就以为该给 memcached 加内存了。可惜这不一定对。考虑以下几种可能:
你的应用写入了大量 key,其中大部分之后再也不会被用到。
你的应用在多数请求中查询一个或多个不存在的 key,也不会重新缓存——比如某个标志位,或者来自某个有 bug 的用户的值。
前者会导致很高的逐出次数,即使这些数据本来就不重要。审计一下应用存储了什么,看看是否存在这个问题。
后者会拉低命中率,因为大量的 get_misses 都来自这个标志。解决办法是让应用“重新缓存”一个值为“not set”的标志。这样即使标志被禁用,它仍留在缓存中,也不会干扰命中率统计。
操作系统健康(避免 swap!)
Memcached 与网络和内存交互非常密切。swap 的使用会严重拖慢 memcached,因此监控 swap 用量很常见。
同样重要的是网络栈。以 Linux 为例,网络接口有大量与丢包、下溢、CRC 错误等相关的计数器。大多数交换机也有针对每个端口的丢包或链路问题计数器。性能下降的根源可能是线路老化、交换机端口故障、网卡濒临损坏,或网络驱动需要调优。
升级
Memcached 的大多数次要版本更新专注于修 bug 和增加监控指标。新功能很少见,现在一般只在中等版本号变更时才有——比如 1.2 到 1.4 加入了二进制协议和大量计数器;1.4.0 到 1.4.1 则主要是修 bug 和补齐计数器。
小的功能也会出现。SASL 认证支持就是在 1.4 系列中期加入的,但改动是隔离的,不会破坏现有客户端。
你应该跟进新版本和发布说明。通常尽早升级更好,这样在需要时就有额外的监控指标可用,而不是出了问题才后悔没升级。
配置性能与效率