技术之道

长风破浪会有时,直挂云帆济沧海

  • 首页
  • 分类
  • 归档
  • 标签

  • 搜索
服务治理 k8s tabnine cursor github copilot ai chatgpt chatgpt ai sop 技术选型 bigdata 工具 多进程多线程 docker 计算机网络 mysql 事务 基础架构 kafka nio 分布式 服务搭建 监控 jvm 管理/成长 jenkins devops 云原生 nginx 架构 故障处理 hive spark mapreduce apm redis memcached java 性能 linux

Memcached标准化

发表于 2022-08-22 | 分类于 中间件 | 0 | 阅读次数 298

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
# memcached
Memcached原理
Redis常用命令及故障恢复
  • 文章目录
  • 站点概览
lw‘Blogs

lw‘Blogs

自信人生二百年,会当水击三千里

80 日志
8 分类
40 标签
RSS
Github E-mail
Creative Commons
© 2025 京ICP备2022025426号-1