所谓覅破解 发表于 2018-12-24 11:08:40

【Memcached】01、memcached基础



  一、缓存服务器的类型
  缓存服务器首先得有代理功能
  1、透传式缓存
      工作在真实服务器前端,用户请求先到达缓存服务器,缓存服务器中有该请求的数据并在有效期内就直接使用缓存响应给用户,如果没有或数据已过期则缓存服务器请求向后端的服务器请求该数据响应给客户,并根据协议决定是否缓存在本地,缓存服务器对于客户端是透明的。
  

  2、旁挂(旁路)式缓存
     工作在真实服务器后端,在真实服务器上要查询数据时,应用程序调用memcached的客户端|驱动首先查询memcached,如果memcached中有相应的缓存数据,取得数据并响应给用户,如果memcahed中没有相应的缓存数据则真实服务器向mysql中查询,并根据协议决定是否把查询结果缓存在memcached上。
  
  实现多个缓存服务器做互为备分,真实服务器双写,有开源软件实现这个功能。
  两个开源站点:sourceforge.net,github.com
  

  二、Memcached
  1、Memcached简介
     Memcached是一款开源、高性能、分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对Database的访问来加速web应用程序。
     它是一个基于内存的“键值对”存储,用于存储数据库调用、API调用或页面引用结果的直接数据,如字符串、对象等。
     Memcached是以LiveJournal旗下DangaInteractive 公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。
  许多Web应用都将数据保存到RDBMS(关系型数据库管理系统)中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。这时就该memcached大显身手了,通过缓存数据库查询的结果,减少对数据库访问次数,来加速Web应用程序的速度、提高可扩展性。如下图:
https://s3.运维网.com/wyfs02/M02/8E/8B/wKioL1jE2nOSMgXLAACXms9qrm4755.png
  memcached是键值缓存,数据都保存在内存中,系统重启后,缓存都将丢失,对数据没有持久存储能力。
  

  2、Memcached 特点

  memcached是一款开发工具,它既不是一个代码加速器,也不是数据库中间件。
  其设计哲学思想主要反映在如下方面:
  简单key/value存储:
  服务器不关心数据本身的意义及结构,只要是可序列化数据即可。
  存储项由“键、过期时间、可选的标志及数据”四个部分组成;
  缓存功能的实现一半依赖于客户端,一半基于服务器端:
  客户负责发送存储项至服务器端、从服务端获取数据以及无法连接至服务器时采用相应的动作;服务端负责接收、存储数据,并负责数据项的超时过期;
  各memcached服务器间彼此无视:
  不在服务器间进行数据同步
  O(1)的执行效率:
  清理超期数据:
  默认情况下,Memcached是一个LRU缓存,同时,它按事先预订的时长清理超期数据;但事实上,memcached不会删除任何已缓存数据,只是在其过期之后不再为客户所见;而且,memcached也不会真正按期限清理缓存,而仅是当get命令到达时检查其时长;
  

  Memcached的服务器与客户端通信并不使用复杂的XML等格式, 而使用简单的基于文本格式和二进制格式。因此,通过telnet也能在memcached上保存数据、取得数据。
  

  三、Memcached内存分配机制
  1、Slab Allocatior机制
      memcached默认情况下采用了名为Slab Allocaton的机制分配、管理内存。在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc()和free()来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached进程本身还慢。
  Slab Allocator就是为解决该问题而诞生的。
  Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以完全解决内存碎片问题。
  

  2、Slab Allocatior的主要术语
  page:
     分配给Slab用于切割的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk
  chunk:
     存放数据的最小单元。用户数据(key、value等)最终会保存在chunk中。
  slab class:
     特定大小的chunk的组,在memcached中,对数据的管理是以slab为单元进行管理的。每个slab class对应一个或多个空间大小相同的chunk。参考下图一:
