Memcached学习笔记

来源:互联网 发布:淘宝评价回复语大全 编辑:程序博客网 时间:2024/05/18 01:48

一、Memcached介绍

1.1、什么是Memcached?—————–free&opensource,high-performance,distributedmemory objectcachingsystem
自由&开放源码, 高性能 ,分布式的内存对象缓存系统 由 livejounal 旗下的 danga 公司开发的老牌 nosql 应用.
百度百科:
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。
Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。![Memcached缓存图解](http://img.blog.csdn.net/20160502224115919)1.2什么是 NoSQL?————-nosql,指的是非关系型的数据库。
相对于传统关系型数据库的”行与列”,NoSQL 的鲜明特点为 k-v 存储(memcached,redis), 或基于文档存储(mongodb).
> 注: nosql–notonlysql, 不仅仅是关系型数据库, 显著特点:key-value 键值对存储,如 memcached,redis, 或基于文档存储 如,mongodb

二、Memcached基本使用

2.1 linux 下编译 memcached———————–2.1.1:准备编译环境
libevent官网:http://libevent.org/
Memcached官网:http://memcached.org
• 安装 libevent(memcached依赖libevent)
  tar zxvf libevent-2.0.1-stable.tar.gz <br>  cd libevent-2.0.21-stable <br>  ./configure --prefix=/usr<br>  make # make install <br>
• 安装 Memcached
  tar zxvf memcached-1.4.15.tar.gz<br>  cd memcached-1.4.15 <br>  ./configure --prefix=/usr/local <br>  make<br>  make install
在 linux 编译,需要 gcc,make,cmake,autoconf,libtool 等工具.
在 linux 系统联网后,用如下命令安装
> yum install gcc make cmake autoconf libtool2.2 memcached 的启动
memcached -h 查看帮助命令
-p <num>                        监听的TCP端口 (缺省: 11211)-d                              以守护进程方式运行Memcached-u <username>                   运行Memcached的账户,非root用户-m <num>                        最大的内存使用, 单位是MB,缺省是 64 MB-c <num>                        软连接数量, 缺省是 1024-v                              输出警告和错误信息-vv                             打印客户端的请求和返回信息-h                              打印帮助信息-i                              打印memcached和libevent的版权信息
2.3 memcached 的连接
memcached 客户端与服务器端的通信比较简单,使用的基于文本的协议,而不是二进制协议.
(http 协议也是这样), 因此我们通过 telnet 即可与 memcached 作交互.
另开一个终端,并运行 telnet 命令 (开启 memcached 的终端不要关闭)
> 格式 telnet host port
> telnet localhost 11211
> Trying ::1… Connected to localhost.
> Escape character is ‘^]’.连接后 ctrl+] ,然后回车, 打开回显功能
输入stats 回车, 即可查看memcached运行状态.
2.4 memcached 的命令
增: add 往内存增加一行新记录
语法:addkeyflagexpire length 回车
key 给值起一个独特的名字
flag 标志,要求为一个正整数
expire 有效期 length 缓存的长度(字节为单位)
———-flag 的意义:
memcached 基本文本协议,传输的东西,理解成字符串来存储.
想:让你存一个 php 对象,和一个 php 数组,怎么办?
答:序列化成字符串,往出取的时候,自然还要反序列化成 对象/数组/json 格式等等.
这时候,flag 的意义就体现出来了. 比如,1 就是字符串,2 反转成数组 3,反序列化对象…..
———-expire 的意义: 设置缓存的有效期,有 3 种格式
1:设置秒数, 从设定开始数,第 n 秒后失效.
2:时间戳, 到指定的时间戳后失效. 比如在团购网站,缓存的某团到中午 12:00 失效.addkey013792099996
3: 设为 0. 不自动失效.———- delete 删除 deletekey [time seconds] 删除指定的 key.
如加可选参数 time,则指删除 key,并在删除 key 后的 time 秒内,不允许 get,add,replace 操作此 key.
———-replace 替换 replacekeyflagexpire length 参数和 add 完全一样,不单独写.
———-get 查询 get key 返回 key 的值
set 是设置和修改值 参数和 add,replace 一样,但功能不一样.
用 add 时,key 不存在,才能建立此键值.
但对于已经存在的键,可以用 replace 进行替换/更改
repalce,key 存在时,才能修改此键值,如上图,date 不存在,则没改成功.
———-而 set 想当于有 addreplace 两者的功能. setkeyflagexpireleng 时 如果服务器无此键 —-> 增加的效果 如果服务器有此键 —-> 修改的效果.
———- incr,decr 命令:增加/减少值的大小 语法: incr/decrkeynum
- 应用场景——秒杀功能, 一个人下单,要牵涉数据库读取,写入订单,更改库存,及事务要求, 对于传统型数据库来说, 压力是巨大的. 可以利用 memcached 的 incr/decr 功能, 在内存存储 count 库存量, 秒杀 1000 台 每人抢单主要在内存操作,速度非常快, 抢到 count3.1:内存的碎片化———-如果用 c 语言直接 malloc,free 来向操作系统申请和释放内存时, 在不断的申请和释放过程中,形成了一些很小的内存片断,无法再利用. 这种空闲,但无法利用内存的现象,—称为内存的碎片化.3.2: slaballocator 缓解内存碎片化————————–memcached 用 slaballocator 机制来管理内存.
slaballocator 原理: 预告把内存划分成数个 slabclass 仓库.(每个 slabclass 大小 1M)
各仓库,切分成不同尺寸的小块(chunk). 需要存内容时,判断内容的大小,为其选取合理的仓库.
如下图:![这里写图片描述](http://img.blog.csdn.net/20160502224543437)

3.3:Slab Allocator缓存原理

memcached根据收到的数据的大小,
选择最适合数据大小的slab。memcached中保存着slab内空闲chunk的列表,
根据该列表选择chunk,然后将数据缓存于其中。
这里写图片描述

警示: 如果有 100byte 的内容要存,但 122 大小的仓库中的 chunk 满了 并不会寻找更大的,如 144 的仓库来存储, 而是把 122 仓库的旧数据踢掉! 详见过期与删除机制.

3.4 固定大小 chunk 带来的内存浪费———————-由于 slaballocator 机制中, 分配的 chunk 的大小是”固定”的,
因此, 对于特定的 item,可能造 成内存空间的浪费. 比如, 将 100 字节的数据缓存到 122 字节的 chunk 中, 剩余的 22 字节就浪费了.
对于 chunk 空间的浪费问题,无法彻底解决,只能缓解该问题.
开发者可以对网站中缓存中的item的长度进行统计,并制定合理的slabclass中的chunk的大小. 可惜的是,我们目前还不能自定义 chunk 的大小,但可以通过参数来调整各 slabclass 中 chunk 大小的增长速度. 即增长因子,grow factor! ![这里写图片描述](http://img.blog.csdn.net/20160502224629292)3.5 grow factor 调优——————memcached 在启动时可以通过­f 选项指定 Growth Factor 因子, 并在某种程度上控制 slab 之间的差异. 默认值为1.25. 但是,在该选项出现之前,这个因子曾经固定为2,称为”powersof2” 策略。 我们分别用 grow factor 为 2 和 1.25 来看一看效果:
>memcached ­f 2 ­vvv
slab class 1: chunk size 128 perslab 8192
slab class 2: chunk size 256 perslab 4096
slab class 3: chunk size 512 perslab 2048
slab class 4: chunk size 1024 perslab 1024
…. …..
slab class 10: chunk size 65536 perslab 16
slab class 11: chunk size 131072 perslab 8
slab class 12: chunk size 262144 perslab 4
slab class 13: chunk size 524288 perslab 2
可见,从 128 字节的组开始,组的大小依次增大为原来的 2 倍.
来看看 f=1.25 时的输出: >memcached -f 1.25 -vvv
slab class 1: chunk size 88 perslab 11915
slab class 2: chunk size 112 perslab 9362
slab class 3: chunk size 144 perslab 7281
slab class 4: chunk size 184 perslab 5698 …. ….
slab class 36: chunk size 250376 perslab 4
slab class 37: chunk size 312976 perslab 3
slab class 38: chunk size 391224 perslab 2
slab class 39: chunk size 489032 perslab 2对比可知, 当 f=2 时, 各 slab 中的 chunksize 增长很快,有些情况下就相当浪费内存. 因此,我们应细心统计缓存的大小,制定合理的增长因子.
注意: 当f=1.25时,从输出结果来看,某些相邻的slabclass的大小比值并非为1.25,可能会觉得有些 计算误差,这些误差是为了保持字节数的对齐而故意设置的.

3.6 memcached 的过期数据惰性删除

1: 当某个值过期后,并没有从内存删除,因此,stats 统计时,curr_item 有其信息

2: 当某个新值去占用他的位置时,当成空 chunk 来占用.

3: 当 get 值时,判断是否过期,如果过期,返回空,并且清空,curr_item 就减少了.

即–这个过期,只是让用户看不到这个数据而已,并没有在过期的瞬间立即从内存删除.
这个称为 lazyexpiration, 惰性失效. 好处— 节省了 cpu 时间和检测的成本.

3.7: memcached 此处用的 lru 删除机制.—————————–如果以122byte大小的chunk举例,122的 chunk都满了, 又有新的值(长度为 120)要加入, 要挤掉谁?
memcached 此处用的 lru 删除机制. (操作系统的内存管理,常用 fifo,lru 删除)
lru:leastrecentlyused 最近最少使用
fifo:first in,first out
原理: 当某个单元被请求时,维护一个计数器,通过计数器来判断最近谁最少被使用. 就把谁 t 出.
> 注: 即使某个 key 是设置的永久有效期,也一样会被踢出来! 即–永久数据被踢现象

四、分布式集群算法

4.1 memcached 如何实现分布式?

在第 1 章中,我们介绍 memcached 是一个”分布式缓存”,然后 memcached 并不像 mongoDB 那样,允许配置多个节点,且节点之间”自动分配数据”.
就是说–memcached 节点之间,是不互相通信的. 因此,memcached 的分布式,要靠用户去设计算法,把数据分布在多个 memcached 节点中.

4.2 分布式之取模算法

最容易想到的算法是取模算法,即 N 个节点要,从 0->N-1 编号. key 对 N 取模,余 i,则 key 落在第 i 台服务器上.

余数分布式的缺陷:
这里写图片描述

4.3 取模算法对缓存命中率的影响

假设有 8 台服务器, 运行中,突然 down 一台, 则求余的底数变成 7
后果:

key0%8==0, key0%7 ==0 hits ….

key6%8==6, key6%7== 6 hits
key7%8==7, key7%7==0 miss
key9%8==1, key9%7 == 2 miss

key55%8 ==7 key55%7 == 6 miss

一般地,我们从数学上归纳之: 有 N 台服务器, 变为 N-1 台, 每 N*(N-1)个数中, 只有(n-1)个单元,%N,%(N-1)得到相同的结果

所以 命中率在服务器 down 的短期内, 急剧下降至 (N-1)/(N*(N-1)) = 1/(N-1) 所以: 服务器越多, 则 down 机的后果越严重!

4.4 一致性哈希算法原理

这里写图片描述

关于一致性hash算法的详细讲解,请转到:
一致性哈希算法详解

4.5 一致性哈希对其他节点的影响

4.6 一致性哈希+虚拟节点对缓存命中率的影响

理想状态下,
1) 节点在圆环上分配分配均匀,因此承担的任务也平均,但事实上, 一般的 Hash 函数对于节 点在圆环上的映射,并不均匀.
2) 当某个节点 down 后,直接冲击下 1 个节点,对下 1 个节点冲击过大,能否把 down 节点上的 压力平均的分担到所有节点上?

