xmemcached的使用


 轉載 http://www.voidcn.com/blog/u010408365/article/p-4972896.html

xmemcached主要特性

  高性能

    XMemcached同樣是基於java nio的客戶端,java nio相比於傳統阻塞io模型來說,有效率高(特別在高並發下)和資源耗費相對較少的優點。傳統阻塞IO為了提高效率,需要創建一定數量的連接形成連接池,而nio僅需要一個連接即可(當然,nio也是可以做池化處理),相對來說減少了線程創建和切換的開銷,這一點在高並發下特別明顯。

  支持完整的協議

    Xmemcached支持所有的memcached協議

  支持客戶端分布

    Memcached的分布只能通過客戶端來實現,XMemcached實現了此功能,並且提供了一致性哈希(consistent hash)算法的實現。

  允許設置節點權重

    XMemcached允許通過設置節點的權重來調節memcached的負載,設置的權重越高,該memcached節點存儲的數據將越多,所承受的負載越大。

  動態增刪節點

    XMemcached允許通過JMX或者代碼編程實現節點的動態添加或者移除,方便用戶擴展和替換節點等。

  支持JMX

    XMemcached通過JMX暴露的一些接口,支持client本身的監控和調整,允許動態設置調優參數、查看統計數據、動態增刪節點等。

  與spring集成

    鑒於很多項目已經使用Spring作為IOC容器,因此XMemcached也提供了對Spring框架的集成支持。Hibernate-memcached是一個允許將memcached作為hibernate的二級緩存的開源項目,默認是使用Spymemcached,Xmemcached提供了對這個項目的支持,允許替換Spymemcached.

  客戶端連接池

    剛才已經提到java nio通常對一個memcached節點使用一個連接,而XMemcached同樣提供了設置連接池的功能,對同一個memcached可以創建N個連接組成連接池來提高客戶端在高並發環境下的表現,而這一切對使用者來說卻是透明的。啟用連接池的前提條件是保證數據之間的獨立性或者數據更新的同步,對同一個節點的各個連接之間是沒有做更新同步的,因此應用需要保證數據之間是相互獨立的或者全部采用CAS更新來保證原子性。

如果你使用maven

 <dependency>
       <groupId>com.googlecode.xmemcached</groupId>
       <artifactId>xmemcached</artifactId>
       <version>{版本號}</version>
  </dependency>

簡單例子

對於用戶來說,最主要的功能是存取數據,假設我們有一個memcached節點IP地址或者域名是host,端口是11211,一個簡單的存取數據的例子如下:

MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:11211"));
        MemcachedClient memcachedClient = builder.build();
        try {
            memcachedClient.set("hello", 0, "Hello,xmemcached");
            String value = memcachedClient.get("hello");
            System.out.println("hello=" + value);
            memcachedClient.delete("hello");
            value = memcachedClient.get("hello");
            System.out.println("hello=" + value);
        } catch (MemcachedException e) {
            System.err.println("MemcachedClient operation fail");
            e.printStackTrace();
        } catch (TimeoutException e) {
            System.err.println("MemcachedClient operation timeout");
            e.printStackTrace();
        } catch (InterruptedException e) {
            // ignore
        }
        try {
            //close memcached client
            memcachedClient.shutdown();
        } catch (IOException e) {
            System.err.println("Shutdown MemcachedClient fail");
            e.printStackTrace();
        }

存儲數據是通過set方法,它有三個參數,第一個是存儲的key名稱,第二個是expire時間(單位秒),超過這個時間,memcached將這個數據替換出去,0表示永久存儲(默認是一個月),第三個參數就是實際存儲的數據,可以是任意的java可序列化類型。獲取存儲的數據是通過get方法,傳入key名稱即可。如果要刪除存儲的數據,這是通過delete方法,它也是接受key名稱作為參數。XMemcached由於是基於nio,因此通訊過程本身是異步的,client發送一個請求給memcached,你是無法確定memcached什么時候返回這個應答,客戶端此時只有等待,因此還有個等待超時的概念在這里。客戶端在發送請求后,開始等待應答,如果超過一定時間就認為操作失敗,這個等待時間默認是5秒(1.3.8開始改為5秒,之前是1秒),上面例子展現的3個方法調用的都是默認的超時時間,這三個方法同樣有允許傳入超時時間的重載方法,例如

  value=client.get(“hello”,3000);

