01 . Memcached原理,主从复制,代理,管理后台

2021-05-14 15:18:05 浏览数 (1)

Memcached简介

memcached是一个自由开源,高性能,分布式内存对象存储系统

基于内存的key-valued存储,用来存储小块的任意数据(字符串,对象)

他是一个简洁的key-value存储系统

代码语言:javascript复制
# 分为服务器和客户端两部分
# 1. 服务端: memcached
# 2. 客户端: memcache

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

Memcached特点
代码语言:javascript复制
# 1. C/S模式架构: 由C语言编写,总共2000多行代码。
# 				 协议简单: 使用的是基于文本行的协议,能通过telnet/nc直接操作Memcached服务存取数据.

# 2. 支持epoll/queue异步I/O模型: 使用libevent作为事件处理通知机制.

# 3. Key/Value键值对数据类型

# 4. 纯内存缓存,效率高

# 5. 支持分布式集群

# 6. 多进程
Memcached应用

完整缓存

代码语言:javascript复制
# 例如:京东的商品分类,就可以事先放在Memcached里,然后在对外提供数据访问,这个被称之为“数据预热”

热点缓存

代码语言:javascript复制
# 热点缓存一般是用于由用户更新的商品,例如淘宝的卖家,当卖家新增商品后,淘宝网的程序就会把商品写入数据库,然后读取写入的数据,把这部分数据,放入 Memcached中,下一次访问这个商品的请求直接从Memcached中取走了。

作为集群节点的session会话共享机制

Memcached原理
Memcached数据存储机制
代码语言:javascript复制
# 需要被缓存的数据以key/value键值对的形式保存在服务器端预分配的内存区中,每个被缓存的数据都有唯一的标识key,操作Memcached中的数据就是通过这个唯一标识的key进行的。
Memcached内存管理机制
代码语言:javascript复制
# Memcached采用了如下机制:
# 1. 采用slab内存分配机制
# 2. 采用LRU对象清除机制
# 3. 采用hash机制快速检索item

memcached是利用Slab Allocation机制来分配和管理内存的,提前将大内存分配大小为1MB若干个slab,然后针对每个slab再进行小对象填充,这个小对象称为chunk,避免大量重复的初始化和清理,减轻了内存管理器的负担。 Slab Allocation内存分配的原理是按照预先规定的大小,将分配给Memcached服务的内存预先分割成特定长度的内存块(chunk),再把尺寸相同的内存块(chunk)分成组(chunks slab class),这些内存块不会释放,可以重复利用

代码语言:javascript复制
# 小结
# 1. Memcached早期内存管理机制为malloc(动态内存分配)
# 2. lab内存分配机制可以解决内存碎片的问题
# 3. Memcached服务的内存预先分割成特定长度的内存块,称为chunk,用于缓存数据的内存空间或内存块,相当于磁盘的block,只不过磁盘的每一个block都是相等的,而chunk只有在同一个Slab Class内才是相等的。
# 4. Slab Class指特定大小(1MB)的包含多个chunk的集合或组,一个Memcached包含多个Slab Class,每个Slab Class包含多个相同大小的chunk。
# 5. Slab机制缺点:  例如,Chunk空间会有浪费(通过调优因子以及大小接近的数据放入一个MC实例)
Memcached过期机制
代码语言:javascript复制
# 不主动检测item对象是否过期,而是在get时才会检查item对象是否过期以及是否应该删除。
# 当删除item对象时,一般不释放内存空间,而是做删除标记,将指针放入slot回收插槽,下次分配的时候可以直接使用。
# 当内存空间满的时候,将会根据LRU算法把最近最少使用的item对象删除。
# 数据存入可以设定过期时间,但是数据过期后不会被立即删除,而是在get时检查item对象是否过期以及是否应该删除。
# 如果不希望系统使用LRU算法清除数据,可以用使用-M参数。
Memcached部署
结构规划
代码语言:javascript复制
# 用户名 memcached
# 用户组 memcached
# 端口 11211

# 源码包
/root/memcached-1.5.9.tar.gz

# 解压后源码
/root/memcached-1.5.9

# 编译目录
/root/

# 安装目录
/usr/local/memcached

