Memcached分布式缓存系统

Memcached分布式缓存系统

介绍

优化访问速度

  • 随着网站迭代开发,访问会变慢。

  • LNMP架构中网站应用访问流程

    • 浏览器(app)=>web服务器=>后端服务(php)=>数据库(mysql)
  • 访问流程越多,访问速度越慢,出现问题的几率也越大

  • 优化访问速度,可以减少访问步骤或者提高单步访问速度

  • 具体优化方法:

    • 提高web服务器的并发量:如采用nginx作为web服务器;多台服务器实现负载均衡
    • 页面静态化:把经常访问,但数据不常变动的动态页面,制作为静态页面
    • 优化数据库
    • 内存缓存优化:把经常访问的数据,加载到缓存中间件(memcached)的内存中

在这里插入图片描述

Memcached介绍

  • cache in memory 缓存放入内存中

  • Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。

  • Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。

  • Memcached是一种基于内存key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。

  • Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。

  • 本质上,它是一个简洁的key-value存储系统

  • 一般的使用目的是,通过缓存数据库查询结果减少数据库访问次数以提高动态Web应用的速度、提高可扩展性

  • Memcached 官网:https://memcached.org/

在这里插入图片描述

Memcached&Redis

  • Redis不仅支持简单的k/v类型的数据,同时还支持list、set、zset(sorted set)、hash等数据结构的存储,使得它拥有更广阔的应用场景

  • Redis最大的亮点是支持数据持久化,它在运行的时候可以将数据备份在磁盘中,断电或重启后,缓存数据可以再次加载到内存中,只要Redis配置的合理,基本上不会丢失数据

  • Redis支持主从模式的应用

  • Redis单个value的最大限制是1GB,而Memcached则只能保存1MB内的数据

  • Memcache在并发场景下,能用cas保证事务一致性,而Redis事务支持比较弱,只能保证事务中的每个操作连续执行

  • 性能方面,Redis在读操作和写操作上是略领先Memcached的

  • Memcached的内存管理不像Redis那么复杂,元数据metadata更小,相对来说额外开销就很少。Memcached唯一支持的数据类型是字符串string,非常适合缓存只读数据,因为字符串不需要额外的处理

slab存储机制

相关概念

  • item:数据存储节点,主要用于存储数据
  • slab:slab是一块内存空间,默认大小为1M
  • chunk:memcached会把一个slab分割成一个个chunk, 这些被切割的小的内存块,主要用来存储item
  • slabclass:每个item的大小都可能不一样,item存储于chunk。如果chunk大小不够,则不足以分配给item使用,如果chunk过大,则太过于浪费内存空间。因此memcached采取的做法是,将slab切割成不同大小的chunk,这样就满足了不同大小item的存储。被划分不同大小chunk的slab的内存在memcached就是用slabclass这个结构体来表现的

img

slabclass的初始化

  • slabclass数组初始化的时候,每个slabclass_t都会分配一个1M大小的slab,slab会被切分为N个小的内存块,这个小的内存块的大小取决于slabclass_t结构上的size的大小
  • 每个slabclass_t都只存储一定大小范围的数据,并且下一个slabclass切割的chunk块大于前一个slabclass切割的chunk块大小
  • memcached中slabclass数组默认大小为64,slabclass切割块大小的增长因子默认是1.25
    例如:slabclass[1]切割的chunk块大小为100字节,slabclass[2]为125,如果需要存储一个110字节的缓存,那么就需要到slabclass[2] 的空闲链表中获取一个空闲节点进行存储。

item节点分配流程

  • 根据大小,找到合适的slabclass
  • 查看slabclass空闲列表中是否有空闲的item节点,如果有直接分配item,用于存储内容
  • 空闲列表没有空闲的item可以分配,会重新开辟一个slab(默认大小为1M)的内存块,然后切割slab并放入到空闲列表中,然后从空闲列表中获取节点

item节点释放

  • 释放一个item节点,并不会free内存空间,而是将item节点归还到slabclass的空闲列表中

失效机制

Lazy Expiration懒惰机制

  • memcached 内部不会监视记录是否过期,而是在 get时查看记录的时间戳,检查记录是否过期。这种技术被称为 lazy(惰性)expiration。因此,memcached 不会在过期监视上耗费 CPU 时间

  • 类似的有:php的里session机制,懒惰机制;php垃圾回收机制;gc回收;python变量垃圾回收机制

  • memcached1.4.25之后,懒惰机制失效