就是等待3秒超時,如果3秒超時就跑出TimeutException,用戶需要自己處理這個異常。因為等待是通過調用CountDownLatch.await(timeout)方法,因此用戶還需要處理中斷異常InterruptException。最后的MemcachedException表示Xmemcached內部發生的異常,如解碼編碼錯誤、網絡斷開等等異常情況。

touch更新數據超時時間

經常有這樣的需求,就是希望更新緩存數據的超時時間(expire time),在沒有touch協議之前,你需要整體的get-set一次:

    value=client.get("a");
    client.set("a",new-expire-time,value);

兩次操作,加上value的序列化/反序列化、網絡傳輸,這個開銷可不小。幸好,現在memcached已經支持touch協議,只需要傳遞key就更新緩存的超時時間:

     client.touch(key,new-expire-time);

xmemcached 1.3.6開始支持二進制協議的touch命令,1.3.8開始支持文本協議的touch命令。

有時候你希望獲取緩存數據並更新超時時間,這時候可以用getAndTouch方法(僅二進制協議支持):

   client.getAndTouch(key,new-expire-time);

客戶端分布

Memcached的分布是通過客戶端實現的,客戶端根據key的哈希值得到將要存儲的memcached節點,並將對應的value存儲到相應的節點。

XMemcached同樣支持客戶端的分布策略,默認分布的策略是按照key的哈希值模以連接數得到的余數,對應的連接就是將要存儲的節點。如果使用默認的分布策略,你不需要做任何配置或者編程。

XMemcached同樣支持一致性哈希(consistent hash),通過編程設置:

 

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil
                                .getAddresses(properties.getProperty("test.memcached.servers"))
        builder.setSessionLocator(new KetamaMemcachedSessionLocator());
        MemcachedClient client=builder.build();

XMemcached還提供了額外的一種哈希算法——選舉散列,在某些場景下可以替代一致性哈希

  MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                                        AddrUtil.getAddresses("server1:11211 server2:11211 server3:11211"));
  builder.setSessionLocator(new ElectionMemcachedSessionLocator());
  MemcachedClient mc = builder.build();

CAS操作

Memcached是通過cas協議實現原子更新,所謂原子更新就是compare and set,原理類似樂觀鎖,每次請求存儲某個數據同時要附帶一個cas值,memcached比對這個cas值與當前存儲數據的cas值是否相等,如果相等就讓新的數據覆蓋老的數據,如果不相等就認為更新失敗,這在並發環境下特別有用。XMemcached提供了對CAS協議的支持(無論是文本協議還是二進制協議),CAS協議其實是分為兩個步驟:獲取CAS值和嘗試更新,因此一個典型的使用場景如下:

  GetsResponse<Integer> result = client.gets("a");
  long cas = result.getCas(); 
  //嘗試將a的值更新為2
  if (!client.cas("a", 0, 2, cas)) {
        System.err.println("cas error");
   }

首先通過gets方法獲取一個GetsResponse,此對象包裝了存儲的數據和cas值,然后通過cas方法嘗試原子更新,如果失敗打印”cas error”。顯然,這樣的方式很繁瑣,並且如果你想嘗試多少次原子更新就需要一個循環來包裝這一段代碼,因此XMemcached提供了一個*CASOperation*接口包裝了這部分操作,允許你嘗試N次去原子更新某個key存儲的數據,無需顯式地調用gets獲取cas值,上面的代碼簡化為:

            client.cas("a", 0, new CASOperation<Integer>() {
                public int getMaxTries() {
                    return 1;
                }

                public Integer getNewValue(long currentCAS, Integer currentValue) {
                    return 2;
                }
            });

CASOpertion接口只有兩個方法,一個是設置最大嘗試次數的getMaxTries方法,這里是嘗試一次,如果嘗試超過這個次數沒有更新成功將拋出一個TimeoutException,如果你想無限嘗試(理論上),可以將返回值設定為Integer.MAX_VALUE;另一個方法是根據當前獲得的GetsResponse來決定更新數據的getNewValue方法,如果更新成功,這個方法返回的值將存儲成功,這個方法的兩個參數是最新一次gets返回的GetsResponse結果。

