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

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

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

    隨筆-4  評論-10  文章-0  trackbacks-0
    創建日期:2012年7月3日
    修改日期:2012年7月19日
    前段時間細節的了解了Jedis的使用,Jedis是redis的java版本的客戶端實現。
    本文做個總結,主要分享如下內容:

    【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】
    好了,一個一個來。
    一、 Pipeline
    官方的說明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you finish sending them。簡單點說pipeline適用于批處理。當有大量的操作需要一次性執行的時候,可以用管道。
    示例:
    Jedis jedis = new Jedis(String, int);
    Pipeline p = jedis.pipelined();
    p.set(key,value);//每個操作都發送請求給redis-server
    p.get(key,value);

    p.sync();//這段代碼獲取所有的response
    這里我進行了20w次連續操作(10w讀,10w寫),不用pipeline耗時:187242ms,用pipeline耗時:1188ms,可見使用管道后的性能上了一個臺階。看了代碼了解到,管道通過一次性寫入請求,然后一次性讀取響應。也就是說jedis是:request response,request response,...;pipeline則是:request request... response response的方式。這樣無需每次請求都等待server端的響應。

    二、 跨jvm的id生成器 
    談到這個話題,首先要知道redis-server端是單線程來處理client端的請求的。
    這樣來實現一個id生成器就非常簡單了,只要簡單的調用jdeis.incr(key);就搞定了。
    你或許會問,incr是原子操作嗎,能保證不會出現并發問題嗎,前面說過,server端是單線程處理請求的。

    三、 【跨jvm的鎖實現【watch】【multi】】
    首先說下這個問題的使用場景,有些時候我們業務邏輯是在不同的jvm進程甚至是不同的物理機上的jvm處理的。這樣如何來實現不同jvm上的同步問題呢,其實我們可以基于redis來實現一個鎖。
    具體事務和監聽請參考文章:redis學習筆記之事務
     暫時找到三種實現方式:
    1. 通過jedis.setnx(key,value)實現
         import java.util.Random;

    import org.apache.commons.pool.impl.GenericObjectPool.Config;

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.Transaction;

    /**
     * 
    @author Teaey
     
    */
    public class RedisLock {
        //加鎖標志
        public static final String LOCKED = "TRUE";
        public static final long ONE_MILLI_NANOS = 1000000L;
        //默認超時時間(毫秒)
        public static final long DEFAULT_TIME_OUT = 3000;
        public static JedisPool pool;
        public static final Random r = new Random();
        //鎖的超時時間(秒),過期刪除
        public static final int EXPIRE = 5 * 60;
        static {
            pool = new JedisPool(new Config(), "host", 6379);
        }
        private Jedis jedis;
        private String key;
        //鎖狀態標志
        private boolean locked = false;

        public RedisLock(String key) {
            this.key = key;
            this.jedis = pool.getResource();
        }

        public boolean lock(long timeout) {
            long nano = System.nanoTime();
            timeout *= ONE_MILLI_NANOS;
            try {
                while ((System.nanoTime() - nano) < timeout) {
                    if (jedis.setnx(key, LOCKED) == 1) {
                        jedis.expire(key, EXPIRE);
                        locked = true;
                        return locked;
                    }
                    // 短暫休眠,nano避免出現活鎖
                    Thread.sleep(3, r.nextInt(500));
                }
            } catch (Exception e) {
            }
            return false;
        }
        public boolean lock() {
            return lock(DEFAULT_TIME_OUT);
        }

        // 無論是否加鎖成功,必須調用
        public void unlock() {
            try {
                if (locked)
                    jedis.del(key);
            } finally {
                pool.returnResource(jedis);
            }
        }
    }
    2. 通過事務(multi)實現
    由于采納第一張方法,第二種跟第三種實現只貼了關鍵代碼,望諒解。^_^
         public boolean lock_2(long timeout) {
            long nano = System.nanoTime();
            timeout *= ONE_MILLI_NANOS;
            try {
                while ((System.nanoTime() - nano) < timeout) {
                    Transaction t = jedis.multi();
                    // 開啟事務,當server端收到multi指令
                    
    // 會將該client的命令放入一個隊列,然后依次執行,知道收到exec指令
                    t.getSet(key, LOCKED);
                    t.expire(key, EXPIRE);
                    String ret = (String) t.exec().get(0);
                    if (ret == null || ret.equals("UNLOCK")) {
                        return true;
                    }
                    // 短暫休眠,nano避免出現活鎖
                    Thread.sleep(3, r.nextInt(500));
                }
            } catch (Exception e) {
            }
            return false;
        }
    3. 通過事務+監聽實現
        public boolean lock_3(long timeout) {
            long nano = System.nanoTime();
            timeout *= ONE_MILLI_NANOS;
            try {
                while ((System.nanoTime() - nano) < timeout) {
                    jedis.watch(key);
                    // 開啟watch之后,如果key的值被修改,則事務失敗,exec方法返回null
                    String value = jedis.get(key);
                    if (value == null || value.equals("UNLOCK")) {
                        Transaction t = jedis.multi();
                        t.setex(key, EXPIRE, LOCKED);
                        if (t.exec() != null) {
                            return true;
                        }
                    }
                    jedis.unwatch();
                    // 短暫休眠,nano避免出現活鎖
                    Thread.sleep(3, r.nextInt(500));
                }
            } catch (Exception e) {
            }
            return false;
        }
    最終采用第一種實現,因為加鎖只需發送一個請求,效率最高。
    四、 【redis分布式】
        最后一個話題,jedis的分布式。在jedis的源碼里發現了兩種hash算法(MD5,MURMUR Hash(默認)),也可以自己實現redis.clients.util.Hashing接口擴展。
        List<JedisShardInfo> hosts = new ArrayList<JedisShardInfo>();
            //server1
            JedisShardInfo host1 = new JedisShardInfo("", 6380, 2000);
            //server2
            JedisShardInfo host2 = new JedisShardInfo("", 6381, 2000);
            hosts.add(host1);
            hosts.add(host2);
            ShardedJedis jedis = new ShardedJedis(hosts);
            jedis.set("key", "");


    另外寫博客真費力。。。
    posted on 2012-07-03 13:32 沖杯茶喝 閱讀(24080) 評論(6)  編輯  收藏

    評論:
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 2013-01-25 10:08 | finallygo
    2.6之后,支持了script,又有新的辦法了  回復  更多評論
      
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 2013-05-03 09:54 | 沖杯茶喝
    沒時間研究了,如果有新的,可以完善本文@finallygo
      回復  更多評論
      
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 2013-05-23 00:53 | leealways887
    請問博主,為什么我用了pipeline之后,設置10萬條數據,程序反應不過來,倒是不用pipeline,程序還能正常運行呢?  回復  更多評論
      
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】[未登錄] 2014-02-11 15:44 | young
    @leealways887
    數據量太大了吧 內存用完了  回復  更多評論
      
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 2014-11-03 17:36 | louzhu
    什么叫反應不過來!據我說之,redis服務器應該不會反應不過來。

    @leealways887
      回復  更多評論
      
    # re: Jedis使用總結【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 2016-05-20 10:13 | fruwei
    第二種的t.expire(key, EXPIRE);有問題吧 ,如果一直有鎖請求,豈不是每次都把這個過期時間重新設置了?應該先判斷下有沒有超時,沒有就設置,有的話就不設置。  回復  更多評論
      

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲av无码国产精品色午夜字幕| 国产大片91精品免费观看男同 | 亚洲熟妇丰满多毛XXXX| 日本高清不卡中文字幕免费| 国产视频精品免费| 免费的黄色网页在线免费观看| 国产国产成年年人免费看片| 菠萝菠萝蜜在线免费视频| 亚洲成av人片在线观看天堂无码| 香蕉视频在线观看免费| 久久久久亚洲AV综合波多野结衣 | 亚洲情侣偷拍精品| 成人免费网站久久久| 久久综合亚洲色HEZYO国产| 久久er国产精品免费观看8| 亚洲爆乳无码一区二区三区| 久久大香香蕉国产免费网站| 亚洲高清在线mv| 成年女人午夜毛片免费看| 美女视频黄a视频全免费网站一区 美女视频黄a视频全免费网站色 | a级毛片在线免费| 亚洲精品天天影视综合网| 亚洲精品视频在线观看免费| 亚洲欧洲无码AV不卡在线| 亚洲高清无码专区视频| 永久免费A∨片在线观看| 亚洲男人的天堂在线| 在线观看免费成人| 精品一区二区三区免费观看| 91在线亚洲精品专区| 国产男女猛烈无遮挡免费视频 | 亚洲一卡2卡4卡5卡6卡残暴在线| 日本一道一区二区免费看 | 亚洲av永久无码精品国产精品| 114一级毛片免费| 色偷偷亚洲第一综合网| 国产亚洲综合色就色| 国产精品视频永久免费播放| free哆拍拍免费永久视频| 亚洲伊人久久精品| av在线亚洲欧洲日产一区二区|