LRU机制

  • memcached 会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为 Least Recently Used(LRU)机制来分配空间。

  • 顾名思义,这是删除“最近最少使用”的记录的机制。因此,当 memcached 的内存空间不足时,就从最近未被使用的记录中搜索,并将其空间分配给新的记录。

  • 从缓存的实用角度来看,该模型十分理想。不过,有些情况下 LRU 机制反倒会造成麻烦,memcached 启动时通过“­M”参数可以禁止 LRU

Memcached安装

  • 基于server07克隆server08
  • 基本环境配置
vim /etc/sysconfig/network
vim /etc/sysconfig/network-scripts/ifcfg-eth
cd /etc/udev/rules.d/
rm -rf 70-persistent-net.rules
reboot
cat >> /etc/hosts <<EOF
	192.168.139.135 memcached
	EOF
service nginx stop
service php-fpm stop
service mysqld stop
  • yum安装
yum install libevent libevent-devel -y 
yum install memcached -y
  • 编译安装
yum install libevent libevent-devel -y 
rz
#memcached-1.5.8.tar.gz
tar -xcf memcached-1.5.8.tar.gz 
cd memcached-1.5.8
./configure --prefix=/usr/local/memcached
make && make install
  • 启动
cd /usr/local/memcached/
cd bin
./memcached -h

#memcached选项说明
-d	是启动一个守护进程
-p	是设置Memcache监听的端口,最好是1024以上的端口
-d	是启动一个守护进程
-m	是分配给Memcache使用的内存数量,单位是MB
-u	是运行Memcache的用户
-l	是监听的服务器IP地址,可以有多个地址
-c	是最大运行的并发连接数,默认是1024
-P	是设置保存Memcache的pid文件

./memcached -uroot -d
ss -tnalp|grep memcached
	LISTEN   0   128   *:11211   *:*    users:(("memcached",3661,26))
#想要关闭memcached,使用killall工具即可

Memcached使用

talnet客户端工具连接memcached