更全面的例子

一些更全面的例子,展現了MemcachedClient接口的主要方法:

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                AddrUtil.getAddresses("localhost:12000"));
        MemcachedClient client = builder.build();
        client.flushAll();
        if (!client.set("hello", 0, "world")) {
            System.err.println("set error");
        }
        if (client.add("hello", 0, "dennis")) {
            System.err.println("Add error,key is existed");
        }
        if (!client.replace("hello", 0, "dennis")) {
            System.err.println("replace error");
        }
        client.append("hello", " good");
        client.prepend("hello", "hello ");
        String name = client.get("hello", new StringTranscoder());
        System.out.println(name);
        client.deleteWithNoReply("hello");

首先存儲了hello對應的world字符串,然后調用add和replace方法去嘗試添加和替換,因為數據已經存在,因此add會失敗,同樣replace在數據存在的情況才會成功,也就是將hello對應的數據更新為dennis,然后通過append和prepend方法在dennis前后加上了字符串hello和good,因此通過get返回的結果是hello dennis good。而刪除數據則是通過deleteWithNoReply方法,這個方法刪除數據並且告訴memcached不用返回應答,因此這個方法不會等待應答直接返回,特別適合於批量處理;同樣地,set、add、replace等方法也有相應的withNoReply重載版本,具體請看API文檔。

迭代所有key

Memcached本身並沒有提供迭代所有key的方法,但是通過"stats items"和"stats cachedump"統計協議可以做到迭代所有的key,這個迭代過程是低效,因此如無必要,並不推薦使用此方法。XMemcached僅提供了文本協議的迭代支持,其他協議暫未支持。

想迭代所有的key,你只需要獲取一個KeyIterator即可:

MemcachedClient client=...
KeyIterator it=client.getKeyIterator(AddrUtil.getOneAddress("localhost:11211"));
while(it.hasNext())
{
   String key=it.next();
}

Incr/Decr

下面這個例子展現了incr/decr操作的使用,兩個操作類似Java中的原子類如AtomicIntger,用於原子遞增或者遞減變量數值:

 assert(1==this.memcachedClient.incr("a", 5, 1));
 assert(6==this.memcachedClient.incr("a", 5));
 assert(10==this.memcachedClient.incr("a", 4));
 assert(9==this.memcachedClient.decr("a", 1));
 assert(7==this.memcachedClient.deccr("a", 2));

incr和decr都有三個參數的方法,第一個參數指定遞增的key名稱,第二個參數指定遞增的幅度大小,第三個參數指定當key不存在的情況下的初始值。兩個參數的重載方法省略了第三個參數,默認指定為0。

Xmemcached還提供了一個稱為計數器的封裝,它封裝了incr/decr方法,使用它就可以類似AtomicLong那樣去操作計數:

  Counter counter=client.getCounter("counter",0);
  counter.incrementAndGet();
  counter.decrementAndGet();
  counter.addAndGet(-10);

其中getCounter的第二個參數是計數器的初始值。

 

命名空間

從1.4.2開始,xmemcached提供了memcached命名空間的封裝使用,你可以將一組緩存項放到同一個命名空間下,可以讓整個命名空間下所有的緩存項同時失效,例子:

String ns = "namespace" ;
this.memcachedClient.withNamespace(ns,
                                new MemcachedClientCallable<Void>() {

                                        public Void call(MemcachedClient client)
                                                        throws MemcachedException, InterruptedException,
                                                        TimeoutException {
                                                 //a,b,c都在namespace下
                                                client.set("a",1);
                                                client.set("b",1);
                                                client.set("c",1);
                                                return null;
                                        }
                                });
//獲取命名空間內的a對應的值
Integer aValue = this.memcachedClient.withNamespace(ns,
                                new MemcachedClientCallable<Integer>() {

                                        public Integer call(MemcachedClient client)
                                                        throws MemcachedException, InterruptedException,
                                                        TimeoutException {
                                                  return client.get("a");
                                        }
                                });