# 工作目录
/var/sites/memcached
初始化系统环境
代码语言:javascript复制
[root@memcached-1 ~]# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core) 
[root@memcached-1 ~]# uname -r
3.10.0-514.el7.x86_64
下载Memcached依赖
代码语言:javascript复制
# 安装libevent依赖和gcc编译工具
yum -y install libevent libevent-devel gcc
添加用户和组
代码语言:javascript复制
groupadd memcached;
useradd -s /sbin/nologin -d /dev/null -M -g memcached memcached;
下载Memcached包并编译安装
代码语言:javascript复制
wget -O ./memcached-1.5.9.tar.gz http://www.memcached.org/files/memcached-1.5.9.tar.gz
tar xvf memcached-1.5.9.tar.gz
cd memcached-1.5.9
./configure --prefix=/usr/local/memcached --prefix=/usr/local/memcahced/
make && make install 
修改配置文件
代码语言:javascript复制
mkdir -p /var/sites/memcached-1.5.9/etc/
cp /root/memcached-1.5.9/scripts/memcached.sysconfig /var/sites/memcached-1.5.9/memcached

cat /var/sites/memcached-1.5.9/memcached |sed -e "s/#.*/ /g" |uniq |awk '{if (length !=0) print $0}'
 
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="127.0.0.1"
PORT="11211"
启动Memcached
代码语言:javascript复制
/usr/local/memcahced/bin/memcached -m 16m -p 11211 -d -u memcached -c 8192

# 验证启动结果
ps -ef |grep memcahced
memcach   14967      1  0 15:27 ?        00:00:00 /usr/local/memcahced/bin/memcached -m 16m -p 11211 -d -u memcached -c 8192
            
# 启动多实例Memcached
/usr/local/memcahced/bin/memcached -m 16m -p 11212 -d -u memcached -c 8192

# 启动多实例Memcached指定PID文件
memcached -m 16m -p 11211 -d -u root -c 8192 -P /var/run/11211.pid
# 此时我们可以通过kill 命令指定pid文件关闭Memcached
kill `cat /var/run/11211.pid`
加入开机自启动

把上述两个实例的启动命令放入/etc/rc.local,以便下次开机可以自启动。

代码语言:javascript复制
tail -2 /etc/rc.local
memcached -m 16m -p 11211 -d -u root -c 8192
memcached -m 16m -p 11212 -d -u root -c 8192

# 关闭可以用killall ,pkill
Memcached启动参数说明
代码语言:javascript复制
#进程与连接设置:
-d	以守护进程(daemon)方式运行服务
-u	指定运行Memcached的用户,如果当前用户为root,需要使用此参数指定用户
-l	指定Memcached进程监听的服务器IP地址,可以不设置此参数, 如果服务器有多块网卡,可用-l指定监听的某个网卡上.

-p(小写)指定Memcached服务监听TCP端口号。默认为11211
-P(大写)设置保存Memcached的pid文件($$),保存PID到指定文件

#内存相关设置:
-m	# 指定Memcached服务可以缓存数据的最大内存,默认为64MB
-M	# Memcached服务内存不够时禁止LRU,如果内存满了会报错
-n	# 为key value——flags分配的最小内存空间,默认为48字节
-f	# chunk size增长因子,默认为1.25
-L	# 启用大内存页,可以降低内存浪费,改进性能,视图使用最多的内存空间

#并发连接设置:
-c	# 最大的并发连接数,默认是1024
-t	
# 线程数,默认4.由于Memcached采用的是NIO,所以太多线程作用不大,
# 一般用于处理入站请求的最大线程数,仅在memcached编译时开启了支持线程才有效,
# 而linux对线程支持是非常有限的,所以不用关心了

-s # 如果只在本地通信那么可以将其监听在某个套接字上,比如mysql.scok 能够利用共享内存方式进行通信的
-S # 启用SSL认证功能

-r  # 设定最大内核大小限制
-R	# 每个event最大请求数,默认是20
-C	# 禁用CAS(可以禁止版本计数,减少开销)

#测试参数:
-v		打印较少的errors/warnings
-vv	打印非常多调试信息和错误输出到控制台
-vvv	打印极多的调试信息和错误输出,也打印内部状态转变