完全可以—引入虚拟节点来达到目标虚拟节点即—-N 个真实节点,把每个真实节点映射成 M 个虚拟节点, 再把 M*N 个虚拟节点, 散列在圆环上. 各真实节点对应的虚拟节点相互交错分布 这样,某真实节点 down 后,则把其影响平均分担到其他所有节点上.

五、memcached 经典问题或现象

5.1 缓存雪崩现象及真实案例

缓存雪崩一般是由某个缓存节点失效,导致其他节点的缓存命中率下降, 缓存中缺失的数据去数据库查询.短时间内,造成数据库服务器崩溃.
重启 DB,短期又被压跨,但缓存数据也多一些.
DB 反复多次启动多次,缓存重建完毕,DB 才稳定运行.
或者,是由于缓存周期性的失效,比如每 6 小时失效一次,那么每 6 小时,将有一个请求”峰值”, 严重者甚至会令 DB 崩溃.

5.2 缓存的无底洞现象 multiget-hole

该问题由 facebook 的工作人员提出的,facebook 在 2010 年左右,memcached 节点就已经达 3000 个.缓存数千 G 内容. 他们发现了一个问题—memcached 连接频率,效率下降了,于是加 memcached 节点, 添加了后,发现因为连接频率导致的问题,仍然存在,并没有好转,称之为”无底洞现象”.
原文见:
http://highscalability.com/blog/2009/10/26/facebooks-memcached-multiget-hole-more-machinesmore-capacit.html