//使得命名空間失效
this.memcachedClient.invalidateNamespace(ns);

查看統計信息

Memcached提供了統計協議用於查看統計信息:

   Map<InetSocketAddress,Map<String,String>> result=client.getStats();

getStats方法返回一個map,其中存儲了所有已經連接並且有效的memcached節點返回的統計信息,你也可以統計具體的項目,如統計items項目:

  Map<InetSocketAddress,Map<String,String>> result=client.getStatsByItem("items");

只要向getStatsByItem傳入需要統計的項目名稱即可。

SASL驗證

Memcached 1.4.3開始支持SASL驗證客戶端,在服務器配置啟用SASL之后,客戶端需要通過授權驗證才可以跟memcached繼續交互,否則將被拒絕請求。XMemcached 1.2.5開始支持這個特性。假設memcached設置了SASL驗證,典型地使用CRAM-MD5或者PLAIN的文本用戶名和密碼的驗證機制,假設用戶名為cacheuser,密碼為123456,那么編程的方式如下:

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                                        AddrUtil.getAddresses("localhost:11211"));
        builder.addAuthInfo(AddrUtil.getOneAddress("localhost:11211"), AuthInfo
                                        .typical("cacheuser", "123456"));
        // Must use binary protocol
        builder.setCommandFactory(new BinaryCommandFactory());
        MemcachedClient client=builder.build();

請注意,授權驗證僅支持二進制協議。

高級主題

與Spring框架集成

通過XMemcachedClientFactoryBean類,即可與spring框架集成,簡單的配置如下:

<bean name="memcachedClient" class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean" destroy-method="shutdown">
    <property name="servers">
        <value>host1:port host2:port2</value>
    </property>
</bean>

那么你就可以在需要使用MemcachedClient的地方引用這個bean.

更完整的配置例子,設置備份節點、協議類型、一致性哈希、權重、連接池大小甚至SASL驗證信息(xmemcached 1.2.5支持),具體請看注釋:

<bean name="server1" class="java.net.InetSocketAddress">
    <constructor-arg>
        <value>host1</value>
    </constructor-arg>
    <constructor-arg>
        <value>port1</value>
    </constructor-arg>
</bean>
<bean name="memcachedClient" class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean" destroy-method="shutdown">
    <property name="servers">
        <value>host1:port,host2:port host3:port,host4:port</value>
    </property>
    <!-- server's weights -->
    <property name="weights">
        <list>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </list>
    </property>
    <!-- AuthInfo map,only valid on 1.2.5 or later version -->
    <property name="authInfoMap">
        <map>
            <entry key-ref="server1">
                <bean class="net.rubyeye.xmemcached.auth.AuthInfo" factory-method="typical">
                    <constructor-arg index="0">
                        <value>cacheuser</value>
                    </constructor-arg>
                    <constructor-arg index="1">
                        <value>123456</value>
                    </constructor-arg>
                </bean>
            </entry>
        </map>
    </property>
    <!-- nio connection pool size -->
    <property name="connectionPoolSize" value="2"></property>
    <!-- Use binary protocol,default is TextCommandFactory -->
    <property name="commandFactory">
        <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory"></bean>
    </property>
    <!-- Distributed strategy -->
    <property name="sessionLocator">
        <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
    </property>
    <!-- Serializing transcoder -->
    <property name="transcoder">
        <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
    </property>
    <!-- ByteBuffer allocator -->
    <property name="bufferAllocator">
        <bean class="net.rubyeye.xmemcached.buffer.SimpleBufferAllocator"></bean>
    </property>
    <!-- Failure mode -->
    <property name="failureMode" value="false" />
</bean>

