memcached内存分配机制
内存碎片化问题
memcached slab allocator
基本原理:预先把内存划分成数个slab仓库,各仓库,切分成不同尺寸的小块,需要存内容时,判断内容的大小,为其选取合理的块。
警告:如果有100byte的内容要存,但122大小的仓库中的chunk满了怎么办?
并不会寻找更大的,如144的仓库来存储,而是把122仓库的旧数据踢掉!
slab allocator的缺点
chunks为固定大小,造成浪费,这个问题不能克服,只能缓解
如何缓解?
对于特定的网站,你可以长期的统计网站内存缓存数据,按自己的网站的特点,设置chunk的大小
一般而言,观察缓存数据大小的变化规律,设置合理的生长因子
grow factor默认是1.25倍
可以根据自己网站缓存的大小,来调整比例因子
memcheched的过期数据删除机制——LRU删除机制
- 当某个值过期后,并没有从内存删除,因此,stats统计时curr_item有其信息
- 当取其值时,判断是否过期,如果过期,返回空,并且清空,curr_item就减少了
- 如果之前没有get过,将不会自动删除,当某个新值去占用他的位置时,当成空chunk来占用
即,这个过期,只是让用户看不到这个数据而已,并没有在过期的瞬间立即从内存删除,这个称为lazy expiration,惰性失效
优点:节省了cpu时间的检测的成本
如果以122byte大小的chunk举例,122的chunk都满了,又有新的值(长度为120)要加入,要挤掉谁?
memcached此处用的LRU删除机制(操作系统的内存管理,常用FIFO,LRU删除)
LRU Least Recently Used 最近最少使用
FIFO first in,first out
原理:当某个单元被请求时,维护一个计数器,通过计数器来判断最近谁最少被使用,就把谁T出
注:即时某个key是设置的永久有效,也一样还会被踢出来!--老数据被踢现象
linux下编译memcached
从官网获取最新源码
- 准备编辑环境
安装编译器和工具:
- yum install gcc make
- yum install autoconf
- yum install libtool
一次执行的命令
yum install gcc make libtool autoconf
这几件工具,以后还要编译redis等时使用
2.下载相应的库和memcached源码
memcached依赖于libevent库,因此我们需要先安装libevent
libevent
http://libevent.org/
memcached
http://memcached.org/
进入 /usr/local/src/目录
wget https://github.com/libevent/libevent/releases/download/release-2.0.22-stable/libevent-2.0.22-stable.tar.gz
wget -O "文件名" http://文件地址 下载并命名
wget http://www.memcached.org/files/memcached-1.4.31.tar.gz
先安装库
解压libevent
查到tar zxvf libevent-2.0.22-stable.tar.gz
cd 进目录
./configure - h
./configure --prefix=/usr/local/libevent
安装 make && make install
库装好了
安装memcached
./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
make && make install
--no-check-certificate
注意:安装时容易碰到时间不对,导致gcc编译过程检测时间通不过,一直处于编译过程
解决办法
date -s 'yyy-mm-dd HH:mm:ss'
clock --w (把时间写入cmos)
启动memcached
./bin/memcached -m 64 -p 11211 -u nobody -vvv
不能以root用户开启
memcached中的一些参数限制
- key的长度:250字节(二进制协议支持65536个字节)
- value的限制:1M,一般都是存储一些文本,如新闻列表等等,这个值也足够了
- 内存的限制:32位下最大设置到2G
如果有30G数据要缓存,一般也不会单实例装30G(不要把鸡蛋装在一个篮子里)
一般建议开启多个实例(可以在不同的机器,或同台机器的不同端口开几个)
PHP连接memcached
在windows下添加memcached.dll
windows下的dll下载下来,未必能够使用,要寻找合适的dll,需要考虑3个参数
根据PHP.ini判断
- 编辑器comliler vc9还是vc6
- php的大版本
- ts或nts
- 下载编译好的dll,并放在php扩展的目录下
- 观察正确的目录和配置文件路径
- 观察extension_dir的路径,
- 运行phpinfo(),确认真正实用的PHp.ini文件是哪个
- 把dll放入extension目录,修改php.ini,重启apache
linux下编译apache和php
cd /usr/local/src/
分别从官网下载apache和php
apache http://httpd.apache.org/download.cgi#apache24
php http://php.net/downloads.php
./configure --prefix=/usr/local/httpd
[root@localhost httpd-2.4.23]# ./configure --prefix=/usr/local/httpd
checking for chosen layout... Apache
checking for working mkdir -p... yes
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking target system type... x86_64-unknown-linux-gnu
configure:
configure: Configuring Apache Portable Runtime library...
configure:
checking for APR... no
configure: error: APR not found. Please read the documentation.
http://apr.apache.org/
http://mirror.bit.edu.cn/apache//apr/apr-1.5.2.tar.gz
http://apache.fayea.com//apr/apr-util-1.5.4.tar.gz
http://stackoverflow.com/questions/9436860/apache-httpd-setup-and-installation
http://www.cnblogs.com/Anker/p/3355573.html
参考:
http://blog.sina.com.cn/s/blog_912389e5010141rb.html
pcre被墙
https://sourceforge.net/projects/pcre/files/pcre/8.39/
http://ftp.exim.llorien.org/pcre/
pcre报错
configure: error: You need a C++ compiler for C++ support.
解决办法:
yum install -y gcc gcc-c++
编译apache
./configure --prefix=/usr/local/httpd --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util/ --with-pcre=/usr/local/pcre/
启动apache
/usr/local/httpd/bin/apachectl start
编译php
./configure --prefix=/usr/local/php --with-httpd --with-apxs2=
http://blog.sina.com.cn/s/blog_4d83777b0100pgal.html
libxml2 没找到的错误
解决方法
同时安装libxml2 和 devle
yum
php编译完之后要进入
/usr/local/httpd/conf/httpd
添加addType
重启apache
编辑PHP的memcache扩展
php扩展通用的编译方法——以memcache为例
- 到软件的官方(如memcached)或pecl.php.net查找去寻找源码包
- 进入到/memecache目录
- 配置configure环境
configure依赖于当前系统的php环境,所以要根据php环境配置configure
在扩展目录下执行
# /usr/local/php/bin/phpize --with-php-config=/usr/local/php/bin/php-config
configure报错
configure: error: Cannot find php-config. Please use --with-php-config=PATH
解决办法
./configure --with-php-config=/usr/local/php/bin/php-config
configure报错
checking for libmemcached location... configure: error: memcached support requires libmemcached. Use --with-libmemcached-dir=<DIR> to specify the prefix where libmemcached headers and library are located
解决办法
缺少依赖库
http://libmemcached.org/libMemcached.html
wget tar zxvf cd
./configure --prefix=/usr/local/libmemcached
make && make install
./configure --with-php-config=/usr/local/php/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached/
configure报错
configure: error: no, sasl.h is not available. Run configure with --disable-memcached-sasl to disable this check
creating libtoolappending
configuration tag "CXX" to libtoolconfigure: creating ./config.status
config.status: creating config.h
config.status: config.h is unchanged
编译成功,在php的扩展目录下生成了memcache.so
/usr/local/php/lib/php/extensions/no-debug-zts-20131226
配置php.ini
在合适的位置加入
extension=/usr/local/php/lib/php/extensions/no-debug-zts-20131226/memcached.so
重启apache
/usr/local/httpd/bin apacheacl restart
参考 http://blog.51yip.com/php/928.html
分布式之取模算法的缺陷
假设有8台服务器,运行中突然down一台,则求余的底数变成7
后果:
key0%8==1,key0%7==1 hits
……
key6%8==6,key6%7==6 hits
key9%8==1,key9%7==2 miss
……
key55%8==7,key55%7==6 miss
我们从数学上归纳之:
有N台服务器,变为N-1台
每NN-1个数中,求余相同的数字只有N-1个数字
所以命中率在服务器宕机的短时间内,急剧下降至(N-1)(N(N-1)) = 1/(N-1)
所以:服务器越多,则宕机的危害越大
一致性哈希算法
缓存雪崩现象
一般是由某个节点失效,导致其他节点的缓存命中率下降,缓存中缺失的数据去数据库查询,短时间内,造成数据库服务器崩溃。
重启DB,短期又被压垮,但缓存数据也多一些
DB反复启动多次,缓存重建完毕,DB稳定运行
或者是由于缓存周期性的失效,比如,每6小时失效一次,那么每6小时将有一个请求峰值。
见下面这个真实例子,及解决办法:
解决方案:
1.讨论的解决方案:
把缓存设置为随机3-9小时的生命周期,这样不同时失效,把工作分担到各个时间点上去。
2.在夜间访问量比较低的时候缓慢重建缓存。
缓存无底洞现象
facebook工作人员反映的,facebook在2010年左右,memcached节点就已经达到3000个,存储数千G的缓存。
他们发现了一个问题——memcached连接频繁,效率下降了,于是加memcached节点,添加了后,发现因为连接频率导致的问题,仍然存在,并没有好转。
以会员信息为例:
user-133-age 22
user-133-height 170
user-89-age 60
user-89-height 182
问题分析:
用用户为例:共N个key
当服务器增多,133号用户的信息,也被散落在更多的服务器
所以,同样是访问个人主页,得到相同的个人信息,节点越多,要连接的节点也越多,对于memcached的连接数,并没有虽则节点的增多而降低,问题出现
事实上:
Nosql和传动的RDBNS,并不是水火不容,两者在某些设计上,是可以相互参考的
对于memcached,redis这种kv存储,key的设计,可以参考mysql中表与列的设计
比如:user表下,有age列,name列,身高列,
对应的key,可以用
user:133:age =23,
user:133:name='lisi',
user:133:height:168,
问题解决方案:
把某一组key,按其共同前缀来分布,在用分布式算法求其节点时,应该以‘user-133’来计算,而不是以‘user-133-age/name/height’来计算
这样,3个关于个人信息的key都落在同一个节点上,访问个人主页时,只需要连接一个节点,问题解决。
永久数据被踢现象
网上有人反馈为 memcached数据丢失,明明设为永久有效,却莫名其妙的丢失了
这要从两方面找原因:
即前面介绍的惰性删除与LRU最近最少使用记录删除
- 数据在内存中并未真正删除,系统也不知道某个item已失效,下次去get时才知道失效,才把chunk情况
- 如果slab里的很多chunk都已经过期,但从没有被get过,系统不知他们已经过期
- 永久数据很久没get了,不活跃,如果新增item则永久数据被踢了
- 当然,如果那些非永久数据频繁的get,也会别标识为expire,从而不会再踢掉永久数据
官方解决方案:永久数据和非永久数据分开放
安装memcache扩展
下载源码包
wget http://pecl.php.net/get/memcache-3.0.8.tgz
解压源码包
tar zxvf memcache-3.0.8.tgz
生成configure文件
/usr/local/php/bin/phpize --with-php-config=/usr/local/php/bin/php-config
./configure --with-php-config=/usr/local/php/bin/php-config
creating libtool
appending configuration tag "CXX" to libtool
configure: creating ./config.status
config.status: creating config.h
make && make install
Build complete.
Don't forget to run 'make test'.
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-zts-20131226/
[root@localhost memcache-3.0.8]#