具体表现为:出于效率的考虑,很多Memcached应用都已Multiget操作为主,随着访问量的增加,
系统负载捉襟见肘,
遇到此类问题,直觉通常都是通过增加服务器来提升系统性能,
但是在实际操作中却发现问题并不简单,新加的服务器好像被扔到了无底洞里一样毫无效果。

为什么会这样?让我们来模拟一下案发经过,看看到底发生了什么:

我们使用Multiget一次性获取100个键对应的数据,
系统最初只有一台Memcached服务器,随着访问量的增加,系统负载捉襟见肘,
于是我们又增加了一台Memcached服务器,数据散列到两台服务器上,
开始那100个键在两台服务器上各有50个,
问题就在这里:原本只要访问一台服务器就能获取的数据,
现在要访问两台服务器才能获取,服务器加的越多,
需要访问的服务器就越多,所以问题不会改善,甚至还会恶化。

5.2.1multiget-hole 问题分析

以用户为例:user-133-age, user-133-name,user-133-height …..
N 个 key, 当服务器增多,133 号用户的信息,也被散落在更多的节点,
所以,同样是访问个人主页,得到相同的个人信息, 节点越多,要连接的节点也越多.
对于 memcached 的连接数,并没有随着节点的增多,而降低. 于是问题出现.