例子

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="memcachedFactory"
        class="com.comall.cybershop.cache.xmemcached.XMemcachedClient">
        <property name="xmemcachedClientMap">
            <map>
                <entry key="productMemcachedClient" value-ref="productMemcachedClient"></entry>
                <entry key="basicMemcachedClient" value-ref="basicMemcachedClient"></entry>
            </map>
        </property>
    </bean>
    
    <bean id="configuration"
        class="com.google.code.yanf4j.config.Configuration">
        <property name="sessionReadBufferSize" value="131072"/>
        <property name="readThreadCount" value="0"/>
        <property name="sessionIdleTimeout" value="5000"/>  
        <property name="writeThreadCount" value="0"/>
        <!--Socket SO_TIMEOUT 單位:毫秒  -->
        <property name="soTimeout" value="6000"/>
    </bean>
    
    <!-- product -->
    <bean name="productMemcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">
        <!-- 緩存服務器地址和端口 -->
        <constructor-arg>
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${memcached.product.address1}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${memcached.product.port1}</value>
                    </constructor-arg>
                </bean>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${memcached.product.address2}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${memcached.product.port2}</value>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
        <!-- 對應的節點的權重 -->
        <constructor-arg>
            <list>
                <value>1</value>
                <value>1</value>
            </list>
        </constructor-arg>
        <!-- 授權驗證信息 -->
        <!-- 
        <property name="authInfoMap">
            <map>
                <entry key-ref="server1">
                    <bean class="net.rubyeye.xmemcached.auth.AuthInfo"
                        factory-method="typical">
                        <constructor-arg index="0">
                            <value>cacheuser</value>
                        </constructor-arg>
                        <constructor-arg index="1">
                            <value>123456</value>
                        </constructor-arg>
                    </bean>
                </entry>
            </map>
        </property>
         -->
        <!-- 連接數 -->
        <property name="connectionPoolSize" value="1"></property>
        <!-- 協議工廠,net.rubyeye.xmemcached.command.BinaryCommandFactory,TextCommandFactory(默認),KestrelCommandFactory -->
        <property name="commandFactory">
            <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory"></bean>
        </property>
        <!-- 分布策略,一致性哈希net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator或者ArraySessionLocator(默認) -->
        <property name="sessionLocator">
            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
        </property>
        <!-- 序列化轉換器,默認使用net.rubyeye.xmemcached.transcoders.SerializingTranscoder,更多選項參見javadoc -->
        <property name="transcoder">
            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
        </property>
        <!-- IoBuffer分配器,默認為net.rubyeye.xmemcached.buffer.SimpleBufferAllocator,可選CachedBufferAllocator(不推薦) -->
        <property name="bufferAllocator">
            <bean class="net.rubyeye.xmemcached.buffer.SimpleBufferAllocator"></bean>
        </property>
        <!-- 是否啟用failure模式,true為啟用,默認不啟用 -->
        <property name="failureMode" value="false"/>
        <!-- 配置 -->
        <property name="configuration">
            <ref bean="configuration" />
        </property>
    </bean>
    <!-- Use factory bean to build memcached client -->
    <bean name="productMemcachedClient" factory-bean="productMemcachedClientBuilder"
        factory-method="build" destroy-method="shutdown" />
    
    <!-- order -->
    <bean name="basicMemcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">
        <!-- 緩存服務器地址和端口 -->
        <constructor-arg>
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${memcached.basic.address1}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${memcached.basic.port1}</value>
                    </constructor-arg>
                </bean>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${memcached.basic.address2}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${memcached.basic.port2}</value>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
        <!-- 對應的節點的權重 -->
        <constructor-arg>
            <list>
                <value>1</value>
                <value>2</value>
            </list>
        </constructor-arg>
        <!-- 授權驗證信息 -->
        <!-- 連接數 -->
        <property name="connectionPoolSize" value="1"></property>
        <!-- 協議工廠,net.rubyeye.xmemcached.command.BinaryCommandFactory,TextCommandFactory(默認),KestrelCommandFactory -->
        <property name="commandFactory">
            <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory"></bean>
        </property>
        <!-- 分布策略,一致性哈希net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator或者ArraySessionLocator(默認) -->
        <property name="sessionLocator">
            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
        </property>
        <!-- 序列化轉換器,默認使用net.rubyeye.xmemcached.transcoders.SerializingTranscoder,更多選項參見javadoc -->
        <property name="transcoder">
            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
        </property>
        <!-- IoBuffer分配器,默認為net.rubyeye.xmemcached.buffer.SimpleBufferAllocator,可選CachedBufferAllocator(不推薦) -->
        <property name="bufferAllocator">
            <bean class="net.rubyeye.xmemcached.buffer.SimpleBufferAllocator"></bean>
        </property>
        <!-- 是否啟用failure模式,true為啟用,默認不啟用 -->
        <property name="failureMode" value="false"/>
        <!-- 配置 -->
       <property name="configuration">
            <ref bean="configuration" />
        </property>
    </bean>
    <!-- Use factory bean to build memcached client -->
    <bean name="basicMemcachedClient" factory-bean="basicMemcachedClientBuilder"
        factory-method="build" destroy-method="shutdown" />