#其他选项可通过在命令行输入“memcached -h”命令来显示
Memcached基本操作

向Memcached中添加数据时,注意添加的数据一般为键值对的形式,例如: key1->values1, key2->values2

安装工具
代码语言:javascript复制
yum -y install nc telnet
printf配合nc向Memcached写入数据
代码语言:javascript复制
# 向memcached写入数据
printf "set key1 0 0 5rnzhou1rn" | nc 127.0.0.1 11211

# replace 更新数据
printf "replace  key1 0 0 7rnxmhrn" | nc 127.0.0.1 11211 


# 配合printf配置nc从Memcached中读取数据
printf "get key1rn" | nc 127.0.0.1 11211

# 通过printf配合nc从Memcached中删除数据
printf "delete key1rn" | nc 127.0.0.1 11211
telnet命令写入数据
代码语言:javascript复制
telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set user01 0 0 6  #写入数据,创建key,长度等
youmen #数据长度要和value一致
STORED
get user01    #浏览数据
VALUE user01 0 7
jason12
END
delete user01  #删除数据,删除的是key
DELETED
get user01   #再次浏览数据,数据被删除       
END
quit       #quit退出
Connection closed by foreign host.
Memcached命令解释
代码语言:javascript复制
# 1. set 		设置数据
# 2. get 		获取数据
# 3. delete		删除数据
# 4. replace	更新数据

# 操作Memcached 相关命令语法
             set                 key1         0            0              6                rn          benet        rn
<command name><key><flags><exptime><bytes><datablock><string><datablock>

command             # 命令参数(set、get、delete、replace)
key                 # key 用于查找缓存值,要求小于250字符,不包含空格和控制字段
flags               #  用户端用来表示数据格式数值,如json、xml、压缩等
exptime             # 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes               # 在缓存中存储的字节数
datablock    		# 文本行,以rn结尾
string              # 键值对应的缓存内容

memcached-tool

源码包内置了一个 perl 写的 scripts/memcached-tool 管理脚本,可以用来查看 Memcached 的运行状态。 注:这个脚本并不会自动安装到安装目录中,因此要使用的话要手动复制过去

代码语言:javascript复制
cd /root/memcached-1.5.9
cp /root/memcached-1.5.9/scripts/memcached-tool /usr/local/memcahced/bin/
Memcached集群及Magent缓存代理
Memcached如何处理容错的

不处理!? 在memcached节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,下面列出几种方案供您选择: 忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。 把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。 启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱(hashing chaos)。

代码语言:javascript复制
# 根据上面的说法,Memcached其中一个节点失效以后,memcached本身是没有任何策略维持失效转发的,这对于大型系统是一个无法接受的事实

举例说明

在客户端连接的部分写入多个服务器端的ip地址,客户端将会自动的把缓存数据分布的放在每个不同的机器上,如图所示:

缺陷说明

如果其中一个缓存节点的机器down机,那么客户端存入的缓存数据将会丢失一部分,就是图中红色字体描述的“Losed 33% Cache Data”,也就是说那部分数据彻底没有了!如果是用户的关键性信息那么就玩大了,如图所示:

解决方案: 采用缓存代理服务器

采用 Magent 缓存代理,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存服务器,缓存代理服务器可以连接多台Memcached机器,如下图所示,配件清单如下:

代码语言:javascript复制
# Magent代理服务器:2台,分别为 192.168.1.2:12000、192.168.1.3:12000

# Memcached主服务器:3台,分别为 192.168.1.4:11211、192.168.1.5:11211、192.168.1.6:11211 

# Memcached备服务器:2台,分别为 192.168.1.5:11211、192.168.1.6:11211

{{uploading-image-561861.png(uploading...)}}

环境
代码语言:javascript复制
# magent keepalived memcached repcache
# 1)magent:代理memcached实现负载均衡
# 2)keepalived:magent主从HA高可用
# 3)memcached:缓存对象
# 4)repcache:实现memcached单点恢复数据同步
搭建Memcached服务
代码语言:javascript复制
# 安装libevent库
wget https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz
tar -zxvf libevent-2.1.8-stable.tar.gz
cd libevent-2.1.8-stable
./configure
make && make install

