• Memcached服务器安装、配置、使用详解


    Memcached服务器安装、配置、使用详解

    我使用的是CentOS 6.4系统,安装的Memcached版本为1.4.20。这里,记录一下安装配置的过程,以及如何使用一些常用的客户端来访问Memcached存储的数据。

    安装配置

    首先,编译、安装、配置libevent库,执行如下命令:

    1
    2
    3
    4
    5
    6
    7
    wget https://github.com/downloads/libevent/libevent/libevent-1.4.14b-stable.tar.gz
    tar xvzf libevent-1.4.14b-stable.tar.gz
    ln -s /usr/local/libevent-1.4.14b-stable /usr/local/libevent
    cd /usr/local/libevent
    ./configure
    make
    make install

    然后,编译、安装、配置Memcached,执行如下命令行:

    1
    2
    3
    4
    5
    6
    wget http://www.memcached.org/files/memcached-1.4.20.tar.gz
    tar xvzf memcached-1.4.20.tar.gz
    ln -s /usr/local/memcached-1.4.20 /usr/local/memcached
    ./configure --with-libevent=/usr/local/libevent/
    make
    make install

    如果没有出错,安装成功。

    管理memcached服务

    • 启动Memcached

    一般情况下,简单地可以使用类似如下形式,启动Memcached服务:

    1
    /usr/local/bin/memcached -d -m 64 -I 20m -u root -l 192.168.4.86 -p 11211 -c 1024 -P /usr/local/memcached/memcached.pid

    上述命令行中,基于上面各个选项,以及其他一些选项的含义,说明如下表所示:

    选项 含义说明
    -d 指定memcached进程作为一个守护进程启动
    -m <num> 指定分配给memcached使用的内存,单位是MB
    -u <username> 运行memcached的用户
    -l <ip_addr> 监听的服务器IP地址,如果有多个地址的话,使用逗号分隔,格式可以为“IP地址:端口号”,例如:-l 指定192.168.0.184:19830,192.168.0.195:13542;端口号也可以通过-p选项指定
    -p <num> Memcached监听的端口,要保证该端口号未被占用
    -c <num> 设置最大运行的并发连接数,默认是1024
    -R <num> 为避免客户端饿死(starvation),对连续达到的客户端请求数设置一个限额,如果超过该设置,会选择另一个连接来处理请求,默认为20
    -k 设置锁定所有分页的内存,对于大缓存应用场景,谨慎使用该选项
    -P 保存memcached进程的pid文件
    -s <file> 指定Memcached用于监听的UNIX socket文件
    -a <perms> 设置-s选项指定的UNIX socket文件的权限
    -U <num> 指定监听UDP的端口,默认11211,0表示关闭
    -M 当内存使用超出配置值时,禁止自动清除缓存中的数据项,此时Memcached不可以,直到内存被释放
    -r 设置产生core文件大小
    -f <factor> 用于计算缓存数据项的内存块大小的乘数因子,默认是1.25
    -n 为缓存数据项的key、value、flag设置最小分配字节数,默认是48
    -C 禁用CAS
    -h 显示Memcached版本和摘要信息
    -v 输出警告和错误信息
    -vv 打印信息比-v更详细:不仅输出警告和错误信息,也输出客户端请求和响应信息
    -i 打印libevent和Memcached的licenses信息
    -t <threads> 指定用来处理请求的线程数,默认为4
    -D <char> 用于统计报告中Key前缀和ID之间的分隔符,默认是冒号“:”
    -L 尝试使用大内存分页(pages)
    -B <proto> 指定使用的协议,默认行为是自动协商(autonegotiate),可能使用的选项有auto、ascii、binary。
    -I <size> 覆盖默认的STAB页大小,默认是1M
    -F 禁用flush_all命令
    -o <options> 指定逗号分隔的选项,一般用于用于扩展或实验性质的选项
    • 停止Memcached

    可以通过Linux的如下命令查询到Memcached的进程号:

    1
    ps -ef | grep memcached

    然后杀掉Memcached服务进程:

    1
    kill -9 <PID>

    -9表示强制杀掉进程。

    Memcached启动以后,可以通过客户端来操作缓存中的数据,我们说明一些常用的客户端,及其使用方法。

    Telnet客户端

    Telnet客户端可以通过命令行的方式来监控查看Memcached服务器存储数据的情况。例如,Memcached的服务地址为192.168.4.86:11211,可以telnet到该服务端口:

    1
    telnet 192.168.4.86 11211

    如果连接成功,可以使用如下一些命令:

    • stats命令

    该命令用于显示服务器信息、统计数据等,结果示例数据(来自www.2cto.com网站),例如:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    STAT pid 22362    //memcache服务器的进程ID  www.2cto.com
    STAT uptime 1469315    //服务器已经运行的秒数
    STAT time 1339671194    //服务器当前的unix时间戳
    STAT version 1.4.9    //memcache版本
    STAT libevent 1.4.9-stable    //libevent版本
    STAT pointer_size 64    //当前操作系统的指针大小(32位系统一般是32bit,64就是64位操作系统)
    STAT rusage_user 3695.485200    //进程的累计用户时间
    STAT rusage_system 14751.273465    //进程的累计系统时间
    STAT curr_connections 69    //服务器当前存储的items数量
    STAT total_connections 855430    //从服务器启动以后存储的items总数量
    STAT connection_structures 74    //服务器分配的连接构造数
    STAT reserved_fds 20    //
    STAT cmd_get 328806688    //get命令(获取)总请求次数
    STAT cmd_set 75441133    //set命令(保存)总请求次数  www.2cto.com
    STAT cmd_flush 34    //flush命令请求次数
    STAT cmd_touch 0    //touch命令请求次数
    STAT get_hits 253547177    //总命中次数
    STAT get_misses 75259511    //总未命中次数
    STAT delete_misses 4    //delete命令未命中次数
    STAT delete_hits 565730    //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 545701515844        //总读取字节数(请求字节数)
    STAT bytes_written 1649639749866    //总发送字节数(结果字节数)
    STAT limit_maxbytes 2147483648        //分配给memcache的内存大小(字节)
    STAT accepting_conns 1            //服务器是否达到过最大连接(0/1)
    STAT listen_disabled_num 0    //失效的监听数
    STAT threads 4        //当前线程数
    STAT conn_yields 14    //连接操作主动放弃数目
    STAT hash_power_level 16    //
    STAT hash_bytes 524288
    STAT hash_is_expanding 0
    STAT expired_unfetched 30705763
    STAT evicted_unfetched 0
    STAT bytes 61380700    //当前存储占用的字节数
    STAT curr_items 28786    //当前存储的数据总数
    STAT total_items 75441133    //启动以来存储的数据总数
    STAT evictions 0    //为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)
    STAT reclaimed 39957976    //已过期的数据条目来存储新数据的数目
    END

    上面给出了各个统计项的含义说明,不再累述。
    stats命令有几个二级子项,说明如下表所示:

    命令 含义说明
    stats slabs 显示各个slab的信息,包括chunk的大小、数目、使用情况等
    stats items 显示各个slab中item的数目和最老item的年龄(最后一次访问距离现在的秒数)
    stats detail [on|off|dump] 设置或者显示详细操作记录;
    参数为on,打开详细操作记录;
    参数为off,关闭详细操作记录;
    参数为dump,显示详细操作记录(每一个键值get、set、hit、del的次数)
    stats malloc 打印内存分配信息
    stats sizes 打印缓存使用信息
    stats reset 重置统计信息

    下面的命令,我们通过表格的形式说明,如下表所示:

    命令 用法格式 含义说明 示例
    get get <key>* 用于获取缓存的数据,键为key。 get name
    VALUE name 0 7
    shirdrn
    END
    gets gets <key>* 用于获取缓存的数据,键为一组key。 gets name hobby
    VALUE name 1 7
    1234567
    VALUE hobby 0 25
    tenis basketball football
    END
    set set <key> <flags> <exptime> <bytes> [noreply] <value> 向缓存中存储数据,不管key对应的值存在与否,都设置key对应的值。 set name 0 1800 7
    shirdrn
    STORED
    get name
    VALUE name 0 7
    shirdrn
    END
    touch touch <key> <exptime> [noreply] 更新缓存中key对应的值的过期时间。 touch name 1800
    delete delete <key> [<time>] [noreply] 给定键key,删除缓存中key对应的数据。 delete name 60
    add add <key> <flags> <exptime> <bytes> [noreply] <value> 向缓存中存储数据,只有key对应的值不存在时,才会设置key对应的值。 add hobby 0 1800 10
    basketball
    STORED
    get hobby

    VALUE hobby 0 10
    basketball
    END

    replace replace <key> <flags> <exptime> <bytes> [noreply] <value> 覆盖一个已经存在Key及其对应的Value,替换一定要保证替换后的值的长度原始长度相同,否则replace失败。 get name
    VALUE name 0 7
    shirdrn
    END
    replace name 0 1800 7
    youak47
    STORED
    get name
    VALUE name 0 7
    youak47
    END
    append append <key> <flags> <exptime> <bytes> [noreply] <value> 在一个已经存在的数据值(value)上追加,是在数据值的后面追加。 get hobby
    VALUE hobby 0 10
    basketball
    END
    append hobby 0 1800 9
    football
    STORED
    get hobby
    VALUE hobby 0 19
    basketball football
    END
    prepend prepend <key> <flags> <exptime> <bytes> [noreply] <value> 在一个已经存在的数据值(value)上追加,是在数据值的前面追加。 get hobby
    VALUE hobby 0 19
    basketball football
    END
    prepend hobby 0 1800 6
    tenis
    STORED
    get hobby
    VALUE hobby 0 25
    tenis basketball football
    END
    incr incr <key> <value> [noreply] 计数命令,可以在原来已经存在的数字上进行累加求和,计算并存储新的数值。 set active_users 0 1000000 7
    1000000
    STORED
    get active_users
    VALUE active_users 0 7
    1000000
    END
    incr active_users 99
    1000099
    decr decr <key> <value> [noreply] 计数命令,可以在原来已经存在的数字上进行减法计算,计算并存储新的数值。 get active_users
    VALUE active_users 0 7
    1000099
    END
    decr active_users 3456
    996643
    flush_all flush_all [<time>] [noreply] 使缓存中的数据项失效,可选参数是在多少秒后失效。 flush_all 1800
    version version 返回Memcached服务器的版本信息。 version
    quit quit 退出telnet终端。 quit

    Java客户端

    可以使用Java语言编写代码来访问Memcached缓存。目前,可以使用的Java客户端很多,这里简单介绍几个。

    • spymemcached客户端

    示例代码,如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    package org.shirdrn.spymemcached;
     
    import net.spy.memcached.AddrUtil;
    import net.spy.memcached.BinaryConnectionFactory;
    import net.spy.memcached.MemcachedClient;
    import net.spy.memcached.internal.OperationFuture;
     
    public class TestSpymemcached {
     
         public static void main(String[] args) throws Exception {
              String address = "192.168.4.86:11211";
              MemcachedClient client = new MemcachedClient(new BinaryConnectionFactory(),
                        AddrUtil.getAddresses(address));
              
              String key = "magic_words";
              int exp = 3600;
              String o = "hello";
              // set
              OperationFuture<Boolean> setFuture = client.set(key, exp, o);
              if(setFuture.get()) {
                   // get
                   System.out.println(client.get(key));
                   
                   // append
                   client.append(key, " the world!");
                   System.out.println(client.get(key));
                   
                   // prepend
                   client.prepend(key, "Stone, ");
                   System.out.println(client.get(key));
                   
                   // replace
                   o = "This is a test for spymemcached.";
                   OperationFuture<Boolean> replaceFuture = client.replace(key, exp, o);
                   if(replaceFuture.get()) {
                        System.out.println(client.get(key));
                        
                        // delete
                        client.delete(key);
                        System.out.println(client.get(key));
                   }
              }
              
              client.shutdown();
         }
     
    }

    更多用法,可以参考后面的链接。

    • XMemcached客户端

    示例代码,如下所示:

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    024
    025
    026
    027
    028
    029
    030
    031
    032
    033
    034
    035
    036
    037
    038
    039
    040
    041
    042
    043
    044
    045
    046
    047
    048
    049
    050
    051
    052
    053
    054
    055
    056
    057
    058
    059
    060
    061
    062
    063
    064
    065
    066
    067
    068
    069
    070
    071
    072
    073
    074
    075
    076
    077
    078
    079
    080
    081
    082
    083
    084
    085
    086
    087
    088
    089
    090
    091
    092
    093
    094
    095
    096
    097
    098
    099
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    package org.shirdrn.xmemcached;
     
    import java.io.File;
    import java.io.IOException;
    import java.io.Serializable;
    import java.net.InetSocketAddress;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeoutException;
    import java.util.concurrent.atomic.AtomicLong;
     
    import net.rubyeye.xmemcached.CASOperation;
    import net.rubyeye.xmemcached.GetsResponse;
    import net.rubyeye.xmemcached.MemcachedClient;
    import net.rubyeye.xmemcached.XMemcachedClientBuilder;
    import net.rubyeye.xmemcached.command.BinaryCommandFactory;
    import net.rubyeye.xmemcached.exception.MemcachedException;
    import net.rubyeye.xmemcached.utils.AddrUtil;
     
    public class UsingXMemcachedClient {
     
         public static void main(String[] args) throws IOException {
              String servers = "192.168.4.86:11211";
              // build and create a client
              XMemcachedClientBuilder builder = new XMemcachedClientBuilder(
                        AddrUtil.getAddresses(servers));
              builder.setCommandFactory(new BinaryCommandFactory());
              final MemcachedClient client = builder.build();
              
              // examples using client to operate
              final String key = "ghost";
              try {
                   // add
                   client.add(key, 0, "Ghost wind blows!");
                   System.out.println("add & get: " + client.get(key));
                   
                   // append
                   client.append(key, " It's a lie.");
                   System.out.println("append & get: " + client.get(key));
                   
                   // prepend
                   client.prepend(key, "Who's said?! ");
                   System.out.println("prepend & get: " + client.get(key));
                   
                   // replace
                   client.replace(key, 0, "Everything is nothing!");
                   System.out.println("replace & get: " + client.get(key));
                   
                   // delete
                   client.delete(key);
                   System.out.println("delete & get: " + client.get(key));
                   
                   // gets
                   List<String> keys = Arrays.asList(new String[] {
                             "key1", "key2", "key3"
                   });
                   for(String k : keys) {
                        client.set(k, 3600, "v:" + System.nanoTime());
                   }
                   Map<String, GetsResponse<Object>> values = client.gets(keys);
                   for(Map.Entry<String, GetsResponse<Object>> entry : values.entrySet()) {
                        System.out.println("key=" + entry.getKey() + ", value=" + entry.getValue().getValue());
                   }
                   
                   // cas
                   final AtomicLong seq = new AtomicLong(System.nanoTime());
                   ExecutorService pool = Executors.newCachedThreadPool();
                   for(int i=0; i<10; i++) {
                        pool.execute(new Runnable() {
                             @Override
                             public void run() {
                                  while(true) {
                                       CacheResult o = new CacheResult();
                                       o.file = new File("/opt/status/servers.lst");
                                       o.lastmodified = seq.incrementAndGet();
                                       System.out.println("#" + Thread.currentThread().getId() + "=>o: " + o);
                                       try {
                                            client.set(key, 0, o);
                                            Thread.sleep(100);
                                       } catch (TimeoutException e) {
                                            // TODO Auto-generated catch block
                                            e.printStackTrace();
                                       } catch (InterruptedException e) {
                                            // TODO Auto-generated catch block
                                            e.printStackTrace();
                                       } catch (MemcachedException e) {
                                            // TODO Auto-generated catch block
                                            e.printStackTrace();
                                       }
                                  }
                             }
                        });
                   }
                   Thread.sleep(3000);
                   for(int i=0; i<10; i++) {
                        client.cas(key, new CASOperation<CacheResult>() {
                             @Override
                             public int getMaxTries() {
                                  return 3;
                             }
                             @Override
                             public CacheResult getNewValue(long arg0, CacheResult result) {
                                  CacheResult old = result;
                                  CacheResult nu = new CacheResult();
                                  nu.file = old.file;
                                  nu.lastmodified = seq.incrementAndGet();
                                  System.out.println("cas: old=" + old + ", new=" + nu);
                                  return result;
                             }
                        });
                   }
                   pool.shutdown();
                   
                   // flush_all
                  client.flushAll();
                   
                   // stats
                   List<InetSocketAddress> addresses = AddrUtil.getAddresses(servers);
                   for(InetSocketAddress addr : addresses) {
                        Map<String, String> stats = client.stats(addr);
                        System.out.println(stats);
                   }
                   
              } catch (TimeoutException e) {
                   e.printStackTrace();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              } catch (MemcachedException e) {
                   e.printStackTrace();
              }
              
              synchronized(client) {
                   try {
                        client.wait();
                   } catch (InterruptedException e) {
                        e.printStackTrace();
                   }
              }
     
         }
         
         static class CacheResult implements Serializable {
              private static final long serialVersionUID = 3349686173080590047L;
              private File file;
              private long lastmodified;
              @Override
              public String toString() {
                   return "file=[" + file + ", lastmodified=" + lastmodified + "]";
              }
         }
     
    }

    Node.js客户端

    Memcached客户端代码的逻辑都非常类似,这里对Node.js简单举例说明,代码如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #!/usr/bin/env node
     
    var MemcachedClient = require('memcached');
     
    // configure memcached client
    var servers = ['192.168.4.86:11211'];
    var client = new MemcachedClient(servers);
     
    // access memcached servers
    var key = 'ghost';
     
    // set
    var value = 'Ghost wind blows!';
    client.set(key, 0, value, function(err) {
         var data = 'key=' + key + ', value=' + value;
         if(err) {
              console.error('Fail to set: ' + data);
         } else {
              console.log('Added: ' + data);
         }
    });
     
    // get
    var valueGot = client.get(key, function(err, data) {
         var dataGot = 'key=' + key + ', valueGot=' + data;
         if(err) {
                    console.error('Fail to get: ' + dataGot);
            } else {
                    console.log('Got: ' + dataGot);
            }
    });

    参考链接

  • 相关阅读:
    FileDescriptor详解
    java序列化
    ObjectInputStream和ObejctOutputStream
    ByteArrayOutputStream
    ByteArrayInputStream
    PipedInputStream/PipedOutputStream
    字节输入流
    反义
    贪婪和非贪婪
    MYSQL数据库优化
  • 原文地址:https://www.cnblogs.com/zzwx/p/8820153.html
Copyright © 2020-2023  润新知