</beans>

配置選項參數表:

屬性名
servers memcached節點列表,形如“主節點1:port,備份節點1:port 主節點2:port,備份節點2:port“的字符串,可以不設置備份節點,主備節點逗號隔開,不同分組空格隔開。
weights 與servers對應的節點的權重
authInfoMap 授權驗證信息,僅在xmemcached 1.2.5及以上版本有效
connectionPoolSize nio連接池大小,默認為1
commandFactory 協議工廠,net.rubyeye.xmemcached.command.BinaryCommandFactory,TextCommandFactory(默認),KestrelCommandFactory
sessionLocator 分布策略,一致性哈希net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator或者ArraySessionLocator(默認)

 

 

 

transcoder 序列化轉換器,默認使用net.rubyeye.xmemcached.transcoders.SerializingTranscoder,更多選項參見javadoc
bufferAllocator IoBuffer分配器,默認為net.rubyeye.xmemcached.buffer.SimpleBufferAllocator,可選CachedBufferAllocator(不推薦)
failureMode 是否啟用failure模式,true為啟用,默認不啟用

 

Spring 3.0和Builder配置

Spring 3.0修改了查找destroy method的方式,因此如果還是采用上面的配置來集成xmemcached話,會在啟動的時候拋出一個異常,信息類似“Couldn't find a destroy method named 'shutdown' on bean”,這種情況下xmemcached就無法正常工作,spring的IOC容器也無法正常啟動。有沒有解決辦法呢?答案是有的,暫時可以通過XmemcachedClientBuilder的工廠方法方式來創建MemcachedClient,也就是通過factory-bean加上factory-method指定的方式,一個示范配置如下:

<bean name="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">
    <!-- XMemcachedClientBuilder have two arguments.First is server list,and second is weights array. -->
    <constructor-arg>
        <list>
            <bean class="java.net.InetSocketAddress">
                <constructor-arg>
                    <value>localhost</value>
                </constructor-arg>
                <constructor-arg>
                    <value>12000</value>
                </constructor-arg>
            </bean>
            <bean class="java.net.InetSocketAddress">
                <constructor-arg>
                    <value>localhost</value>
                </constructor-arg>
                <constructor-arg>
                    <value>12001</value>
                </constructor-arg>
            </bean>
        </list>
    </constructor-arg>
    <constructor-arg>
        <list>
            <value>1</value>
            <value>2</value>
        </list>
    </constructor-arg>
    <property name="authInfoMap">
        <map>
            <entry key-ref="server1">
                <bean class="net.rubyeye.xmemcached.auth.AuthInfo" factory-method="typical">
                    <constructor-arg index="0">
                        <value>cacheuser</value>
                    </constructor-arg>
                    <constructor-arg index="1">
                        <value>123456</value>
                    </constructor-arg>
                </bean>
            </entry>
        </map>
    </property>
    <property name="connectionPoolSize" value="2"></property>
    <property name="commandFactory">
        <bean class="net.rubyeye.xmemcached.command.TextCommandFactory"></bean>
    </property>
    <property name="sessionLocator">
        <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
    </property>
    <property name="transcoder">
        <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
    </property>
</bean>
<!-- Use factory bean to build memcached client -->
<bean name="memcachedClient3" factory-bean="memcachedClientBuilder" factory-method="build" destroy-method="shutdown" />

設置節點權重

如果是通過spring配置,請看上一節,如果需要編程設置,通過下面代碼:

 MemcachedClientBuilder builder = new     
XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});
   MemcachedClient memcachedClient=builder.build();

傳入一個int數組,里面的元素就是節點對應的權重值,比如這里設置"localhost:12000"節點的權重為1,而"localhost:12001"的權重為3。注意,xmemcached的權重是通過復制連接的多個引用來實現的,比如權重為3,那么就復制3個同一個連接的引用放在集合中讓MemcachedSessionLocator查找。

改變節點權重,可以通過setServerWeight方法:

 public interface XMemcachedClientMBean{
             ....
         /**
         * Set a memcached server's weight
         * 
         * @param server
         * @param weight
         */
        public void setServerWeight(String server, int weight);
   }

使用二進制協議

如果使用spring配置,請參見與spring集成一節。

Memcached 1.4開始正式啟用二進制協議,xmemcached 1.2開始支持二進制協議,啟用這一特性也非常簡單,設置相應的CommandFactory即可:

MemcachedClientBuilder builder = new    XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});
   builder.setCommandFactory(new BinaryCommandFactory());//use binary protocol 
   MemcachedClient memcachedClient=builder.build();

默認使用的TextCommandFactory,也就是文本協議。

JMX支持

可以通過JMX查看xmemcached的狀態,在jvm啟動參數中添加:

 java -Dxmemcached.jmx.enable=true

即可通過JMX監控xmemcached狀態,xmemcached通過RMI暴露服務接口:

 service:jmx:rmi:///jndi/rmi://[host]:7077/xmemcachedServer 

你可以在jconsole中查看這些MBean。 提供的MBean包括: 

MBean 描述
net.rubyeye.xmemcached.monitor.StatisticsHandlerMBean 用於查看Client統計信息
net.rubyeye.xmemcached.impl.OptimizerMBean 用於調整性能參數
net.rubyeye.xmemcached.XMemcachedClientMBean 動態添加或者刪除節點,查看有效服務器等信息

 JMX的更多選項:

選項 描述
-Dxmemcached.rmi.port RMI端口
-Dxmemcached.rmi.name RMI服務名

 

動態添加/刪除節點

在JMX支持一節提到的JMX方式操作外,還可以通過編程方式:

    MemcachedClient client=new XMemcachedClient(AddrUtil.getAddresses("server1:11211 server2:11211"));
   //Add two new memcached nodes
   client.addServer("server3:11211 server4:11211");
   //Remove memcached servers
   client.removeServer("server1:11211 server2:11211");

Nio連接池

Xmemcached是基於java nio的client實現,默認對一個memcached節點只有一個連接,這在通常情況下已經有非常優異的表現。但是在典型的高並發環境下,nio的單連接也會遇到性能瓶頸。因此XMemcached支持設置nio的連接池,允許建立多個連接到同一個memcached節點,但是請注意,這些連接之間是不同步的,因此你的應用需要自己保證數據更新的同步,啟用連接池可以通過下面代碼:

  MemcachedClientBuilder builder = new    XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000"));

  builder.setConnectionPoolSize(5);

如果采用Spring配置,請參見與Spring集成一節。

Failure模式和standby節點

從1.3版本開始,xmemcached支持failure模式。所謂failure模式是指,當一個memcached節點down掉的時候,發往這個節點的請求將直接失敗,而不是發送給下一個有效的memcached節點。具體可以看memcached的文檔。默認不啟用failure模式,啟用failure模式可以通過下列代碼:

   MemcachedClientBuilder builder=……
   builder.setFailureMode(true);

不僅如此,xmemcached還支持主輔模式,你可以設置一個memcached的節點的備份節點,當主節點down掉的情況下,會將本來應該發往主節點的請求轉發給standby備份節點。使用備份節點的前提是啟用failure模式。備份節點設置如下:

   MemcachedClient builder=new XmemcachedClientBuilder(AddrUtil.getAddressMap("localhost:11211,localhost:11212 host2:11211,host2:11212"));

上面的例子,將localhost:11211的備份節點設置為localhost:11212,而將host2:11211的備份節點設置為host2:11212

形如“host:port,host:port"的字符串也可以使用在spring配置中,完全兼容1.3之前的格式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM