• 第七章 Xmemcached客户端介绍


    提示:有关于XMemcached在实际开发中的具体使用,查看"Java企业项目开发实践"系列博客的《第八章 企业项目开发--分布式缓存memcached

    注意:本文主要参考自https://code.google.com/p/xmemcached/wiki/User_Guide_zh

    1、为什么选用Xmemcached客户端

    当下常用的三种memcached Java客户端:

    • Memcached Client for Java:memcached官方提供,基于Java BIO实现
    • SpyMemcached:基于Java NIO
    • XMemcached:基于Java NIO,并发性能优于XMemcached,实际上SpyMemcached性能也很高

    三者的实验比较结果:

    http://xmemcached.googlecode.com/svn/trunk/benchmark/benchmark.html

    所以,我们选用XMemcached来实现客户端的编写。

    2、XMemcached的主要特性

    • 高性能(参照上一部分)
    • 支持客户端分布(查看文章开头链接的文章中的代码:根pom.xml+MemcachedUtil类的静态块)
    • 允许设置节点权重(XMemcached允许通过设置节点的权重来调节memcached的负载,设置的权重越高,该memcached节点存储的数据将越多,所承受的负载越大)
    • 动态增删节点(JMX或zookeeper)
    • 客户端连接池
      • 默认为1,在开发中直接使用默认值即可
      • 若要配置多个连接的连接池,需要保证:数据之间是相互独立的或者全部采用CAS更新来保证原子性。
      • 在开发中,发现配置了多个连接后,会发生死锁现象(可能是我的使用方法不对),使用多客户端也是不错的选择,且并发处理的也很好。(具体实现方式查看文章开头链接的文章)

    3、使用

    具体的实际使用查看文章头部的链接。

    3.1、常用类介绍

    说明:

    • XMemcachedClientBuilder:XMemcachedClient的构建器,通过该构建器可以配置一系列参数,常用的参数有:
      • hash算法:setSessionLocator
        • 简单求余法(默认):ArrayMemcachedSessionLocator
        • 一致性hash:KetamaMemcachedSessionLocator(true)
          • 注意:这里我配置了一个true,该参数cwNginxUpstreamConsistent用于兼容nginx-upstream-consistent,如果系统用了nginx,最好配成true
      • 序列化协议:setCommandFactory
        • 文本协议(默认):TextCommandFactory,实现了memcached的自定义文本协议
        • 二进制协议:BinaryCommandFactory,减少了文本解析的步骤,有一些方法仅支持二进制协议
      • 序列化转化器:setTranscoder(下面是序列化转换器SerializingTranscoder的一些配置参数)
        • 压缩边界值:setCompressionThreshold,默认为16k,实际使用中根据自己的数据大小来指定,我们指定为1M
        • 压缩算法:setCompressionMode,默认为GZIP,还有一种是ZIP,使用默认值就会
      • 池数量:setConnectionPoolSize,默认为1,实际中采用多客户端的方式可以代替多连接
      • failure模式:setFailureMode(true):设置为true后,当一个memcached节点down掉后,发往该节点的请求将发往备份机,若没有备份机,直接抛出异常,而不会像之前那样,把请求打向下一个节点
      • standby:主从配置
        /*
                     * 下面这样是配置主从
                     * 其中localhost:11211是主1,localhost:11212是他的从
                     * host2:11211是主2,host2:11212是他的从
                     * 
                     * 注意:使用主从配置的前提是builder.setFailureMode(true)
                     */
                    MemcachedClientBuilder builder = 
                            new XMemcachedClientBuilder(AddrUtil.getAddressMap("localhost:11211,localhost:11212 host2:11211,host2:11212"));
        
                    builder.setFailureMode(true);//设置failure模式
        View Code

    其中,两种hash算法的实现与比较、两种序列化的实现与比较、池化的注意点查看《第六章 memcached剖析

    • XMemcachedCient:所有缓存的具体操作(add/set/replace/remove/get等)都在这里
      • SanitizeKeys:当选用URL当key时,MemcachedClient会自动将URL encode后再存储,该参数默认是关闭的,若要开启,如下:
        client.setSanitizeKeys(true);//URL做key
        View Code

         

    3.2、注意点

    • 多服务器之间必须用空格隔开,用逗号不行。原因参看XMemcached转换多服务器字符串的AddrUtil.getAddress(String s)方法源代码:
       1     /**
       2      * 该方法用于将传入的"host1:port1 host2:port2 ..."
       3      * 这些众多的服务器转换为一个InetSocketAddress集合
       4      */
       5     public static List<InetSocketAddress> getAddresses(String s) {
       6         if (s == null) {
       7             throw new NullPointerException("Null host list");
       8         }
       9         if (s.trim().equals("")) {
      10             throw new IllegalArgumentException("No hosts in list:  ``" + s
      11                     + "''");
      12         }
      13         s = s.trim();
      14         ArrayList<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>();
      15 
      16         for (String hoststuff : s.split(" ")) {//这里就是多服务器为什么要用空格隔开的理由
      17             int finalColon = hoststuff.lastIndexOf(':');
      18             if (finalColon < 1) {
      19                 throw new IllegalArgumentException("Invalid server ``"
      20                         + hoststuff + "'' in list:  " + s);
      21 
      22             }
      23             String hostPart = hoststuff.substring(0, finalColon).trim();
      24             String portNum = hoststuff.substring(finalColon + 1).trim();
      25 
      26             addrs
      27                     .add(new InetSocketAddress(hostPart, Integer
      28                             .parseInt(portNum)));
      29         }
      30         assert !addrs.isEmpty() : "No addrs found";
      31         return addrs;
      32     }
      View Code
    • 缓存过期参数设置:在API的使用中,有一个缓存过期参数的设置:缓存单位是s,缓存时间最长为1个月(此时参数设为0),所以一定要注意这个时间的设置
    • 等待超时时间:XMemcached是基于Java NIO(yanf4j框架)的,客户端与服务端的通讯本身是异步的,所以MemcachedClient向memcached服务器发送一个请求后,不知道什么时候memcached服务器才能把应答返回,所以在一些需要返回应答的API中我们可以指定超时时间,客户端在这个时间内会一直等待应答,若超出这个时间,就认为操作失败了,抛出TimeoutException,当然若在这些需要返回应答的API中没有指定等待超时时间,则默认的等待超时时间是5秒。
          /**
           * Default operation timeout,if the operation is not returned in 5
           * second,throw TimeoutException.
           */
          public static final long DEFAULT_OP_TIMEOUT = 5000L;
      View Code
    • 更新缓存过期参数:XMemcached1.3.6之前,若要更新缓存超时时间,需要先缓存缓存,再设置缓存(get-set),两次操作+反序列化/序列化+网络传输,造成开销很大。1.3.6之后,
      public boolean touch(final String key, int exp)
      View Code

      速度极快。若希望获取缓存并更新缓存过期时间,该方法应该是只有二进制协议支持

      public <T> T getAndTouch(final String key, int newExp)
      View Code
    • 增加缓存
      • add:key若已存在,添加缓存失败
      • replace:key若不存在,更换缓存失败
      • set:key不管存在不存在,都成功
    • 缓存缓存所有的key:没有好方法。getKeyIterator接口将会在1.6.x以后取消
    • 命名空间:1.4.2之后,可以将一组缓存项放到同一个命名空间下,如果有这样的需求,我们直接使用redis去做了

    疑问:

    standby主从模式,当主宕机后,set和get都会从从上边操作;那么,当主没有宕机,set操作是否会同时set到主和从呢?

  • 相关阅读:
    HashMap底层实现原理及面试常见问题
    Java面试题:==运算符与equals方法的区别
    SpringBoot基础,Java配置(全注解配置)取代xml配置
    实战SpringBoot Admin
    Java Object类中toString方法的重写
    java题
    1.5 安全性测试(功能)
    1.4 容量测试
    压力测试/极限测试(可靠性)
    1.2 性能测试(效率)
  • 原文地址:https://www.cnblogs.com/java-zhao/p/5158860.html
Copyright © 2020-2023  润新知