<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 沖杯茶喝 閱讀(24082) 評論(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);有問題吧 ,如果一直有鎖請求,豈不是每次都把這個過期時間重新設置了?應該先判斷下有沒有超時,沒有就設置,有的話就不設置。  回復  更多評論
      

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


    網站導航:
     
    主站蜘蛛池模板: 91精品国产免费| 2021精品国产品免费观看| 免费无码又爽又高潮视频| 亚洲天堂中文字幕在线观看| 777爽死你无码免费看一二区| 国产精品自拍亚洲| 日韩免费一区二区三区在线播放| 日本一线a视频免费观看| 精品日韩99亚洲的在线发布| 无码国产精品久久一区免费| 抽搐一进一出gif免费视频| 亚洲国产精品视频| 97在线免费观看视频| 国产亚洲精品xxx| 99re免费99re在线视频手机版| 免费国产黄线在线观看| 亚洲videos| 国产一卡二卡≡卡四卡免费乱码 | 大地资源免费更新在线播放 | 亚洲男人的天堂在线va拉文| 青青青视频免费观看| 亚洲第一黄色网址| 99久久成人国产精品免费 | 99视频全部免费精品全部四虎| 免费人妻无码不卡中文字幕18禁| 亚洲AV无码不卡无码| 每天更新的免费av片在线观看| 亚洲综合图色40p| 免费国产黄网站在线观看| 国产精品高清视亚洲一区二区 | 精品国产日韩久久亚洲| 国产精品深夜福利免费观看| 无码日韩人妻AV一区免费l| 亚洲成AV人片在线观看无码 | 99久久免费观看| 亚洲精品国产高清在线观看| 国产成人99久久亚洲综合精品 | 亚洲一区二区在线视频| 国产精品久免费的黄网站| 两个人看的www高清免费视频| 亚洲国产成人精品无码久久久久久综合|