memcached - a distributed memory object caching system

云端 Extstore - Dormando (2018 年 8 月 15 日)

在我们关于 memcached 外部存储的介绍性文章中,我们谈到了持久内存、昂贵的 NVMe 设备和数 TB 的缓存。Extstore 与来自各种云供应商的商品 VM-with-SSD 有关吗?在这篇文章中,我们将通过在廉价的 DigitalOcean VM 上安装和配置 extstore 来回答这个问题。

用例:会话缓存

无论好坏,云中键值存储的一个主要用例是会话缓存。这些对象是短暂的,经常更新的,与用户登录会话关联的大型数据块。非结构化数据和生存时间限制使其不适合作为主数据库。

网站所有者通常会设置一个 memcached 实例来处理会话。我们将重点关注会话数据,但是该实例可以同时处理其他数据。

问题

假设您有一个网站,它已经从单个 droplet 发展起来。您有一个每月 20 美元的实例,其中 3.5G 的 RAM 专用于 memcached(尽管我们建议您运行多个实例,以防万一一个实例出现故障!)。您最近注意到,用户无法每天保持登录状态,并且您的数据库使用量正在上升。

内存需求

对于许多会话实现,如果会话对象消失,用户将注销或数据库将遭受大量打击以重新生成它。因此,重要的是要将会话保留在它们有用的时间内。

Extstore 需要将对象的键和元数据保存在 RAM 中,同时将值指向存储。这对于小型对象来说不太合适。会话数据可能会变得相当大,所以让我们先检查一下。

$ echo "stats slabs" | nc localhost 11211 | grep -E "total_pages|chunk_size"
[... snip ...]
STAT 26:chunk_size 27120
STAT 26:total_pages 321
STAT 27:chunk_size 33904
STAT 27:total_pages 2936
STAT 28:chunk_size 42384
STAT 28:total_pages 157
[... snip ...]

通过快速检查,我们可以看到,分配的大部分内存最终都用于使用 26k-42k 内存的对象,其中大部分为 32k。即使在极端情况下,memcached 中的键和元数据也不能超过 300 字节,因此大部分空间都是项目值。非常适合 extstore!(尽管是人为的)

您可以并且应该查看或绘制来自 stats itemsstats slabs 的计数器。在这种情况下,我们可以发现 slab 类 26、27 和 28 也具有很高的驱逐计数。我们过早地丢弃了会话!

扩展缓存并降低成本

目前,我们通过一个 20 美元的 droplet 获得了 3.5G 的 RAM 缓存。截至撰写本文时,一个 10 美元的 droplet 附带 2G 的 RAM 和 50G 的 SSD 支持的磁盘空间。让我们尝试将可用缓存空间增加三倍,而成本减半。

设置实例

由于 extstore 仍然是新功能,您可能需要自己构建 memcached 来启用它。当您阅读本文时,这可能不再需要,因此请检查 memcached -h 以查看是否支持 extstore,然后再手动构建任何内容。

在本例中,我们使用来自 DigitalOcean 的 Ubuntu 18.04 64 位 Droplet。请根据您的喜好对这些二进制文件和配置进行打包、快照或管理。

首先,获取最新的 tarball。我们应该修复重定向;)

d@blogbox:~$ wget https://memcached.org.cn/latest
[... snip ...]
latest		       100%[=========================>] 454.27K  --.-KB/s    in 0.005s

2018-08-14 04:46:27 (96.5 MB/s) - ‘latest’ saved [465169/465169]

d@blogbox:~$ tar -zxvf latest
d@blogbox:~$ ls
latest	memcached-1.5.10
d@blogbox:~$ rm latest

接下来,我们获取一些依赖项并编译守护进程。请注意,在基于 Red Hat 的发行版(CentOS 等)上,您可能需要安装一些 Perl 模块才能运行测试。

d@blogbox:~$ cd memcached-1.5.10/
d@blogbox:~/memcached-1.5.10$ sudo apt-get install build-essential libevent-dev
Reading package lists... Done
Building dependency tree... 50%
Reading state information... Done
[... snip ...]
Do you want to continue? [Y/n] y
[... snip ...]
d@blogbox:~/memcached-1.5.10$ ./configure --enable-extstore
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
[... snip ...]
configure: creating ./config.status
config.status: creating Makefile
config.status: creating doc/Makefile
config.status: creating config.h
config.status: executing depfiles commands
d@blogbox:~/memcached-1.5.10$ make
[... snip ...]
Leaving directory '/home/d/memcached-1.5.10'
make[1]: Leaving directory '/home/d/memcached-1.5.10'
d@blogbox:~/memcached-1.5.10$

可选地,运行测试。注意在 1.5.10 中,在 Ubuntu 18.04 上,t/lru-maintainer.t 可能会因竞争条件而失败。这已经修补,将在 1.5.11 中修复。

d@blogbox:~/memcached-1.5.10$ make test
[ might fail on t/lru-maintainer.t ]

现在,我们将二进制文件安装到 /usr/local 中。您可以在配置步骤中使用 --prefix 更改此设置。

d@blogbox:~/memcached-1.5.10$ sudo make install

源 tarball 附带 systemd 服务脚本和配置文件。让我们安装它们。请参阅以下内容以了解对文件的某些编辑。

d@blogbox:~/memcached-1.5.10$ sudo cp scripts/memcached.service /etc/systemd/system/
d@blogbox:~/memcached-1.5.10$ sudo mkdir /etc/sysconfig
d@blogbox:~/memcached-1.5.10$ sudo cp scripts/memcached.sysconfig /etc/sysconfig/memcached
d@blogbox:~/memcached-1.5.10$ sudo vi /etc/systemd/system/memcached.service
d@blogbox:~/memcached-1.5.10$ sudo vi /etc/sysconfig/memcached

编辑 /etc/systemd/system/memcached.service 中的“ExecStart”行,使其看起来像

ExecStart=/usr/local/bin/memcached -p ${PORT} -u ${USER} -m ${CACHESIZE} -c ${MAXCONN} $OPTIONS

我们所做的只是在路径中添加“/local/”。

最后,使用类似于以下内容的 /etc/sysconfig/memcached

# These defaults will be used by every memcached instance, unless overridden
# by values in /etc/sysconfig/memcached.
USER="nobody"
MAXCONN="1024"
CACHESIZE="1500"
OPTIONS="-l 127.0.0.1 -o ext_path=/tmp/extstore:10G,ext_item_size=512"

# The PORT variable will only be used by memcached.service, not by
# memcached@xxxxx services, which will use the xxxxx
PORT="11211"

最后,启用并启动服务

d@blogbox:~/memcached-1.5.10$ sudo systemctl enable memcached
Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → 
 /etc/systemd/system/memcached.service.
d@blogbox:~/memcached-1.5.10$ sudo systemctl start memcached
d@blogbox:~/memcached-1.5.10$ ps aux | grep -i memcached
nobody	 10069	0.0  0.3 1723160 7152 ?        Ssl  05:32   0:00
/usr/local/bin/memcached -p 11211 -u nobody -m 1024 -c 1024 -l 127.0.0.1 -o
ext_path=/tmp/extstore:10G,ext_item_size=512
d	 10100	0.0  0.0  14856  1048 pts/1    S+   05:33   0:00 grep --color=auto -i memcached
d@blogbox:~/memcached-1.5.10$

然后...您就完成了!您现在已使用 1.5G 的 RAM 和 10G 的磁盘支持存储配置了 memcached。我们还告诉它允许将任何大于 512 字节的对象刷新到磁盘。


您可以(也应该!)根据自己的用例进行实验。也许您想将缓存分散到更多节点以提高可靠性,也许您的会话更小(因此需要更多 RAM)等等。没有硬性规定。

不太可能。Memcached 不会立即将大型对象刷新到磁盘:只要有可能,它们就会保留在 RAM 中。实际上,最新的对象也是“最热的”,经常被读取和覆盖。即使磁盘比 RAM 多 10 倍,9/10 的读写操作也可能保留在 RAM 中。

作为额外的好处,当对象被覆盖、删除或因 TTL 而过期时,它们不会造成任何磁盘 I/O。即使对于云实例有限的 I/O,这也能很好地扩展。

结论

通过本演练,我们能够将理论网站会话缓存扩展 3 倍,成本降低一半。虽然这不能涵盖所有用例,但它可以快速确定并廉价地进行实验。

更详细的文档可在 维基页面 上找到。