https://s3.运维网.com/wyfs02/M01/8E/8D/wKiom1jE3wDRnvZPAAC4wEYm1fI984.jpg
  

  3、在Slab Class中缓存记录的原理
  下面说明memcached如何针对客户端发送的数据选择slab并缓存到chunk中:memcached根据收到的数据的大小,选择最适合数据大小的slab;memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。
https://s1.运维网.com/wyfs02/M02/8E/8D/wKiom1jE37Oj5NR2AABAdDzG7n4307.png
  4、Slab Allocator的缺点
  Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。
  这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。
  例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。
https://s1.运维网.com/wyfs02/M01/8E/8D/wKiom1jE39yRtIcHAAAjrurNmDI573.png
  对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案,
  The most efficient way to reducethe waste is to use a list of size classes that closely matches (if that's atall possible) common sizes of objects that the clients of this particularinstallation of memcached are likely to store.
  就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。
  但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。
  但是,我们可以通过设置growth factor(增长系数/因子)选项来调节slab class的大小的差别
  

  四、分布式缓存中负载均衡的方法
  负载均衡所使用的方法应该在调用memcached的程序或调度器上实现
  1、普通hash
  传统的数据分布方法,将key的hash值对机器数除模取余,对用户的检索关键词分词后进行hash然后对hash出的数对4(缓存服务器的个数)取模取余;余数为1则分配到服务器1上,为2分配到2上,依次类推。
  这个算法的实现非常简单,计算hash(key)/n,n为机器数,得到的值就是该key需要路由到的服务器编号了。
  优点:实现简单
  缺点:在服务器数量发生变化的时候,缓存会大量失效。
  

  2、一致性hash
  试想下如果使用传统取模算法。如果有一个key要存到缓存中,根据hash(key)/n (n表示有n台缓存服务器),可以计算出缓存所在的服务器id。这个时候有一台服务器挂掉了,剩下n-1台服务器。这时候,同样一个key,根据hash(key)/(n-1) ,这个时候就命中不了缓存了,基本所有的缓存都会失效,这个情况在线上可能是灾难性的。一致性hash可以解决部分问题。
  通常可以考虑为hash值的取值范围。我们可以把取值范围想象成一个闭环,2^32-1 和0相连接。如下图所示。
   https://s3.运维网.com/wyfs02/M01/8E/8B/wKioL1jE5b7DCs03AABqBf5Lx6c367.png


   这个时候假设我们有4个缓存服务器节点。(node1~node4)首先计算这四个服务器(名称或ID)的hash值,并且这四个点占据了闭环的四个位置,如上图所示;这个时候需要根据key来路由缓存服务器,首先计算hash(key)值对2^32 -1取余,所得到的值必能在0到2^32-1之间,然后我们可以想象这个值位于闭环的其中一个点,然后用这个hash(key)依次加一,直到命中其中一个node为止,命中的node就是key需要路由的服务器
如上图:
   需要找到key2的缓存值所在的服务器,首先计算hash(key2),落在如图的闭环中,然后顺时针找到离这个hash值最近的node,可以看到是node1。key2对应的缓存值就存在node1中。http://blog.运维网.com/e/u261/themes/default/images/spacer.gif
  如果这个时候如果增加了节点node5如下图:
http://blog.运维网.com/e/u261/themes/default/images/spacer.gifhttps://s1.运维网.com/wyfs02/M00/8E/8D/wKiom1jE59Ww8JjgAAB63zUNqNg617.png
  看下缓存失效的情况,如上图,只有hash(key)落在node4~node5之间的key才会有影响,在未增加node5之前落在这个范围的key最终路由到node1,增加node5之后路由到node5了,缓存失效了。除此之外,落在其他范围的hash值就不受影响。如上图,增加node5之后key6原来会路由到node1的,现在路由到node5。而key1不受影响,还是路由到node1。
  同理,如果少掉一个节点,还是上图为例,假如这个时候node5失效了,node5失效之前落在node4~node5之间的hash值,会路由到node5,失效之后会路由到node1,也就是原本落在node4~node5之间的hash值失效了。由此可见一致性hash能在节点变动的时候减少缓存失效的比例。
  还有一种情况,当cache的数量很少的或者缓存服务器很少的时候,会导致缓存分布不均衡。如下图所示:
https://s4.运维网.com/wyfs02/M01/8E/8B/wKioL1jE6Diwr3r2AABousKiGoc744.png
  当只有很少节点的时候,例如上图的两个,这个时候就会分配得很不均衡。这个时候引入一个叫虚拟节点的概念,原理就是增加更多的虚拟节点,让每个节点承受的压力尽量均衡。
这些增加的节点并不是真正新增的服务器节点,而是由原来的节点”复制“出来的。
例如下图,”复制“了两个新节点,node3,node4。实际上,落到node3,node4的key最终访问的服务器是node2,node1.
https://s1.运维网.com/wyfs02/M01/8E/8D/wKiom1jE6HeAqmA7AAB1Bs8leNM468.png
    这样就可以把压力尽量分配到各个机器上。另外需要维护一张表格,用来记录虚拟节点指向的真正节点。
  优点:
   相比简单的对机器数取模算法,当节点变动的时候只有相对较少的key失效,实现也相对简单。不需要进行数据迁移,每个服务器是独立的。
  缺点:
  还是会有部分的key失效,如果访问量非常大的时候,如果访问到失效的key的时候,就会直接访问到数据源上面去了,可能会导致数据源直接压挂。



  五、Memcached 过期方式
  Memcached数据过期方式:Lazy Expiration + LRU
  1、Lazy Expiration(惰性过期)
  根据缓存对象的ttl进行清理
  memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazyexpiration(惰性)。因此,memcached不会在过期监视上耗费CPU时间。
  
  2、LRU(最近最少使用算法)
  memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为 Least Recently Used(LRU)机制来分配空间。当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。可以支持禁用此功能


  六、memcached基于libevent的事件处理
  libevent是个程序库,它将Linux的poll、epool,select,BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥O(1)的性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。
  memcached 依赖于libevent API,因此要事先安装libevent,项目主页:http://libevent.org/
  可以使用yum安装libevent,也可以使用源码包编译安装。
  安装过程:
# rpm -qa|grep libevent
# ldconfig -p|grep event
libxcb-event.so.1 (libc6,x86-64) => /usr/lib64/libxcb-event.so.1
# rpm -qa|grep event
# ls libevent-2.1.8-stable.tar.gz
libevent-2.1.8-stable.tar.gz
# tar xf libevent-2.1.8-stable.tar.gz
# cd libevent-2.1.8-stable
# ./configure --prefix=/usr/local/libevent
# make && make install
# echo "/usr/local/libevent/lib" > /etc/ld.so.conf.d/libevent.conf
# ldconfig
# ldconfig -p|grep event
libxcb-event.so.1 (libc6,x86-64) => /usr/lib64/libxcb-event.so.1
libevent_pthreads-2.1.so.6 (libc6,x86-64) => /usr/local/libevent/lib/libevent_pthreads-2.1.so.6
libevent_openssl-2.1.so.6 (libc6,x86-64) => /usr/local/libevent/lib/libevent_openssl-2.1.so.6
libevent_extra-2.1.so.6 (libc6,x86-64) => /usr/local/libevent/lib/libevent_extra-2.1.so.6
libevent_core-2.1.so.6 (libc6,x86-64) => /usr/local/libevent/lib/libevent_core-2.1.so.6
libevent-2.1.so.6 (libc6,x86-64) => /usr/local/libevent/lib/libevent-2.1.so.6  

  

  七、memcached 安装
  1、直接yum安装
  CentOS6中base源中就自带Memcached,版本还很新
# yum install memcached -y   # 会自动安装好依赖的libevent
Dependencies Resolved
===================================================================================================
Package               Arch               Version                        Repository         Size
===================================================================================================
Installing:
memcached             x86_64             1.4.4-3.el6_8.1                updates            68 k
Installing for dependencies:
libevent            x86_64             1.4.13-4.el6                   base               66 k
Transaction Summary
===================================================================================================
Install       2 Package(s)

# rpm -ql memcached
/etc/rc.d/init.d/memcached
/etc/sysconfig/memcached   # 没有生成配置文件,所有的配置都在这个服务脚本的配置文件中
/usr/bin/memcached
/usr/bin/memcached-tool
/usr/share/doc/memcached-1.4.4
/usr/share/doc/memcached-1.4.4/AUTHORS
/usr/share/doc/memcached-1.4.4/CONTRIBUTORS
/usr/share/doc/memcached-1.4.4/COPYING
/usr/share/doc/memcached-1.4.4/ChangeLog
/usr/share/doc/memcached-1.4.4/NEWS
/usr/share/doc/memcached-1.4.4/README
/usr/share/doc/memcached-1.4.4/protocol.txt
/usr/share/doc/memcached-1.4.4/readme.txt
/usr/share/doc/memcached-1.4.4/threads.txt
/usr/share/man/man1/memcached.1.gz
/var/run/memcached

# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""  

  2、编译安装
# ls memcached-1.4.35.tar.gz
memcached-1.4.35.tar.gz
# tar xf memcached-1.4.35.tar.gz
# cd memcached-1.4.35
# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
# make && make install
# cd /usr/local/memcached/
# ls
binincludeshare
# ls bin
memcached
# ls include/memcached/
protocol_binary.h  后续配置:
# echo "PATH=$PATH:/usr/local/memcached/bin" > /etc/profile.d/memcached.conf
# . /etc/profile.d/memcached.conf
# ln -sv /usr/local/memcached/include/memcached/ /usr/local/include/memcached`/usr/local/include/memcached' -> `/usr/local/memcached/include/memcached/'
# ls /usr/local/include/memcached
protocol_binary.h  

  八、memcached的配置

  1、memcached常用选项
         -p      TCP监听端口 (default: 11211),小写
             -U      UDP 监听端口 (default: 11211, 0 is off),大写
            -s       UNIX socket监听路径,不支持网络
            -a       UNIX socket访问掩码, 八进制(default: 0700)
             -l      监听的服务器IP地址 (default: all addresses)
            -d      运行为守护进程
         -r         最大限度利用核心文件限制
         -u         运行memcached用户
         -m N      最大的内存使用 (default: 64 MB),也不宜过大(因为memcached只能缓存单一大小为1M以下的对象)
      -M         内存耗尽返回错误,而不是删除缓存对象,
         -c         最大并发连接 (default: 1024)
          -k            锁定所有分页内存
      -v          输出警告和错误信息
               -vv             同时打印客户端请求和返回信息
            -vvv            打印内部状态转换信息
         -i            打印memcached 和 libevent 版本信息
         -P            设置保存pid文件, only used with -d option
   -f             指定增长因子|倍数 (default: 1.25)
    -n            key+value+flags最小分配空间(default: 48),就是chunk的最小值
   -L               尝试使用大内存页。增加内存页大小可以减少失误的TLB数量,提高性能。
    -D               指定key和IDs的分隔符 defaultis “:” (colon). 如果指定此选项,统计信息收集自动开启;
      -t               使用的线程数量 (default: 4)
       -R                  每个事件的最大请求数 (default: 20)
   -b               设置积压队列数限制 (default: 1024)、
    -B               绑定协议 – one of ascii, binary, or auto (default)
    -I                分配给每个slab页(default: 1mb, min: 1k, max: 128m)
   -o                配置额外选项


2、启动memcached
# memcached
can't run as root without the -u switch
# useradd -r -s /sbin/nologin memcached
# memcached -u memcached
       # 没有使用-d选项,将阻塞在前台
# ss -tuan|grep 11211
udp    UNCONN   0      0                      *:11211               *:*   
udp    UNCONN   0      0                     :::11211                :::*   
tcp    LISTEN   0      128                   :::11211                :::*   
tcp    LISTEN   0      128                  *:11211               *:*3、memcached的客户端工具

# memcached-tool
Usage: memcached-tool
       memcached-tool 10.0.0.5:11211 display    # shows slabs
       memcached-tool 10.0.0.5:11211            # same.(default is display)
       memcached-tool 10.0.0.5:11211 stats      # shows general stats
       memcached-tool 10.0.0.5:11211 dump       # dumps keys and values
# memcached-tool localhost
#Item_SizeMax_age   Pages   Count   Full?Evicted Evict_Time OOM

# memcached-tool 192.168.10.5 stats
#192.168.10.5:11211 Field       Value
         accepting_conns         1
               auth_cmds         0
             auth_errors         0
                   bytes         0
            bytes_read         239
         bytes_written      2996
            cas_badval         0
                cas_hits         0
            cas_misses         0
               cmd_flush         0
               cmd_get         0
               cmd_set         0
               cmd_touch         0
             conn_yields         0
   connection_structures          12
   crawler_items_checked         0
       crawler_reclaimed         0
      curr_connections          11
            curr_items         0
               decr_hits         0
             decr_misses         0
             delete_hits         0
         delete_misses         0
       evicted_unfetched         0
               evictions         0
       expired_unfetched         0
             get_expired         0
             get_flushed         0
                get_hits         0
            get_misses         0
            hash_bytes      524288
       hash_is_expanding         0
      hash_power_level          16
               incr_hits         0
             incr_misses         0
                libevent 2.1.8-stable
          limit_maxbytes    67108864
   listen_disabled_num         0
      log_watcher_sent         0
   log_watcher_skipped         0
      log_worker_dropped         0
      log_worker_written         0
       lrutail_reflocked         0
            malloc_fails         0
                     pid       46494
            pointer_size          64
               reclaimed         0
            reserved_fds          20
         rusage_system    0.055991
             rusage_user    0.076988
               threads         4
                  time1489305861
time_in_listen_disabled_us         0
       total_connections          19
             total_items         0
            touch_hits         0
            touch_misses         0
                  uptime         253
               version      1.4.35
# memcached-tool localhost dump
Dumping memcache contents
Number of buckets: 0
Number of items:因为memcached和客户端通信支持文本和二进制格式,所以我们也可以使用telnet连上memcached服务器:

# telnet 192.168.10.5 11211
Trying 192.168.10.5...
Connected to 192.168.10.5.
Escape character is '^]'.
stats               
STAT pid 8279 #进程ID
STAT uptime 8000 #服务器运行秒数
STAT time 1378284623 #服务器当前unix时间戳,秒
STAT version 1.4.15 #服务器版本
STAT libevent 2.0.21-stable #libevent版本号
STAT pointer_size 64 #操作系统指针大小(这台服务器是64位的)
STAT rusage_user 0.000999计用户时间
STAT rusage_system 0.003999 #进程累计系统时间
STAT curr_connections 10 #当前打开连接数
STAT total_connections 11 #曾打开的连接总数
STAT connection_structures 11 #服务器分配的连接结构数
STAT reserved_fds 20 #内部使用的FD数
STAT cmd_get 0 #执行get命令总数
STAT cmd_set 0 #执行set命令总数
STAT cmd_flush 0 #执行flush命令总数
STAT cmd_touch 0 #执行touch命令总数
STAT get_hits 0 #get命中次数
STAT get_misses 0 #get未命中次数
STAT delete_misses 0 #delete未命中次数
STAT delete_hits 0 #delete命中次数
STAT incr_misses 0 #incr未命中次数
STAT incr_hits 0 #incr命中次数
STAT decr_misses 0 #decr未命中次数
STAT decr_hits 0 #decr命中次数
STAT cas_misses 0 #cas未命中次数
STAT cas_hits 0 #cas命中次数
STAT cas_badval 0 #使用擦拭次数
STAT touch_hits 0 #touch命中次数
STAT touch_misses 0 #touch未命中次数
STAT auth_cmds 0 #认证处理的次数
STAT auth_errors 0 #认证失败次数
STAT bytes_read 7 #读取字节总数
STAT bytes_written 0 #写入字节总数
STAT limit_maxbytes 134217728 #现在的内存大小为128M
STAT accepting_conns 1 #目前接受的新接数
STAT listen_disabled_num 0 #失效的监听数
STAT threads 4 #当前线程数
STAT conn_yields 0 #连接操作主支放弃数目
STAT hash_power_level 16 #hash等级
STAT hash_bytes 524288 #当前hash表等级
STAT hash_is_expanding 0 #hash表扩展大小
STAT bytes 0 #当前存储占用的字节数
STAT curr_items 0 #当前存储数据总数
STAT total_items 0 #启动以来存储的数据总数
STAT expired_unfetched 0 #已过期但未获取的对象数目
STAT evicted_unfetched 0 #已驱逐但未获取的对象数目
STAT evictions 0 #LRU释放的对象数目
STAT reclaimed 0 #用已过期的数据条目来存储新数据的数目
END

  九、memcached基本命令

               Memcached提供了为数不多的几个命令来完成与服务器端的交互,这些命令基于memcached的协议实现。
  1、存储类命令
   set,add,replace,append(在一个缓存后附加内容), prepend(在一个缓存之前附加内容)
  


存储命令的格式:
   
参数说明:
操作命令:set/add/replace缓存的键值客户机使用它存储关于键值对的额外信息缓存过期时间 单位为秒 0 表示永远存储缓存值的字节数key对应的值

  add:
    addkeyname flag(修饰符) timeoutdatasize
如:
       addmykey0(表示没有修饰符) 10(生存周期或过期时间单位为秒)   12(数据大小,单位bit)


  2、获取数据类命令
   get,delete,incr/decr(自加1/自减1)
get:

    get   keyname
  

  3、统计类命令
    stats,stats items,stats slabs,statssizes
  
  4、清理命令

             flush_all
                   实际上没有立即释放项目所占用的内存,而是在随后陆续有新的项目被储存时执行(这是由memcached的懒惰检测和删除机制决定的)。flush_all 效果是它导致所有更新时间早于 flush_all 所设定时间的项目,在被执行取回命令时命令被忽略。
# telnet 192.168.10.5 11211
Trying 192.168.10.5...
Connected to 192.168.10.5.
Escape character is '^]'.
add name 0 300 7         # 这个大小得一定符合,给定的字符不能少也不能多才行
xie jun
STORED
GEt name
ERROR
get name
VALUE name 0 7
xie jun
END
add AF 0 600 3
sb
get AF
CLIENT_ERROR bad data chunk
ERROR然后在客户端可以使用memcached-tool查看:
# memcached-tool 192.168.10.5 display
#Item_SizeMax_age   Pages   Count   Full?Evicted Evict_Time OOM
1      96B       136s       1       1   yes      0      0    0
# memcached-tool 192.168.10.5 dump
Dumping memcache contents
Number of buckets: 1
Number of items: 1
Dumping bucket 1 - 1 total items
add name 0 1489307305 7
xie jun
# memcached-tool 192.168.10.5 dump > tmp.txt
Dumping memcache contents
Number of buckets: 1
Number of items: 1
Dumping bucket 1 - 1 total items
# cat tmp.txt
add name 0 1489307305 7         
xie jun
附:
   memcached 常用命令及使用说明





页: [1]
查看完整版本: 【Memcached】01、memcached基础