memcached是一个分布式,开源的数据存储引擎。
memcached是一款高性能的分布式内存缓存服务器,通过减少查询次数来抵消沉重缓慢的数据集或API调用、提高应用响应速度、提高可扩展性。
在高并发的场景下, 大量的读/写请求涌向数据库, 此时磁盘IO将成为瓶颈, 从而导致过高的响应延迟, 因此缓存应运而生.
Memcached的工作方式是将关键词和他们对应的值(最大能达到1MB)保存在一个关联矩阵中(比如哈希表),延展和分布在大量的虚拟服务器中。
当然无论是单机缓存还是分布式缓存都有其适用场景和优缺点, 最常见的有redis和memcached. 本文主要是介绍memcached.
硬盘 --> 内存 --> 三级缓存 --> 二级缓存 --> 一级缓存
首先访问较快的存储介质, 如果命中且未生效则返回内容. 如果命中或失效则访问较慢的存储介质将内容返回同时更新缓存.
特点 | 描述 |
---|---|
协议简单 | 它是基于文本行的协议,直接通过telnet在memcached服务器上可进行存取数据操作 |
基于libevent事件处理 | 异步I/O, 基于事件的单进程和单线程, 使用libevent作为事件处理机制; |
内置内存存储方式, 非持久性存储 | 所有数据都保存在内存中,存取数据比硬盘快,当内存满后,通过LRU算法自动删除不使用的缓存,但没有考虑数据的容灾问题,重启服务,所有数据会丢失。 |
分布式 | 各个memcached服务器之间互不通信,各自独立存取数据,不共享任何信息。服务器并不具有分布式功能,分布式部署取决于memcache客户端。 |
# 安装依赖包
apt-get install libevent-dev
#安装Memcached
wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install
#启动memcached
memcached -p 11211 -d -u root -P /tmp/memcached.pid
复制代码
-P是表示使用TCP,默认端口为11211 -d表示后台启动一个守护进程(daemon) -u表示指定root用户启动,默认不能用root用户启动 -P表示进程的pid存放地点,此处“p”为大写“P” -l,后面跟IP地址,手工指定监听IP地址,默认所有IP都在监听 -m后面跟分配内存大小,以MB为单位,默认为64M -c最大运行并发连接数,默认为1024 -f 块大小增长因子,默认是1.25 -M 内存耗尽时返回错误,而不是删除项,即不用LRU算法 在64位系统中,会报libevent-1.4.so.2文件无法找到,解决办法是把32位目录里的同名文件链接至64位目录中,即像windows那样建立快捷方式。 Shell > /usr/local/lib/libevent-1.4.so.2 /usr/lib64/libevent-1.4.so.2 启动后如果发现没有端口在监听,是因为命动命令时带pid参数的“p”是大写“P”,你可能写成小写了。
// 运行一个内存限制为1024MB的容器:
sudo docker run -name csphere-memcached -m 1024m -d -p 11211:11211 memcached:alpine
复制代码
可以查看Memcached:latest
使用的 Dockerfile, 来获取 memcached在debian下的安装方法
分类 | 方法 | 描述 |
---|---|---|
存 | set | 添加一个新条目到memcached或是用新的数据替换替换掉已存在的条目 |
存 | add | 当KEY不存在的情况下,它向memcached存数据,否则,返回NOT_STORED响应 |
存 | replace | 当KEY存在的情况下,它才会向memcached存数据,否则返回NOT_STORED响应 |
存 | cas | 改变一个存在的KEY值 ,但它还带了检查的功能 |
存 | append | 在这个值后面插入新值 |
存 | prepend | 在这个值前面插入新值 |
取 | get | 取单个值 ,从缓存中返回数据时,将在第一行得到KEY的名字,flag的值和返回的value长度,真正的数据在第二行,最后返回END,如KEY不存在,第一行就直接返回END |
取 | get_multi | 一次性取多个值 |
删 | delete |
# 清空memcache数据
telnet 10.27.5.71 11211
flush_all
quit //退出telnet
复制代码
yum -y install libmemcached.x86_64 libmemcached-devel.x86_64
cd /usr/src
git clone https://github.com/php-memcached-dev/php-memcached.git
cd php-memcached/
git checkout php7
/alidata/server/php/bin/phpize
./configure --with-php-config=/alidata/server/php/bin/php-config
make
make install
复制代码
可以通过命令行直接管理与监控也可通过nagios等监控软件进行监控 命令行:
// 如果在启动时指定了IP及端口号,这里要作相应改动,连接成功后命令
telnet 127.0.0.1 11211
复制代码
命令 | 描述 |
---|---|
stats | 统计memcached的各种信息 |
stats reset | 重新统计数据 |
stats slabs | 显示slabs信息,可以详细看到数据的分段存储情况 |
stats items | 显示slab中的item数目 |
stats cachedump 1 0 | 列出slabs第一段里存的KEY值 |
set/get | 保存/获取数据 |
STAT evictions 0 | 表示要腾出新空间给新的item而移动的合法item数目 |
Memcached利用slab allocation机制来分配和管理内存,它按照预先规定的大小,将分配的内存分割成特定长度的内存块,再把尺寸相同的内存块分成组,数据在存放时,根据键值 大小去匹配slab大小,找就近的slab存放,所以存在空间浪费现象。
传统的内存管理方式是,使用完通过malloc分配的内存后通过free来回收内存,这种方式容易产生内存碎片并降低操作系统对内存的管理效率。
Memcached的内存管理制效率高,而且不会造成内存碎片,但是它最大的缺点就是会导致空间浪费。因为每个 Chunk都分配了特定长度的内存空间,所以变长数据无法充分利用这些空间。如图二所示,将100个字节的数据缓存到128个字节的Chunk中,剩余的28个字节就浪费掉了。
如何避免内存浪费
Memcached的缓存策略是**LRU(最近最少使用)**加上到期失效策略。当你在memcached内存储数据项时,你有可能会指定它在缓存的失效时间,默认为永久。当memcached服务器用完分配的内时,失效的数据被首先替换,然后也是最近未使用的数据。在LRU中,memcached使用的是一种Lazy Expiration策略,自己不会监控存入的key/vlue对是否过期,而是在获取key值时查看记录的时间戳,检查key/value对空间是否过期,这样可减轻服务器的负载。
当空间占满时
memcached不相互通信,那么memcached是如何实现分布式的呢?
memcached的分布式实现主要依赖客户端的实现.
当数据到达客户端, 客户端实现的算法会根据”键”来决定保存的memcached服务器. 服务器选定后, 命令他保存数据. 取的时候也一样, 客户端根据”键”选择服务器, 使用保存时候的相同算法就能保存选中和存的时候相同的服务器.
也就是说,存取数据分二步走,第一步,选择服务器,第二步存取数据。
使用什么算法选择服务器呢?
client 使用Hash算法来完成数据分散存储.
复制代码
当向memcached集群存入/取出key/value时,memcached客户端程序根据一定的算法计算存入哪台服务器,然后再把key/value值存到此服务器中。也就是说,存取数据分二步走,第一步,选择服务器,第二步存取数据。
常用的算法有两种: 余数计算分散法 和 一致性Hash算法.
3.4.1 余数计算分散法
CRC($key)%N
复制代码
客户端首先根据key来计算CPC, 然后结果对服务器取模得到memcached服务器节点
3.4.2 一致性hash算法
将server的hash值分配至0~2^32的圆环上, 用同样的方法求出存储数值键的hash值并映射到圆上. 然后从数据映射到的位置开始顺时针查找, 将数据存放至找到的第一台服务器上. 如果超过0~2^32还找不到, 则将数据存放至第一台服务器.
如果新添/删除一台server, 在一致性hash算法下会有什么影响?
如图, 新添/删除server时, 只在圆上增加服务器的逆时针方向的第一台服务器上的键会受到影响。
优化一致性hash算法
优化后: 在物理机很少的情况下, 只要虚拟节点足够多, 也能使的key分布相对均匀. 提升了算法的平衡性.
3.5.1 是单调性(Monotonicity)
单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
复制代码
3.5.2 平衡性
平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。
复制代码
hash 算法并不是保证绝对的平衡
对比点 | memcached | redis |
---|---|---|
数据结构 | 单一(存储数据的类型都是String字符串类型) | 丰富(String、List、Set、Sortedset、Hash) |
内存使用率 | 使用简单的key-value存储,Memcached的内存利用率更高 | Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached |
持久化 | 不可以 | 可以(可以把数据随时存储在磁盘上) |
数据同步 | 不可以 | 可以 |
多核 | 可以使用多核(多线程) | 单核 |
数据大小 | 单个key(变量)存放的数据有1M的限制 | 单个key(变量)存放的数据有1GB的限制 |
计算能力 | 无 | 本身有一定的计算功能 |
memcached和redis对过期数据的处理
Redis是懒处理,对有有效期的数据会做有效期的标识,在指定时间会对有过期时间的数据做处理。随机取出一部分数据,检查是否有过期数据,如果过期数据超过25/100,则反复此过程
它使用libevent,可以应付任意数量打开的连接(使用epoll,而非poll),使用非阻塞网络IO,分布式散列对象到不同的服务器,查询复杂度是O(1)。
缓存命中率 = get_hits/cmd_get * 100%
一致性Hash
a. 在软件工程的项目实战中, 经常会遇到时间/空间的权衡, 缓存是权衡中被研究出的一种典型的技术, 而memcached又是此类技术中的佼佼者.
b. 在高并发环境下,大量的读、写请求涌向数据库,此时磁盘IO将成为瓶颈,从而导致过高的响应延迟,因此缓存应运而生。
c. 本文在理解缓存基本概念的情况下介绍了memcached的分布式算法实现原理
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。天生支持集群。
目前有多种平台的Memcached版本,比如Linux、FreeBSD、Solaris 、Mac OS X及Windows平台。
官方网站:http://memcached.org/
我们安装Windows版本来演示。
32bit:下载 memcached-win32-1.4.4-14.zip
64bit:如果需要win64版,下载 memcached-win64-1.4.4-14.zip
Memcached 内存管理机制:
Menceched 通过预分配指定的内存空间来存取数据,所有的数据都保存在 memcached 内置的内存中。利用 Slab Allocation 机制来分配和管理内存。按照预先规定的大小,将分配的内存分割成特定长度的内存块,再把尺寸相同的内存块分成组,这些内存块不会释放,可以重复利用。当存入的数据占满内存空间时,Memcached 使用 LRU 算法自动删除不是用的缓存数据,即重用过期数据的内存空间。Memcached 是为缓存系统设计的,因此没有考虑数据的容灾问题,和机器的内存一样,重启机器将会丢失,如果希望服务重启数据依然能保留,那么就需要 sina 网开发的 Memcachedb 持久性内存缓冲系统,当然还有常见的 NOSQL 服务如 redis。默认监听端口:11211
添加新的键值对数据
获取已存在的键值对数据
一致性Hash算法是分布式缓存的核心理论,我也学习得不深入,也只是刚刚了解了一下,后面我有空深入学习一下。
首先,简单的路由算法(通过使用余数Hash)无法满足业务发展时服务器扩容的需要:缓存命中率下降。例如:当3台服务器扩容至4台时,采用普通的余数Hash算法会导致大约75%(3/4)被缓存了的数据无法正确命中,随着服务器集群规模的增大,这个比例会线性地上升。那么,可以想象,当100台服务器的集群中加入一台服务器,不能命中的概率大概是99%(N/N+1),这个结果显然是无法接受的。那么,能否通过改进路由算法,使得新加入的服务器不影响大部分缓存数据的正确性呢?请看下面的一致性Hash算法。
引用文献:
https://juejin.im/post/5b84a73ae51d4538c86d1560
https://www.jianshu.com/p/e5b11670c3bb