<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        外面的陽光多么明媚,廈門空氣真好,真想去海邊走走,可惜我在上班。第一次遇到周6要上班(而非加班,是正常上班)是在廣州那家公司,每月兩個周6上班,兩個周6不用,俗稱大小周。剛開始很不習慣,后來也慢慢接受了,至少還有兩個雙休日。然而金融危機后,公司要求每周6都要上班,從那時候開始俺就堅定了要走的決心了。我很不明白為什么要求周6上班,程序員又不是計件計時的工人,不是時間花的越多,做的就越多,從很大程度上說程序員的工作是很難衡量的,一個人坐在那機器前,你很難知道他是在上網沖浪還是在寫代碼。
        管理者的邏輯仍然是傳統工業的方式來看待程序員,以為人呆在公司,他就能做更多的事情,付出的薪水才值的,然而,他們忘了,程序員這個工作是純粹的腦力工作(嗯,敲鍵盤可能要點體力),他們所做的東西依賴于他們的大腦,他們可以把代碼寫的很高效很健壯,也可以留下一堆bug和極其低效的垃圾代碼,周6可能他寫了10行代碼,接下來的一周他可能需要用3天來修改上周6寫下的那10行代碼。大腦是需要休息的,超人是有,比如我認識的幾個,可以毫無娛樂活動天天上班時下班后就是寫代碼,然而這樣的生活不是我想要的,這樣的生活也沒辦法維持多久,你得到的肯定比你失去的多,代碼之外還有好多有趣的事情。

        我現在的生活就是太緊迫了,周6下班后,匆匆忙忙往車站趕,晚上9點到家,周日或者周一早上又匆匆忙忙趕回來上班,幾乎沒有休息的時間,廈門來了兩個多月,一直想去中山路(《瘋狂的賽車》拍攝地)和鼓浪嶼瞧瞧也抽不出時間,平常下班后人都散了更是懶的動。這樣下去我懷疑自己會得抑郁癥,最近的效率感覺很低下。郁悶啊,可恨的周6上班。

    posted @ 2009-03-14 12:38 dennis 閱讀(696) | 評論 (6)編輯 收藏

        xmemcached發布1.0穩定版,下載地址這里
        相比于1.0-beta版本,這個released版本的主要改進如下:
    1、xmemcached跟yanf4j都是默認采用common-logging,你可以使用log4j,也可以默認使用jdk的日志庫。1.0添加了log4j的配置和依賴包。log4j的性能比jdk自帶的日志庫性能好多了。

    2、添加了BufferAllocator接口,用于分配ByteBufferWrapper,ByteBufferWrapper顧名思義就是ByteBuffer的包裝接口,因此BufferAllocator就是ByteBuffer的分配器,有兩個實現:SimpleBufferAllocator,直接調用ByteBuffer.allocate(capacity)方法,不做任何緩存;一個是CachedBufferAllocator,采用ThreadLocal緩存ByteBuffer,避免重復創建,如果你對mina熟悉的話,這個概念沒什么特別的。默認xmemcached采用的是SimpleBufferAllocator,你可以通過XMemcachedClient的構造方法設置想要采用的BufferAllocator:

    public XMemcachedClient(BufferAllocator allocator) throws IOException;
    //其他重載構造函數


        經過測試,采用CachedBufferAllocator并沒有帶來顯著的性能提升,需要更多測試,慎用。

    3、允許設置網絡參數,在多個memcached節點的情況下,強烈推薦將網絡層的讀線程數(處理OP_READ)設置為接近節點數(具體還是要看場景測試,因為讀線程數本質上是啟動了一個線程池來處理讀事件,太大也會影響效率):
        //XMemcachedClient的getDefaultConfiguration靜態方法,獲取默認配置
        public static Configuration getDefaultConfiguration() {
            Configuration configuration 
    = new Configuration();
            configuration.setTcpRecvBufferSize(TCP_RECV_BUFF_SIZE);
            configuration.setSessionReadBufferSize(READ_BUFF_SIZE);
            configuration.setTcpNoDelay(TCP_NO_DELAY);
            configuration.setReadThreadCount(READ_THREAD_COUNT);
            
    return configuration;
        }

        使用方法:
     Configuration conf=XMemcachedClient.getDefaultConfiguration();
      //設置讀線程數為節點數,更多設置方法請參見Configuration類                       
     conf.setReadThreadCount(5);

     XMemcachedClient mc = new XMemcachedClient(
                        conf,
    new CachedBufferAllocator());
     mc.addServer(ip1, port1);
     mc.addServer(ip2, port2);
     mc.addServer(ip3,port3);
     mc.addServer(ip4,port4);
     mc.addServer(ip5,port5);


    4、修復一系列發現的bug,如Command返回結果需要設置成原子引用、更嚴格的方法參數檢查、提示信息的友好、日志的優化、操作超時的時候取消操作等,重構部分代碼

    5、提供了javadoc文檔,這里下載。


    posted @ 2009-03-13 22:07 dennis 閱讀(1885) | 評論 (2)編輯 收藏

        memcached本身是集中式的緩存系統,要搞多節點分布,只能通過客戶端實現。memcached的分布算法一般有兩種選擇:
    1、根據hash(key)的結果,模連接數的余數決定存儲到哪個節點,也就是hash(key)% sessions.size(),這個算法簡單快速,表現良好。然而這個算法有個缺點,就是在memcached節點增加或者刪除的時候,原有的緩存數據將大規模失效,命中率大受影響,如果節點數多,緩存數據多,重建緩存的代價太高,因此有了第二個算法。
    2、Consistent Hashing,一致性哈希算法,他的查找節點過程如下:
        首先求出memcached服務器(節點)的哈希值,并將其配置到0~232的圓(continuum)上。然后用同樣的方法求出存儲數據的鍵的哈希值,并映射到圓上。然后從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器上。如果超過232仍然找不到服務器,就會保存到第一臺memcached服務器上。

        一致性哈希算法來源于P2P網絡的路由算法,更多的信息可以讀這里

        spymemcached和xmemcached都實現了一致性算法(其實我是照抄的),這里要測試下在使用一致性哈希的情況下,增加節點,看不同散列函數下命中率和數據分布的變化情況,這個測試結果對于spymemcached和xmemcached是一樣的,測試場景:
        從一篇英文小說(《黃金羅盤》前三章)進行單詞統計,并將最后的統計結果存儲到memcached,以單詞為key,以次數為value。單詞個數為3061,memcached原來節點數為10,運行在局域網內同一臺服務器上的不同端口,在存儲統計結果后,增加兩個memcached節點(也就是從10個節點增加到12個節點),統計此時的緩存命中率并查看數據的分布情況。
        結果如下表格,命中率一行表示增加節點后的命中率情況(增加前為100%),后續的行表示各個節點存儲的單詞數,CRC32_HASH表示采用CRC32散列函數,KETAMA_HASH是基于md5的散列函數也是默認情況下一致性哈希的推薦算法,FNV1_32_HASH就是FNV 32位散列函數,NATIVE_HASH就是java.lang.String.hashCode()方法返回的long取32位的結果,MYSQL_HASH是xmemcached添加的傳說來自于mysql源碼中的哈希函數。

       CRC32_HASH  KETAMA_HASH  FNV1_32_HASH  NATIVE_HASH  MYSQL_HASH
    命中率
     78.5%  83.3%  78.2%  99.89%  86.9%
     節點1  319  366  546  3596  271
     節點2  399  350  191  1  233
     節點3  413  362  491  0  665
     節點4  393  364  214  1  42
     節點5  464  403  427  1  421
     節點6  472  306  299  0  285
     節點7  283  347  123  0  635
     節點8  382  387  257  2  408
     節點9  238  341  297  0  55
     節點10  239  375  756  0  586
     范圍  200~500   300~400
     150~750  0~3600  50~650


    結果分析:

    1、命中率最高看起來是NATIVE_HASH,然而NATIVE_HASH情況下數據集中存儲在第一個節點,顯然沒有實際使用價值。為什么會集中存儲在第一個節點呢?這是由于在查找存儲的節點的過程中,會比較hash(key)和hash(節點IP地址),而在采用了NATIVE_HASH的情況下,所有連接的hash值會呈現一個遞增狀況(因為String.hashCode是乘法散列函數),如:
    192.168.0.100:12000 736402923
    192.168.0.100:12001 736402924
    192.168.0.100:12002 736402925
    192.168.0.100:12003 736402926
    如果這些值很大的會,那么單詞的hashCode()會通常小于這些值的第一個,那么查找就經常只找到第一個節點并存儲數據,當然,這里有測試的局限性,因為memcached都跑在一個臺機器上只是端口不同造成了hash(節點IP地址)的連續遞增,將分布不均勻的問題放大了。

    2、從結果上看,KETAMA_HASH維持了一個最佳平衡,在增加兩個節點后還能訪問到83.3%的單詞,并且數據分布在各個節點上的數目也相對平均,難怪作為默認散列算法。

    3、最后,單純比較下散列函數的計算效率:

    CRC32_HASH:3266
    KETAMA_HASH:7500
    FNV1_32_HASH:375
    NATIVE_HASH:187
    MYSQL_HASH:500

       NATIVE_HASH > FNV1_32_HASH > MYSQL_HASH > CRC32_HASH > KETAMA_HASH


    posted @ 2009-03-10 16:31 dennis 閱讀(7768) | 評論 (0)編輯 收藏

       xmemcached發布1.0-beta,從0.60直接到1.0-beta,主要改進如下:
    1、支持更多協議,在已有協議支持的基礎上添加了append、prepend、gets、批量gets、cas協議的支持,具體請查看XMemcachedClient類的實例方法。重點是cas操作,下文將詳細描述下。
    2、memcached分布支持,支持連接多個memcached server,支持簡單的余數分布和一致性哈希分布。
    3、0.60版本以來的bug修復。

       memcached 1.2.4之后開始支持cas協議,該協議存儲數據同時發送一個版本號,只有當這個版本號與memcached server上該key的最新版本一致時才更新成功,否則返回EXISTS,版本號的獲取需要通過gets協議獲得,cas全稱就是compare and set,如果對hibernate樂觀鎖和java.util.concurrent.atomic包都比較熟悉的話這個概念應該很了解了。xmemcached 1.0-beta開始支持cas協議,看例子:
    XMemcachedClient client = new XMemcachedClient();
    client.addServer(
    "localhost",11211);
    client.set(
    "a"01); //設置a為1
    GetsResponse result = client.gets("a");
    long cas = result.getCas(); //獲取當前cas
    //嘗試更新a成2
    if (!client.cas("a"02, cas)) 
        System.err.println(
    "cas error");

        XMemcachedClient.cas(final String key, final int exp, Object value, long cas)將嘗試更新key的值到value,如果失敗就返回false。這樣搞好像很麻煩,需要先gets獲取cas值,然后再調用cas方法更新,因此XMemcached提供了一個包裝類可以幫你搞定這兩步,并且提供重試機制:

                 /**
                 * 合并gets和cas,利用CASOperation
                 
    */
                client.cas(
    "a"0new CASOperation() {

                    @Override
                    
    public int getMaxTries() {
                        
    return 10;
                    }

                    @Override
                    
    public Object getNewValue(long currentCAS, Object currentValue) {
                        System.out.println(
    "current value " + currentValue);
                        
    return 2;
                    }

                });
        通過CASOperation,你只要實現兩個方法即可,getMaxTries返回最大重試次數,超過這個次數還沒有更新成功就拋出TimeoutException;getNewValue方法返回依據當前cas和緩存值,你希望設置的更新值。看一個cas更詳細的例子,開100個線程遞增緩沖中的變量a,采用cas才能保證最后a會等于100:

    import java.util.concurrent.CountDownLatch;

    import net.rubyeye.xmemcached.CASOperation;
    import net.rubyeye.xmemcached.XMemcachedClient;
    /**
     * 測試CAS
     * 
    @author dennis
     
    */
    class CASThread extends Thread {
        
    private XMemcachedClient mc;
        
    private CountDownLatch cd;

        
    public CASThread(XMemcachedClient mc, CountDownLatch cdl) {
            
    super();
            
    this.mc = mc;
            
    this.cd = cdl;

        }

        
    public void run() {
            
    try {
                
    if (mc.cas("a"0new CASOperation() {
                    @Override
                    
    public int getMaxTries() {
                        
    return 50;
                    }

                    @Override
                    
    public Object getNewValue(long currentCAS, Object currentValue) {
                        System.out.println(
    "currentValue=" + currentValue
                                
    + ",currentCAS=" + currentCAS);
                        
    return ((Integer) currentValue).intValue() + 1;
                    }

                }))
                    
    this.cd.countDown();
            } 
    catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public class CASTest {
        
    static int NUM = 100;

        
    public static void main(String[] args) throws Exception {
            XMemcachedClient mc 
    = new XMemcachedClient();
            mc.addServer(
    "192.168.222.100"11211);
            
    // 設置初始值為0
            mc.set("a"00);
            CountDownLatch cdl 
    = new CountDownLatch(NUM);
            
    // 開NUM個線程遞增變量a
            for (int i = 0; i < NUM; i++)
                
    new CASThread(mc, cdl).start();

            cdl.await();
            
    // 打印結果,最后結果應該為NUM
            System.out.println("result=" + mc.get("a"));
            mc.shutdown();
        }
    }

        最高重試次數設置成了50,觀察輸出你就會知道cas沖突在高并發下非常頻繁,這個操作應當慎用。

        說完cas,我們再來看下xmemcached對分布的支持。
    1、如何添加多個memcached server?
    通過XMemcachdClient.addServer(String ip,int port)方法,
                XMemcachedClient mc = new XMemcachedClient();
                mc.addServer(ip1, port1);
                mc.addServer(ip2, port2);
                mc.addServer(ip3, port3);
                mc.addServer(ip4, port3);

    2、怎么分布?
    在添加了>=2個memcached server后,對XMemcachdClient的存儲、刪除等操作都將默認根據key的哈希值連接數的余數做分布,這也是spymemcached默認的分布算法。這個算法簡單快速,然而在添加或者移除memcached server后,緩存會大面積失效需要重組,這個代價太高,因此還有所謂Consistent Hashing算法,通過將memcached節點分布在一個0-2^128-1的環上,發送數據到某個節點經過的跳躍次數可以縮減到O(lgn)次,并且在添加或者移除節點時最大限度的降低影響,這個算法的思想其實來源于p2p網絡的路由算法,不過路由算法比這個復雜多了,畢竟memcached的分布是在客戶端,因此不需要節點之間的通訊和路由表的存儲更新等。這個算法在java上的實現可以通過TreeMap紅黑樹,具體可以參考這里這里
      在xmemcached啟動Consistent Hashing如下:

    XMemcachedClient client = new XMemcachedClient(new KetamaMemcachedSessionLocator(HashAlgorithm.CRC32_HASH));
    client.addServer(ip, 
    12000);
    client.addServer(ip, 
    12001);
    client.addServer(ip, 
    11211);
    client.addServer(ip, 
    12003);
    client.addServer(ip, 
    12004);

      散列函數采用CRC32,你也可以采用其他散列函數,具體看場景測試而定,散列函數決定了你的查找節點效率和緩存重新分布的均衡程度。
     
      在完成1.0-beta這個里程碑版本后,xmemcached將集中于穩定性方面的測試和性能優化。歡迎提交測試報告和建議,我的email killme2008@gmail.com





    posted @ 2009-03-09 15:32 dennis 閱讀(1938) | 評論 (1)編輯 收藏

        翠花,上圖,首先是容器類和自定義對象的get、set在不同并發下的表現





        很明顯,在linux下,spymemcached讀寫復雜對象的效率遠遠超過在windows下的表現,xmemcached在兩個平臺之間表現平穩,在linux上get效率低于spymemcached,差距比較大,準備再優化下;set效率略高于spymemcached。

        xmemcached  0.70將支持多服務器功能和簡單的分布能力,基于hash key后模節點數的余數值做分布,這也是spymemcached默認的分布方式,一致性哈希暫不實現。下面是在linux下多節點情況下讀寫簡單類型的效率對比





       兩者都是在從一個節點到兩個節點的變化中效率有一個顯著下降,在2個節點到更多節點過程中下降的幅度開始減小,曲線變的相對平穩。

    xmemcached路線圖
    0.70  多服務器和簡單分布
    0.80  更多memcached協議支持
    0.90  一致性哈希算法的實現


    posted @ 2009-03-07 10:43 dennis 閱讀(1722) | 評論 (1)編輯 收藏


       充分利用jprofile等工具觀察性能瓶頸,才能對癥下藥,盲目的優化只是在浪費時間,并且效果可能恰恰相反
    1、 觀察到CountDownLatch.await占據最多CPU時間,一開始認為是由于jprofiler帶來的影響,導致這個方法調用時間過長,從而忽 略了這一點,導致后面走了不少彎路。實際上await方法占用50%的CPU,而網絡層和序列化開銷卻比較低,這恰恰說明這兩者的效率低下,沒辦法充分利 用CPU時間,后來觀察spymemcached的CPU占用情況,await占用的時間低于30%,優化后的結果也是如此。

    2、因為沒有深入理解這一點,我就盲目地開始優化,先從優化協議匹配算法開始,匹配ByteBuffer一開始用簡單匹配(O(m*n)復雜 度),后來替代以KMP算法做匹配,想當然以為會更快,比較了兩者效率之后才發現KMP的實現竟然比簡單匹配慢了很多,馬上google,得知比之kmp 算法效率高上幾倍的有BM算法,馬上實現之,果然比KMP和簡單匹配都快。換了算法后,一測試,有提升,但很少,顯然這不是熱點。然后開始嘗試改線程模型并測試,一開始想的是往上加線程,畢竟序列化是計算密集型,搞cpu個數的線程去發送command,調整讀Buffer的線程數,測試效率沒有提升甚至 有所降低,期間還測試了將協議處理改成批處理模式等,全部以失敗告終。

    3、此時才想起應該觀察下spymemcached的CPU使用情況,才有了上面1點提到的觀察,記的在測試yanf4j的echo server的時候,我發現讀Buffer線程數設為0的事情下比之1的效率更高,也就是說僅啟動一個線程處理Select、OP_WRITE和 OP_READ的事件,對于echo這樣簡單的任務來說是非常高效的,難道memcached也如此?立馬設置為0并測試,果然提升很多,與 spymemcached的TPS差距一下減小了2000多,進一步觀察,由于xmemcached構建在yanf4j的基礎上,為了分層清晰導致在發送 和接收消息環節有很多冗余的操作,并且我還多啟動了一個線程做command發送和優化get、set操作,如果能磨平這些差異,擴展yanf4j,避免了隊列同步開銷,這樣也不用額外啟動線程,效率是否更高呢?得益于yanf4j的模塊化,修改工作順利進行,最后的測試結果也證明了我的猜測,效率已經接近 spymemcached甚至超過。




    posted @ 2009-03-06 14:37 dennis 閱讀(1498) | 評論 (2)編輯 收藏

    測試1:開N個線程讀寫刪各10000次,key是String,Value是Integer,數據單位皆為TPS

     線程數           set            get          delete
       xmemcached  spymemcached  xmemcached spymemcached
     xmemcached spymemcached
     1  3368  3047  3422  3232  3787  3404
     10  12307  11742  15274  12623  13473  13473
     50  22115  23021  30769  22630  24483  23222
     100  22448  25467  32569  24105  25538  28119
     200  24187  26165  35320  21379  26683  28181
     500  24623  28810  36955  14328  27609  29789




    觀察下結果,明顯的一點是xmemcached的get比之spyememcached快得多,考慮到memcached是作為緩存使用,這一點很重要。在set、delete上面仍然比spymemcached稍有不如,但是差距已經很小。



    測試2:開N個線程讀寫各100次,key是String,Value是100個元素的map(map的key和value分別是String和一個自定義類NameClass),memcached內存加大,防止lru起作用。

     線程數           set            get
       xmemcached  spymemcached  xmemcached spymemcached
     1  492  377  581  531
     10  1362  84  831  753
     30  1536  66  1015  872
     50  1608  68  1126  1084
     100  1576  67  989  1347

      
     觀察數據結果,難以理解的是spymemcached在寫集合方面竟然如此低效,通過jprofiler觀察兩者的CPU占用,最大頭的都是序列化自定義對象;不過我昨天在ubuntu下開發xmemcached的時候隨手測過,spymemcached寫集合并沒有在windows下這么慢。

        以上測試數據使用的memcached是2.2版本,xmemcached是0.6版本,系統是windows xp,AMD雙核2G內存,memcached是跑在局域網內的服務器上,版本是1.2.2。linux下的測試數據等晚上回家補上。


      



    posted @ 2009-03-06 12:36 dennis 閱讀(2035) | 評論 (0)編輯 收藏


       讀寫簡單類型
       測試方法:開N個線程 ,每個線程set(或者get、delete) 10000次,表格如下(數據為tps,僅供參考)
     線程數    spymemcached      xmemcached  
       set  get delete
    set
     get  delete
     1  2870  2922  3018  2237  2352  2500
     10  11015  11227  11449  8579  10440  8354
     50  19838  20685  22727  13239  24113  14382
     100  25427  22646  26700  18068  29046  18259
      
      結論:顯然在簡單類型的讀寫上,spymemcached全面占優,xmemcached唯一的亮點在于高并發下get的效率超過了spymemcached。對于連續的get操作,xmemcached將合并成一個批量的get操作提交,從而提高效率。

       讀寫100個元素的map,map的value是個自定義類,啟動N個線程,每個線程set(或者get、delete) 100次,表格如下

     線程數    spymemcached    xmemcached
       set  get set
     get
     1  492  492  427  492
     10  159  680  1103  1122
     50  57  1103  1561  1226
     100  71  1308  1530  1223


        結論:在復雜對象的讀寫上,xmemcached全面占優。兩者的CPU和內存占用差不多,肉眼觀察做不得準。比較奇怪的是spymemcached的set竟然那么慢。

        測試所用類下載

        xmemcached發布0.50版本,歡迎更多測試和建議,郵箱 killme2008@gmail.com

    posted @ 2009-03-04 19:09 dennis 閱讀(5101) | 評論 (1)編輯 收藏

    1、xmemcached是什么?

    xmemcached是基于java nio實現的memcached客戶端API。

    實際上是基于我實現的一個簡單nio框架 http://code.google.com/p/yanf4j/的基礎上實現的(目前是基于yanf4j 0.52),核心代碼不超過1000行,序列化機制直接挪用spymemcached的Transcoder。

    性能方面,在讀寫簡單類型上比之spymemcached還是有差距,在讀寫比較大的對象(如集合)有效率優勢。

    當 前0.50-beta版本,僅支持單個memcached服務器,以后考慮擴展。目前已經支持get、set、add、replace、delete、 incr、decr、version這幾個協議。API為阻塞模型,而非spymemcached的異步模式,異步模型在批處理的時候有優勢,但是阻塞模 式在編程難度和使用上會容易很多。

    2、為什么叫xmemcached?

    因為我在廈門(XM)混飯......


    3、xmemcached的下載和使用

    項目主頁:http://code.google.com/p/xmemcached/

    下載地址:http://code.google.com/p/xmemcached/downloads/list

    下載的壓縮包中包括了依賴庫、源碼和打包后的jar,放到項目的lib目錄下即可使用。

    示例參考:

    package net.rubyeye.xmemcached.test;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.io.Serializable;

    import net.rubyeye.xmemcached.XMemcachedClient;

    class Name implements Serializable {
        String firstName;
        String lastName;
        
    int age;
        
    int money;

        
    public Name(String firstName, String lastName, int age, int money) {
            
    super();
            
    this.firstName = firstName;
            
    this.lastName = lastName;
            
    this.age = age;
            
    this.money = money;
        }

        
    public String toString() {
            
    return "[" + firstName + " " + lastName + ",age=" + age + ",money="
                    
    + money + "]";
        }

    }

    public class Example {
        
    public static void main(String[] args) {
            
    try {
                String ip 
    = "192.168.222.100";

                
    int port = 11211;
                XMemcachedClient client 
    = new XMemcachedClient(ip, port);
                
    // 存儲操作
                if (!client.set("hello"0"dennis")) {
                    System.err.println(
    "set error");
                }
                client.add(
    "hello"0"dennis");
                client.replace(
    "hello"0"dennis");

                
    // get操作
                String name = (String) client.get("hello");
                System.out.println(name);

                
    // 批量獲取
                List<String> keys = new ArrayList<String>();
                keys.add(
    "hello");
                keys.add(
    "test");
                Map
    <String, Object> map = client.get(keys);
                System.out.println(
    "map size:"+map.size());

                
    // delete操作
                if (!client.delete("hello"1000)) {
                    System.err.println(
    "delete error");
                }

                
    // incr,decr
                client.incr("a"4);
                client.decr(
    "a"4);

                
    // version
                String version = client.version();
                System.out.println(version);
                
    // 增刪改查自定義對象
                Name dennis = new Name("dennis""zhuang"26-1);
                System.out.println(
    "dennis:" + dennis);
                client.set(
    "dennis"0, dennis);

                Name cachedPerson 
    = (Name) client.get("dennis");
                System.out.println(
    "cachedPerson:" + cachedPerson);
                cachedPerson.money 
    = -10000;

                client.replace(
    "dennis"0, cachedPerson);
                Name cachedPerson2 
    = (Name) client.get("dennis");
                System.out.println(
    "cachedPerson2:" + cachedPerson2);

                
    // delete
                client.delete("dennis");
                System.out.println(
    "after delete:" + client.get("dennis"));
                client.shutdown();
            } 
    catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    4、xmemcached的計劃?

    1)、添加多服務器和集群支持

    2)、性能優化、重構

    3)、添加cas原子操作以及更多協議支持

       
        有興趣的瞧瞧,提提建議。

    posted @ 2009-03-03 16:31 dennis 閱讀(3243) | 評論 (6)編輯 收藏

        yanf4j發布一個0.50-beta2版本,這個版本最重要的改進就是引入了客戶端連接非阻塞API,主要最近的工作要用到,所以添加了。兩個核心類TCPConnectorControllerUDPConnectorController分別用于TCP和UDP的客戶端連接控制。例如,現在的UDP echo client可以寫成:

         //客戶端echo handler
         class EchoClientHandler extends HandlerAdapter {

            
    public void onReceive(Session udpSession, Object t) {
                DatagramPacket datagramPacket 
    = (DatagramPacket) t;
                System.out.println(
    "recv:" + new String(datagramPacket.getData()));
            }

            @Override
            
    public void onMessageSent(Session session, Object t) {
                System.out.println(
    "send:" + new String((byte[]) t));
            }

        }

           //連接代碼,并發送UDP包

            UDPConnectorController connector 
    = new UDPConnectorController();
            connector.setSoTimeout(
    1000);
            connector.setHandler(
    new EchoClientHandler());
            connector.connect(
    new InetSocketAddress(InetAddress.getByName(host),
                    port));
            
    for (int i = 0; i < 10000; i++) {
                String s 
    = "hello " + i;
                DatagramPacket packet 
    = new DatagramPacket(s.getBytes(), s.length());
                connector.send(packet);
            }

        UDP不是面向連接的,因此connect方法僅僅是調用了底層DatagramChannel.connect方法,用來限制接收和發送的packet的遠程端點。

        再來看看TCPConnectorController的使用,同樣看Echo Client的實現:
    //客戶端的echo handler
    class EchoHandler extends HandlerAdapter<String> {

            @Override
            
    public void onConnected(Session session) {
                
    try {
                    
    //一連接就發送NUM個字符串
                    for (int i = 0; i < NUM; i++)
                        session.send(generateString(i));
                 } 
    catch (Exception e) {

                 }
            }

            
    public String generateString(int len) {
                StringBuffer sb 
    = new StringBuffer();
                
    for (int i = 0; i < MESSAGE_LEN; i++)
                    sb.append(i);
                
    return sb.toString();
            }

            @Override
            
    public void onReceive(Session session, String t) {
                //打印接收到字符串
                if (DEBUG)
                    System.out.println(
    "recv:" + t);
                
            }

        }


    //...連接API,TCPConnectorController示例
        Configuration configuration = new Configuration();
            configuration.setTcpSessionReadBufferSize(
    256 * 1024); // 設置讀的緩沖區大小
        TCPConnectorController    connector = new TCPConnectorController(configuration,
                    
    new StringCodecFactory());
        connector.setHandler(
    new EchoHandler());
        connector.setCodecFactory(
    new StringCodecFactory());
       
    try {
                connector.Connect(
    new InetSocketAddress("localhost"8080));
        } 
    catch (IOExceptione) {
                e.printStackTrace();
        }

        注意,connect方法并不阻塞,而是立即返回,連接是否建立可以通過TCPConnectorController.isConnected()方法來判斷,因此通常你可能會這樣使用:

    try {
                connector.Connect(
    new InetSocketAddress("localhost"8080));
                
    while(!connector.isConnected())
                    ;
            } 
    catch (Exception e) {
                e.printStackTrace();
            }

        來強制確保后面對connector的使用是已經連接上的connector,然而更好的做法是在Handler的onConnected()回調方法中處理邏輯,因為這個方法僅僅在連接建立后才會被調用。
        兩個ConnectorController都有系列send方法,用于發送數據:
    TCPConnectorController.send(Object msg) throws InterruptedException
    UDPConnectorController.send(DatagramPacket packet) 
    throws InterruptedException
    UDPConnectorController.send(SocketAddress targetAddr, Object msg)
    throws InterruptedException


        0.50-beta2帶來的另一個修改就是Session接口添加setReadBufferByteOrder方法,用于設置session接收緩沖區的字節序,默認是網絡字節序,也就是大端法。這個方法建議在Handler的onSessionStarted回調方法中調用。

        在0.50-beta最重要的修改是引入了session發送隊列緩沖區的流量控制選項。默認情況下,session的發送緩沖隊列是無界的,隊列的push和pop也全然不會阻塞。在設置了緩沖隊列的高低水位選項后即引入了發送流量控制,規則如下:
    a)當發送隊列中的數據總量大于高水位標記(highWaterMark),Session.send將阻塞
    b)在條件a的作用下,Session.send的阻塞將持續到發送隊列中的數據總量小于于低水位標記(lowWaterMark)才解除。


    緩沖隊列高低水位的設置通過Controller的下列方法設置:
         public void setSessionWriteQueueHighWaterMark(int highWaterMark);

         
    public void setSessionWriteQueueLowWaterMark(int lowWaterMark);
     
    緩沖隊列的流量控制想法來自ACE的ACE_Message_Queue,是通過com.google.code.yanf4j.util.MessageQueue類實現的。

       0.50-beta還引入了Session.send(Object msg)的重載版本 Session.send(Object msg,long timeout),在超過timeout時間后send仍然阻塞時即終止send。注意,現在Session.send的這兩個方法都返回一個bool值來表示send成功與否,并且都將響應中斷(僅限啟動了流量控制選項)拋出InterruptedException。

    posted @ 2009-02-19 00:15 dennis 閱讀(1771) | 評論 (2)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 18 19 20 21 22 23 24 25 26 下一頁 Last 
    主站蜘蛛池模板: 国产成人高清亚洲| 亚洲av片不卡无码久久| 五月亭亭免费高清在线| 亚洲av永久无码精品天堂久久| 免费观看一级毛片| 东北美女野外bbwbbw免费| 亚洲大香人伊一本线| 亚洲熟妇少妇任你躁在线观看无码 | 亚洲天堂男人影院| 久久久久亚洲AV成人网人人网站| 91精品国产免费入口| 成人性生交视频免费观看| 色播在线永久免费视频网站| 2020亚洲男人天堂精品| 亚洲国产另类久久久精品小说| 四虎影院免费视频| 日韩在线永久免费播放| 四虎精品免费永久免费视频| 久久亚洲精品专区蓝色区| 亚洲国产精品久久久久婷婷软件| 免费成人av电影| 在线免费视频一区| 我的小后妈韩剧在线看免费高清版| 你懂的网址免费国产| 成人免费夜片在线观看| 激情无码亚洲一区二区三区| 亚洲国产精品综合久久2007| 亚洲狠狠综合久久| 亚洲an天堂an在线观看| 亚洲va无码手机在线电影| 亚洲七七久久精品中文国产| 亚洲av日韩片在线观看| 中文字幕亚洲综合小综合在线| 亚洲午夜久久影院| 亚洲AV成人一区二区三区AV| 久久精品国产精品亚洲精品| 久久精品亚洲综合一品| 亚洲黄色免费观看| 亚洲中文字幕无码久久2020 | 深夜国产福利99亚洲视频| 国产精品免费看久久久久|