5.2.2multiget-hole 解决方案:

把某一组 key,按其共同前缀,来分布.
比如 user-133-age,user-133-name,user-133-height 这 3 个 key,
在用分布式算法求其节点时,应该以‘user-133’来计算,而不是以 user-133-age/name/height 来计算.
这样,3 个关于个人信息的 key,都落在同 1 个节点上,访问个人主页时,只需要连接 1 个节点. 问题解决. 官方回应:http://dormando.livejournal.com/521163.html

事实上: NoSQL 和传统的 RDBMS,并不是水火不容,两者在某些设计上,是可以相互参考的.
对于 memcached,redis 这种 kv 存储,key 的设计,可以参考 MySQL 中表/列的设计. 比如:user 表下,有 age 列,name 列,身高列, 对应的 key,可以用 user:133:age =23,user:133:name=‘lisi,user:133:height =168;

5.3 永久数据被踢现象

网上有人反馈为”memcached 数据丢失”,明明设为永久有效,却莫名其妙的丢失了.
其实,这要从 2 个方面来找原因: 即前面介绍的 惰性删除,与 LRU 最近最少使用记录删除. 分析:
1:如果 slab 里的很多 chunk,已经过期,但过期后没有被get过, 系统不知他们已经过期.
2:永久数据很久没get了,不活跃,如果新增item,则永久数据被踢了.
3: 当然,如果那些非永久数据被 get,也会被标识为 expire,从而不会再踢掉永久数据.

解决方案: 永久数据和非永久数据分开放

0 0
原创粉丝点击