ls -la /usr/local/lib |grep libevent-
lrwxrwxrwx.  1 root root      21 Jun 11 20:03 libevent-2.1.so.6 -> libevent-2.1.so.6.0.2
-rwxr-xr-x.  1 root root 1325520 Jun 11 20:03 libevent-2.1.so.6.0.2
lrwxrwxrwx.  1 root root      21 Jun 11 20:03 libevent.so -> libevent-2.1.so.6.0.2


# memcached下载地址
http://memcached.org/files/old/memcached-1.4.13.tar.gz

# memcached-repcached补丁下载地址
http://mdounin.ru/files/repcached-2.3.1-1.4.13.patch.gz

tar zxvf memcached-1.4.13.tar.gz
gzip -d repcached-2.3.1-1.4.13.patch.gz
cd memcached-1.4.13/
./configure --prefix=/usr/local/memcached-1.4.13

yum -y install patch
patch -p1 -i ../repcached-2.3.1-1.4.13.patch         #在memcached打repcached补丁
./configure --prefix=/usr/local/memcached-1.4 -enable-replication --enable-64bit
make && make install


# 添加memcached启动用户
groupadd memcache
useradd memcache -g memcache -M

# 设置环境变量
vi /etc/profile.d/memcache.sh
MEMCACHE_HOME=/usr/local/memcached-1.4
export PATH=$MEMCACHE_HOME/bin:$PATH
source /etc/profile.d/memcache.sh

# 创建memcached的pid文件存放目录
mkdir /var/run/memcached
chown memcache:memcache /var/run/memcached

# 测试repcached是否安装
ln -s /usr/local/lib/libevent-2.1.so.6 /usr/lib64/libevent-2.1.so.6
memcached -h
搭建Magent代理服务器
代码语言:javascript复制
# magent下载地址
https://code.google.com/archive/p/memagent/downloads
yum install -y glibc glibc-devel
cp /usr/lib64/libm.so /usr/lib64/libm.a
ln -s /usr/local/lib/libevent*  /usr/lib64/

# 编译生成magent文件
mkdir magent-0.6
tar -zxvf magent-0.6.tar.gz -C magent-0.6
cd magent-0.6

vi Makefile
将
CFLAGS = -Wall -g -O2 -I/usr/local/include $(M64)
改为
CFLAGS = -lrt -Wall -g -O2 -I/usr/local/include $(M64)


vi magent.c      		#在43行前加入
#ifndef SSIZE_MAX  
#define SSIZE_MAX 32767  
#endif

/sbin/ldconfig 
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
make
生成magent文件
cp magent /usr/local/bin/

magent 
# please provide -s "ip:port" argument
# memcached agent v0.6 Build-Date: Jun 11 2020 21:59:26
实现主从复制
代码语言:javascript复制
memcached -v -l 192.168.43.159 -p 11211 -umemcache
replication: listen
replication: accept

memcached -v -l 192.168.43.154 -p 11213 -umemcache -x 192.168.43.159 -X 11212
replication: connect (peer=192.168.43.159:11212)
replication: marugoto copying
replication: start

# 测试
[root@memcached-109 ~]# telnet 192.168.43.154 11213
Trying 192.168.43.154...
Connected to 192.168.43.154.
Escape character is '^]'.
set user01 0 0 7
youmen2
STORED
get user01
VALUE user01 0 7
youmen2
END
quit
Connection closed by foreign host.
[root@memcached-109 ~]# telnet 192.168.43.159 11211
Trying 192.168.43.159...
Connected to 192.168.43.159.
Escape character is '^]'.
get user01
VALUE user01 0 7
youmen2
END
实现代理
代码语言:javascript复制
magent -u memcache -n 51200 -p 11200 -s 192.168.100.3:11211 -b 192.168.100.4:11211
# magent启动时的参数:
# -u 以的身份运行
# -n 最大同时连接数,默认是4096
# -p 监听的端口,默认11211
# -s master memcached ip and port
# -b backup memcached ip and port
# -l 连接的IP地址, 默认是0.0.0.0
# 注:如果有多个master可写成magent -u memcache -n 51200 -p 11200 -s{mastar ip}:port -s{mastar ip}:port -b{backup ip}:port