[root@memcached ~]# yum install -y telnet
[root@memcached ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

ERROR
#多次回车出现error,表名连接成功;error表明,没有键入命令
#退出连接:quit

存储命令

  • set:添加数据;如果数据存在,则更新
  • set=add+replace
  • prepend和append的功能都可以通过set实现
语法:
set key flags exptime bytes [noreply]
value

参数说明:
key		键,key-value结构中的key
flags	可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息,默认为0
exptime	过期时间,以秒为单位,0表示永远
bytes	在缓存中存储的字节数,严格限制,不能多一位,也不能少一位
noreply	不需要返回数据
value	值,key-value结构中的value
STORED	存储成功,系统默认返回

案例:
set name 0 0 8
zhangsan
STORED
  • add:添加数据;如果数据存在,不会更新数据(过期的 key 会更新),响应NOT_STORED
语法:
add key flags exptime bytes [noreply]
value

案例:
add name 0 0 4  
lisi
NOT_STORED
  • replace:替换数据;如果数据不存在,则替换失败,响应NOT_STORED
语法:
replace key flags exptime bytes [noreply]
value

案例:
replace name 0 0 4
lisi
STORED
  • append: 在value后追加数据
语法:
append key flags exptime bytes [noreply]
value

案例:
append name 0 0 3
123
STORED
get name
VALUE name 0 7
lisi123
  • prepend: 在value前追加数据
语法:
prepend key flags exptime bytes [noreply]
value

案例:
prepend name 0 0 3
456
STORED
get name 
VALUE name 0 10
456lisi123
  • delete:删除已存在的 key,响应DELETE表示删除成功
语法:
delete key [noreply]

案例:
delete name
DELETED
  • flush_all:清理缓存中的所有key-value

  • 实际业务中禁止使用!如果执行,可能会造成所有缓存清空不存在,所有的数据请求都直接到了数据库服务器,造成数据库压力瞬间变,可能会导致 数据库宕机

语法:
flush_all [time] [noreply]

参数说明:
time	设置执行清理缓存的时间,默认立即清理缓存

案例:
flush_all
OK
get age
END
  • incr:对已存在的 key 的value(十进制的32位无符号整数)进行自增
语法:
incr key value

案例:
incr age 1
21
incr age 10
31
  • decr:对已存在的 key 的value(十进制的32位无符号整数)进行自减
语法:
incr key value

案例:
decr age 5
26
decr age 10
16
  • get:通过key获取value;如果 key 不存在,则返回空
语法:
get key1 key2 key3

案例:
get name age
VALUE name 0 8
zhangsan
VALUE age 0 2
20
  • gets:获取带有 CAS 令牌存的 value(数据值),如果 key 不存在,则返回空
语法:
gets key1 key2 key3

案例:
gets name age 
VALUE name 0 8 7
zhangsan
VALUE age 0 2 12
16
END
  • stats:返回系统信息,例如 PID(进程号)、版本号、连接数
语法:
stats

案例:
stats
STAT pid 3661					memcache进程ID
STAT uptime 18059				服务器已运行秒数
STAT time 1634849584			服务器当前Unix时间戳
STAT version 1.5.8				版本
STAT libevent 1.4.13-stable
STAT pointer_size 64			操作系统指针大小
STAT rusage_user 2.779577		进程累计用户时间
STAT rusage_system 1.628752		进程累计系统时间
STAT max_connections 1024		最大连接数
STAT curr_connections 2			当前连接数
STAT total_connections 4		Memcached运行以来连接总数
STAT rejected_connections 0
STAT connection_structures 3	Memcached分配的连接结构数量
STAT reserved_fds 20
STAT cmd_get 8					get命令请求次数
STAT cmd_set 8					
STAT cmd_flush 1
STAT cmd_touch 0
STAT get_hits 6					get命令命中次数
STAT get_misses 2				get命令未命中次数
STAT get_expired 0
STAT get_flushed 0
STAT delete_misses 0
STAT delete_hits 1
STAT incr_misses 0
STAT incr_hits 2
STAT decr_misses 0
STAT decr_hits 2
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0			    使用擦拭次数
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0				认证命令处理的次数
STAT auth_errors 0				认证失败数目
STAT bytes_read 377				读取总字节数
STAT bytes_written 339			发送总字节数
STAT limit_maxbytes 67108864	分配的内存总大小(字节)
STAT accepting_conns 1			服务器是否达到过最大连接(0/1)
STAT listen_disabled_num 0		失效的监听数
STAT time_in_listen_disabled_us 0
STAT threads 4					当前线程数
STAT conn_yields 0				连接操作主动放弃数目
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT slab_reassign_rescues 0
STAT slab_reassign_chunk_rescues 0
STAT slab_reassign_evictions_nomem 0
STAT slab_reassign_inline_reclaim 0
STAT slab_reassign_busy_items 0
STAT slab_reassign_busy_deletes 0
STAT slab_reassign_running 0
STAT slabs_moved 0
STAT lru_crawler_running 0
STAT lru_crawler_starts 6120
STAT lru_maintainer_juggles 23105
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT bytes 135					当前存储占用的字节数
STAT curr_items 2				当前存储的数据总数
STAT total_items 7				启动以来存储的数据总数
STAT slab_global_page_pool 0
STAT expired_unfetched 1
STAT evicted_unfetched 0
STAT evicted_active 0
STAT evictions 0				LRU释放的对象数目
STAT reclaimed 1				已过期的数据条目来存储新数据的数目
STAT crawler_reclaimed 0
STAT crawler_items_checked 2
STAT lrutail_reflocked 0
STAT moves_to_cold 9
STAT moves_to_warm 2
STAT moves_within_lru 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END

扩展:

缓存命中率=命中数(get_hits)/获取次数(cmd_get)

  • 如果命中率低,可能业务代码缓存有问题;命中率为0,说明缓存没有起作用

缓存穿透

  • 访问的数据,数据库中不存在,每次都不能生成缓存。以至于每次请求都直接访问数据库,穿透了缓存,缓存没有起到作用,数据库压力没有得到缓解
  • 解决方案:数据库查不到的数据,做空缓存

缓存雪崩

  • 缓存具有失效时间,如果缓存失效时间都是一样,本来应该请求缓存的,但是因为缓存失效了,全部请求到了数据库,数据库压力剧增,可能会造成数据库宕机,进而造成系统崩溃。
  • 解决方案:设置缓存的失效时间均匀分布
  • stats items:显示各个 slab 中 item 的数目和存储时长(最后一次访问距离现在的秒数)
语法:
stats items

案例:
stats items
STAT items:1:number 2
STAT items:1:number_hot 0
STAT items:1:number_warm 0
STAT items:1:number_cold 2
STAT items:1:age_hot 0
STAT items:1:age_warm 0
STAT items:1:age 1703
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 1
STAT items:1:expired_unfetched 1
STAT items:1:evicted_unfetched 0
STAT items:1:evicted_active 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 4
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 9
STAT items:1:moves_to_warm 2
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 6
STAT items:1:hits_to_temp 0
END
  • stats slabs:于显示各个slab的信息,包括chunk的大小、数目、使用情况等
语法:
stats slabs

案例:
stats slabs
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 2
STAT 1:free_chunks 10920
STAT 1:free_chunks_end 0
STAT 1:mem_requested 135
STAT 1:get_hits 6
STAT 1:cmd_set 8
STAT 1:delete_hits 1
STAT 1:incr_hits 2
STAT 1:decr_hits 2
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT 1:touch_hits 0
STAT active_slabs 1
STAT total_malloced 1048576
END
  • stats sizes :显示所有item的大小和个数,大小在前,个数在后
语法:
stats sizes

案例:
stats sizes
STAT 96 1
END

动态监控memcached

  • 基于Memcached_tool.php工具

  • 该软件,可以查看memcached运行状态、key(item)的数量、内存使用量等

  • 需要PHP的运行环境

  • 在web服务器上配置

传入memcached_tool.php工具
cd /usr/local/nginx/html/
rz 

配置
[root@web1 html]# vim memcached_tool.php 

 22 define('ADMIN_USERNAME','root');    // Admin Username
 23 define('ADMIN_PASSWORD','123456');      // Admin Password
 24 define('DATE_FORMAT','Y/m/d H:i:s');
 25 define('GRAPH_SIZE',200);
 26 define('MAX_ITEM_DUMP',50);
 27 
 28 $MEMCACHE_SERVERS[] = '192.168.139.135:11211'; // add more as an array

  • 浏览器访问

在这里插入图片描述

PHP连接Memcached

  • PHP连接memcached需要事先安装相应的扩展类库

  • 官方扩展地址http://pecl.php.net/

  • memcached-3.1.3.tgz php的扩展,依赖libmemcached1.x以上版本。yum 本地源的 libmemcached依赖版本太低,不能够满足php扩展的依赖需要,需要手动源码编译

  • 安装

上传源码包
rz
rz
ls
	memcached-3.1.3.tgz
	libmemcached-1.0.18.tar.gz	依赖
tar -xzf memcached-3.1.3.tgz 
tar -xzf libmemcached-1.0.18.tar.gz
cd libmemcached-1.0.18
./configure --prefix=/usr/local/libmemcached && make && make install
cd ../memcached-3.1.3

扩展源码包和php关联生成configure文件
phpize
#如果执行找不到phpize,说明之前没有给php安装目录bin目录配置环境变量,重新配置即可

安装
./configure --with-libmemcached-dir=/usr/local/libmemcached --disable-memcached-sasl
make && make install

修改php.ini文件
vim /usr/local/php/etc/php.ini
 #添加extension=memcached.so(860行左右)
 
重启php-frm服务
service php-fpm reload
php -m |grep memcached

在这里插入图片描述

  • 测试
cd /usr/local/nginx/html/
vim text_memcached.php
------------------------------------
<?php
//实例化类
$mem = new memcached();
//调用连接memcached方法 注意连接地址和端口号
$mem->addServer('192.168.17.107',11211);
//存数据
var_dump($mem->set('name','lnmp'));
//取数据
var_dump($mem->get('name'));
----------------------------------

在这里插入图片描述

常用案列

session共享

  • session不共享问题:分布式负载均衡架构中,web服务器间的session不共享(默认session存储在本地的文件中),会造成session校验不一致,校验验证码不通过,造成无法判断是否登录
  • 解决方法:
    • session生成校验在同一台服务器
    • session共享,多台web服务器可以调用到session
  • 开启nginx负载均衡

在这里插入图片描述

上述问题是因为数据库代理中间件mycat没有开启

  • session共享配置
vim /usr/local/nginx/html/tp5shop/application/config.php
-----------------------------------------------
205     'session'                => [
206         'id'             => '',
207         // SESSION_ID的提交变量,解决flash上传跨域
208         'var_session_id' => '',
209         // SESSION 前缀
210         'prefix'         => 'think',
211         // 驱动方式 支持redis memcache memcached
212         'type'           => 'memcached',
213         // 连接memcached的主机,需要自己添加
214         'host'          => '192.168.139.135,
----------------------------------------------------
service nginx reload

在memcached中,session_id作为key,session的内容作为value进行存储。

在这里插入图片描述

缓存热点数据

在这里插入图片描述

  • 修改代码文件
vim /usr/local/nginx/html/tp5shop/application/home/controller/Base.php
--------------------------------------------------------------------
 27         //查询在前台首页显示的分类
 28         if(!$category = cache('category')) {
 29             $category = Category::where('is_show', 1)->select();
 30             cache('category', $category);        
 31         }
--------------------------------------------------------------------
  • 修改项目缓存配置
vim /usr/local/nginx/html/tp5shop/application/config.php
-------------------------------------------------------
190     'cache'                  => [
191         // 驱动方式
192         'type'   => 'memcached',
193         // 缓存保存目录
194         'host'   => '192.168.139.135',
195         // 缓存前缀
196         'prefix' => '',
197         // 缓存有效期 0表示永久缓存
198         'expire' => 10,
199     ],
-------------------------------------------------------
service nginx reload
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值