Memcached标准化
现状
自建
以查号服务为例:
类型 | 版本 | 数据量 | 规格 | 部署 | qps /节点 | 带宽流入 | 带宽流出 |
---|---|---|---|---|---|---|---|
自建 | 1.4.25 | 230gb | 8c64g * 4 | 4主机 x 4进程 | 3k | 120Mbps | 1000Mbps |
存在问题
- 大Key存在同一节点上,导致单节点带宽打满
- 单节点多进程维护
Memcached版本
1.6.9
发布时间
2020/11/21
https://github.com/memcached/memcached/wiki/ReleaseNotes160
https://github.com/memcached/memcached/wiki/ReleaseNotes169
特性
- 现在,其默认情况下会编译外部闪存系统。
- 新的元协议,该协议比现已弃用的二进制协议具有更多功能。
- 做了 Memcached 的网络代码,以允许自动批处理响应系统调用。
- 随着网络的变化,平均每个系统调用 1.5 个密钥可以将服务器 CPU 最多减少 25%,并将延迟至少减少几个百分点。
- 默认情况下,Memcached 1.6 还带有“Extstore”作为新的外部存储垫片。Extstore 将哈希表和键保留在内存中,同时将值移至基于外部闪存的存储中。
1.5.22
发布时间
2020/2/1
https://github.com/memcached/memcached/wiki/ReleaseNotes150
https://github.com/memcached/memcached/wiki/ReleaseNotes1522
特性
-
更好的LRU算法(分段 LRU(Segmented LRU)算法)
-
使用 murmur3 算法更快地查找哈希表
-
Slab自动重新平衡。避免slab随着对象大小随时间变化而导致停滞。
-
当达到连接限制时立即关闭连接,而不是挂起直到再次开启
-
服务重启恢复内存缓存,通过DAX文件系统挂载实现缓存持久性功能。可以通过在启动选项使用该功能:
-e /tmpfs_mount/memory_file
/tmpfs_mount/必须是某种类型的ram磁盘,大到足以满足启动时使用-m指定的内存限制。
-
实现优雅地重启:向守护进程发送SIGUSR1信号,并等待它关闭并退出。在关闭时创建/tmpfs_mount/memory_file.meta文件。重新启动时,它将读取此文件并确保兼容。如果文件不兼容或文件已损坏,则会以全新缓存启动。
1.4.39
发布时间
2017/7/5
1.4.25
发布时间
2015/11/20
硬件要求
CPU
memcached通常很少占用CPU,因为它的目标是快速响应。memcached是多线程的,默认为4个工作线程。通常CPU是足够大,大多数按照只需要一个memcached线程
内存
- memcached主要是利用多个主机组成一个分布式内存系统,通常内存越多越好。
- 通常让每个memcached服务器具有大致相同的可用内存,是为了保证集群一致性。集群一致性意味新增和删除服务器简单,而不必关心服务器权重
- 没必要使用高性能RAM(闪存)
避免swap
-
分配物理内存时,需要多加几个百分点,避免出现swap。swap会导致性能非常差
-
需要监控服务器是否正在使用swap
ExtStore
如何使用
构建具有:./configure && make && make test && sudo make install
(使用./configure --enable-extstore
,如果你的版本比1.6.0更早)
使用您的正常启动选项(-m -c 等),并添加:
-o ext_path=/path/to/a/datafile:5G
这将使用多达 5 GB 的存储空间初始化 extstore。存储在内部分成页面。默认情况下,页面的大小为 64 兆字节。
如何调整
除非你的服务器很忙,否则不应该做任何进一步的调整。尝试监视输出stats
以及写入磁盘的数量。
如果你往memcached写太多,你可能会往flash写太多,会烧坏驱动或造成大量延迟!
存储介质
寻址速度 | IO带宽 | |
---|---|---|
内存 | 5-10纳秒 | 10-50GB/s |
SSD | 0.1毫秒 | 130MB/s |
部署建议
使用专用主机
为 memcached 使用专用硬件意味着您不必担心机器上的其他程序会干扰 memcached。您可以将大量内存 (64G+) 放入单个主机中,并拥有更少的机器以满足您的内存需求。但是不建议将 memcached 集群压缩得越多,当主机死机时,您就越痛苦。
假设您的缓存命中率为 90%。如果您有 10 台 memcached 服务器,其中 1 台死机,您的命中率可能会下降到 82% 左右。如果 10% 的缓存未命中通过,那么跃升至 18% 或 20% 意味着您的后端突然处理的请求数量是以前的两倍。实际影响会有所不同,因为数据库在处理重复查询方面仍然很不错,并且典型的缓存未命中通常是数据库无论如何都必须查找的项目。还是两次!
假设你买了一堆内存为 144G 的服务器,但你只能买得起其中的 4 个。现在,当您丢失一台服务器时,25% 的缓存会消失,并且您的命中率可能会更大。
容量规划
需要了解在memcached集群多少个节点出现故障时,会导致应用程序出现故障
网络
Most deployments will have low requirements (< 10mbps per instance),
memcached配置
连接数
maxconns
tcp_backlog
通过发行stats命令并观察“listen_disabled_num”。这个值应该是零或接近于零
thread数
默认4线程
检查运行配置
$ echo "stats settings" | nc localhost 11211
STAT maxbytes 67108864
STAT maxconns 1024
STAT tcpport 11211
STAT udpport 11211
STAT inter NULL
STAT verbosity 0
STAT oldest 0
STAT evictions on
STAT domain_socket NULL
STAT umask 700
STAT growth_factor 1.25
STAT chunk_size 48
STAT num_threads 4
STAT stat_key_prefix :
STAT detail_enabled no
STAT reqs_per_event 20
STAT cas_enabled yes
STAT tcp_backlog 1024
STAT binding_protocol auto-negotiate
STAT auth_enabled_sasl no
STAT item_size_max 1048576
END
部署方案
目标机型
4C16G / 50G SSD
安装
######### 安装memcached
#1. 安装基础组件
yum install libevent-devel
#2. 安装memcached
wget http://www.memcached.org/files/memcached-1.6.9.tar.gz
tar -zxvf memcached-1.6.9.tar.gz
cd memcached-1.6.9
./configure --prefix=/usr/local/memcached --enable-extstore
make && make test && sudo make install
#3. copy脚本到/usr/local/bin
cp /usr/local/memcached/bin/memcached /usr/local/bin/
######### 安装监控
#4. 下载exporter
wget https://github.com/prometheus/memcached_exporter/releases/download/v0.9.0/memcached_exporter-0.9.0.linux-amd64.tar.gz
#5. copy脚本到/usr/local/bin
tar -zxvf memcached_exporter-0.9.0.linux-amd64.tar.gz
cp memcached_exporter /usr/local/bin/
######### 安装工具
#6. memcached-tool脚本可以方便地获得slab的使用情况 (它将memcached的返回值整理成容易阅读的格式)
wget http://www.netingcn.com/demo/memcached-tool.zip
unzip memcached-tool.zip
chmod 755 memcached-tool
cp memcached-tool /usr/local/bin/
启动
memcached启动脚本
#! /bin/bash
#
# memcached: MemCached Daemon
#
# chkconfig: - 90 25
# description: MemCached Daemon
#
### BEGIN INIT INFO
# Provides: memcached
# Required-Start: $syslog
# Required-Stop: $syslog
# Should-Start: $local_fs
# Should-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: memcached - Memory caching daemon
# Description: memcached - Memory caching daemon
### END INIT INFO
RETVAL=0
prog="memcached"
start () {
echo -n $"Starting $prog: "
# /usr/local/bin/memcached -d -p 11211 -u root -t 4 -m 14000 -f 1.12 -n 32 -c 65535 -b 65535 -P /var/run/memcached.pid -o ext_path=/data/extstore:32G ext_item_size=4096 -v >> /data/memcached.log 2>&1
/usr/local/bin/memcached -d -p 11211 -u root -t 4 -m 30000 -f 1.2 -c 65535 -b 65535 -P /var/run/memcached.pid -v >> /data/memcached.log 2>&1
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
else
touch /var/lock/subsys/memcached
echo " done"
fi
}
stop () {
echo -n $"Stopping $prog: "
if [ ! -e /var/run/$prog.pid ]; then
echo -n $"$prog is not running."
exit 1
fi
kill `cat /var/run/memcached.pid`
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
else
rm -f /var/lock/subsys/memcached
rm -f /var/run/memcached.pid
echo " done"
fi
}
restart () {
$0 stop
sleep 2
$0 start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
;;
esac
exit $?
memcached-exporter启动脚本
#!/bin/sh
# chkconfig: 2345 85 15
# description:auto_run
#开始方法
start() {
nohup /usr/local/bin/memcached_exporter > /data/memcached-exporter.log 2>&1 &
echo "memcached_exporter start success."
}
#结束方法
stop() {
pid=`ps -ef | grep memcached_exporter | grep -v grep | grep -v stop | awk '{print $2}'`
echo "kill process: $pid"
if [ "${pid}" != "" ];
then
kill -9 $pid
fi;
echo "memcached_exporter stop success."
}
restart () {
$0 stop
sleep 2
$0 start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo "Userage: $0 {start|stop|restart}"
exit 1
esac
exit $?
copy脚本到/etc/init.d/
# 配置服务
chkconfig -add /etc/init.d/memcached #添加memcached到服务项
chkconfig --level 2345 memcached on #设置开机启动
chkconfig -add /etc/init.d/memcached_exporter #添加memcached_exporter到服务项
chkconfig --level 2345 memcached_exporter on #设置开机启动
# 启动memcached
/etc/init.d/memcached start
# 启动监听
/etc/init.d/memcached_exporter start
调优
memcached内存调优
和内存优化相关的参数大致有三个,分别是
1、chunk大小的增长因子(Growth Factor),
2、chunk大小的初始值
3、slab page的大小
Growth Factor
Growth Factor的值决定了chunk的大小按怎样的倍数进行增长,memcached在启动时可以通过-f参数指定 Growth Factor值, 就可以在某种程度上控制slab之间的差异。默认值为1.25。
memcached -u root -f 3 -vv
输出示例:
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 288 perslab 3640
slab class 3: chunk size 864 perslab 1213
slab class 4: chunk size 2592 perslab 404
slab class 5: chunk size 7776 perslab 134
slab class 6: chunk size 23328 perslab 44
slab class 7: chunk size 69984 perslab 14
slab class 8: chunk size 209952 perslab 4
slab class 9: chunk size 1048576 perslab 1
上图可见,从56字节的组开始,组的大小依次增大为原来的3倍。 这样设置的问题是,slab之间的差别比较大,有些情况下就相当浪费内存。 因此,为尽量减少内存浪费,追加了growth factor这个选项。在使用memcached时,或是直接使用默认值进行部署时, 最好是重新计算一下数据的预期平均长度,调整growth factor, 以获得最恰当的设置,避免内存的大量浪费。
注意:每个slab class 默认1MB。。所以96x10922=1MB;288x3640=1MB;864x1213=1MB
chunk大小的初始值
64位机情况下,默认memcached把slab分为42类(class1~class42),在class 1中,chunk的默认大小为96字节,由于一个slab的大小是固定的1048576字节(1M),因此在class1中最多可以有10922个chunk:10922×96 + 64 = 1048576。在class1中,剩余的64字节因为不够一个chunk的大小(96byte),因此会被浪费掉。每类chunk的大小有一定的计算公式的,假定i代表分类,class i的计算公式如下:
*chunk size(class i) : (default_size+item_size)f^(i-1)+ CHUNK_ALIGN_BYTES
default_size: 默认大小为48字节,也就是memcached默认的key+value的大小为48字节,可以通过-n参数来调节其大小;
item_size: item结构体的长度,固定为48字节。default_size大小为48字节,item_size为48,因此class1的chunk大小为48+48=96字节;
CHUNK_ALIGN_BYTES是一个修正值,用来保证chunk的大小是某个值的整数倍。
下面使用-n参数将chunk的初始值大小设置为80字节:
$ memcached -n 80 -vv
输出示例:
slab class 1: chunk size 128 perslab 8192
slab class 2: chunk size 160 perslab 6553
slab class 3: chunk size 200 perslab 5242
slab class 4: chunk size 256 perslab 4096
slab class 5: chunk size 320 perslab 3276
slab class 6: chunk size 400 perslab 2621
slab class 7: chunk size 504 perslab 2080
slab class 8: chunk size 632 perslab 1659
slab class 9: chunk size 792 perslab 1323
slab class 10: chunk size 992 perslab 1057
slab class 11: chunk size 1240 perslab 845
page大小
memcache默认的page大小是1M,所以不能存入大小超过1M的数据,但一旦需要存入大数据时可以使用-I参数来设置page的值,比如我将page值设为0.5M(不推荐将page值设置为超过1M):
memcached -I 524288 -vv
输出示例:
slab class 1: chunk size 96 perslab 5461
slab class 2: chunk size 120 perslab 4369
slab class 3: chunk size 152 perslab 3449
slab class 4: chunk size 192 perslab 2730
slab class 5: chunk size 240 perslab 2184
slab class 6: chunk size 304 perslab 1724
slab class 7: chunk size 384 perslab 1365
slab class 8: chunk size 480 perslab 1092
slab class 9: chunk size 600 perslab 873
memcached-tool使用
perl memcached-tool server_ip:prot option
比如:
perl memcached-tool 10.0.0.5:11211 display # shows slabs
perl memcached-tool 10.0.0.5:11211 # same. (default is display)
perl memcached-tool 10.0.0.5:11211 stats # shows general stats
perl memcached-tool 10.0.0.5:11211 move 7 9 # takes 1MB slab from class #7
# to class #9.
输出示例:
# Item_Size Max_age 1MB_pages Count Full?
1 104 B 1394292 s 1215 12249628 yes
2 136 B 1456795 s 52 400919 yes
...
各列的含义为:
# slab class编号
Item_Size Chunk大小
Max_age LRU内最旧的记录的生存时间
1MB_pages 分配给Slab的页数
Count Slab内的记录数
Full? Slab内是否含有空闲chunk