# 测试
[root@memcached-117 ~]# telnet 192.168.43.209 12000
Trying 192.168.43.209...
Connected to 192.168.43.209.
Escape character is '^]'.
set user01 0 0 7
youmen1
STORED
set user02 0 0 8
youmen10
Magent工作方式
代码语言:javascript复制
magent工作方式
# 1.get操作,先到普通mem上读取;如果失败,再到备份mem上读取(即服务器失效会导致两次读,不过只是特殊情况下的处理,可以接受)
# 2.如果一次get多个key的值,会逐个执行1中的步骤
# 3.delete,incr,decr,add,set,replace,prepend,append,cas,同时操作{普通mem,备份mem}

# 写操作:先操作备份men,再操作普通mem
# 不关联两者之间操作的成功/失败

# 4.client从magent上断开,不影响magent保持与集群server的链接
# 5.建议:client和magent部署在一起,client通过127.0.0.1访问magent时,效率会更高
基于 PHP5 & JQuery 的 Memcached 管理监控工具
主要功能:
代码语言:javascript复制
# 服务器参数监控:STATS、SETTINGS、ITEMS、SLABS、SIZES实时刷新
# 服务器性能监控:GET、DELETE、INCR、DECR、CAS等常用操作命中率实时监控
# 支持数据遍历,方便对存储内容进行监视
# 支持条件查询,筛选出满足条件的KEY或VALUE
# 数组、JSON等序列化字符反序列显示
# 兼容memcache协议的其他服务,如Tokyo Tyrant (遍历功能除外)
# 支持服务器连接池,多服务器管理切换方便简洁
部署

下载服务安装包

代码语言:javascript复制
yum -y install wget gcc gcc-c   make php php-devel httpd libevent libevent-devel zlib-devel 


# 下载memadmin
http://www.junopen.com/memadmin
# memcache安装请看上面

安装memcached扩展

代码语言:javascript复制
tar xvf memcache-3.0.8.tgz 
cd memcache-3.0.8

phpize

./configure --enable-memcache --with-php-config=/usr/bin/php-config --with-zlib-dir 

# 由于是yum安装的php,可以使用which or find / -name php-config 查找php-config文件的位置

make && make install

使php支持memcache扩展

代码语言:javascript复制
vim /etc/php.ini 
extension_dir = "/usr/lib64/php/modules/"
; On windows:
extension = "memcache.so"
  
php -m
# 在列表中应该有memcache

部署MemAdmin

代码语言:javascript复制
tar xvf memadmin-1.0.12.tar.gz 
mv memadmin/* /var/www/html/
cat /var/www/html/config.php |head -5
<?php
if (!defined('IN_MADM')) exit();

$config['user'] = "admin"; // your username
$config['passwd'] = "admin"; // your password

# 默认密码是以上,可以自己修改

# 启动httpd
systemctl start httpd
Memcache与Memcached的区别

Memcache是一个自由和开放源代码,高性能,分配的内存对象缓存系统,用于加速动态web应用程序,减轻数据库负载,他可以应对任意多个连接,使用非阻塞的IO,由于他的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcache这个软件项目一般叫Memcache,由于命名问题,所以很多人把这个软件系统叫memcache,想叫成memcached也没问题. PHP有两个针对上述软件的PECL扩展:一个叫memcache,一个叫memcached memcache扩展是完全在PHP框架内开发的,memecached扩展是使用libmemcached的。从手册上看,memcached 会比 memcache 多几个方法,使用方式上都差不多

从上图可以看出来不同语言都有自己针对Memcache的扩展

这个内存缓存系统,PHP有两个扩展,分别是memcache和memcached扩展。而memcached和memcache的守护进程 memcached 同名,比较容易引起混淆,甚至提到memcached,有些人第一想到的是后台的守护进程,但还是有必要分析两者之前的区别 memcache是完全在PHP框架内开发的,memecached是使用libmemcached的。从手册上看,memcached 会比 memcache 多几个方法,使用方式上都差不多

0 人点赞