Jedis使用總結(jié) 前段時(shí)間細(xì)節(jié)的了解了Jedis的使用,Jedis是redis的java版本的客戶端實(shí)現(xiàn)。
本文做個(gè)總結(jié),主要分享如下內(nèi)容:【pipeline】【分布式的id生成器】【分布式鎖【watch】【multi】】【redis分布式】 好了,一個(gè)一個(gè)來。一、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。
簡單點(diǎn)說pipeline適用于批處理。當(dāng)有大量的操作需要一次性執(zhí)行的時(shí)候,可以用管道。
示例:Jedis jedis = new Jedis(String, int); Pipeline p = jedis.pipelined(); p.set(key,value);//每個(gè)操作都發(fā)送請求給redis-server p.get(key,value); p.sync();//這段代碼獲取所有的response 這里我進(jìn)行了20w次連續(xù)操作(10w讀,10w寫),不用pipeline耗時(shí):187242ms,用pipeline耗時(shí):1188ms,可見使用管道后的性能上了一個(gè)臺階??戳舜a了解到,管道通過一次性寫入請求,然后一次性讀取響應(yīng)。
也就是說jedis是:request response,request response,。;pipeline則是:request request。
response response的方式。這樣無需每次請求都等待server端的響應(yīng)。
二、跨jvm的id生成器 談到這個(gè)話題,首先要知道redis-server端是單線程來處理client端的請求的。這樣來實(shí)現(xiàn)一個(gè)id生成器就非常簡單了,只要簡單的調(diào)用jdeis.incr(key);就搞定了。
你或許會問,incr是原子操作嗎,能保證不會出現(xiàn)并發(fā)問題嗎,不是說了嗎,server端是單線程處理請求的。三、【跨jvm的鎖實(shí)現(xiàn)【watch】【multi】】 首先說下這個(gè)問題的使用場景,有些時(shí)候我們業(yè)務(wù)邏輯是在不同的jvm進(jìn)程甚至是不同的物理機(jī)上的jvm處理的。
這樣如何來實(shí)現(xiàn)不同jvm上的同步問題呢,其實(shí)我們可以基于redis來實(shí)現(xiàn)一個(gè)鎖。具體事務(wù)和監(jiān)聽請參考文章:redis學(xué)習(xí)筆記之事務(wù) 暫時(shí)找到三種實(shí)現(xiàn)方式:1. 通過jedis.setnx(key,value)實(shí)現(xiàn) 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 { //加鎖標(biāo)志 public static final String LOCKED = "TRUE"; public static final long ONE_MILLI_NANOS = 1000000L; //默認(rèn)超時(shí)時(shí)間(毫秒) public static final long DEFAULT_TIME_OUT = 3000; public static JedisPool pool; public static final Random r = new Random(); //鎖的超時(shí)時(shí)間(秒),過期刪除 public static final int EXPIRE = 5 * 60; static { pool = new JedisPool(new Config(), "host", 6379); } private Jedis jedis; private String key; //鎖狀態(tài)標(biāo)志 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) if (jedis.setnx(key, LOCKED) == 1) { jedis.expire(key, EXPIRE); locked = true; return locked; } // 短暫休眠,nano避免出現(xiàn)活鎖 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; } public boolean lock() { return lock(DEFAULT_TIME_OUT); } // 無論是否加鎖成功,必須調(diào)用 public void unlock() { try { if (locked) jedis.del(key); } finally { pool.returnResource(jedis); } } }2. 通過事務(wù)(multi)實(shí)現(xiàn) 由于采納第一張方法,第二種跟第三種實(shí)現(xiàn)只貼了關(guān)鍵代碼,望諒解。
^_^ public boolean lock_2(long timeout) { long nano = System.nanoTime(); timeout *= ONE_MILLI_NANOS; try { while ((System.nanoTime() - nano) Transaction t = jedis.multi(); // 開啟事務(wù),當(dāng)server端收到multi指令 // 會將該client的命令放入一個(gè)隊(duì)列,然后依次執(zhí)行,知道收到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避免出現(xiàn)活鎖 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; }3. 通過事務(wù)+監(jiān)聽實(shí)現(xiàn) public boolean lock_3(long timeout) { long nano = System.nanoTime(); timeout *= ONE_MILLI_NANOS; try { while ((System.nanoTime() - nano) jedis.watch(key); // 開啟watch之后,如果key的值被修改,則事務(wù)失敗,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避免出現(xiàn)活鎖 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; } 最終采用第一種實(shí)現(xiàn),因?yàn)榧渔i只需發(fā)送一個(gè)請求,效率最高。四、【redis分布式】 最后一個(gè)話題,jedis的分布式。
在jedis的源碼里發(fā)現(xiàn)了兩種hash算法(MD5,MURMUR Hash(默認(rèn))),也可以自己實(shí)現(xiàn)redis.clients.util.Hashing接口擴(kuò)展。 List hosts = new ArrayList(); //server1 JedisShardInfo host1 = new JedisShardInfo("", 6380, 2000); //server2 JedisShardInfo host2 = new 。
Object是所有類的父類,任何類都默認(rèn)繼承Object。Object類到底實(shí)現(xiàn)了哪些方法?
1.clone方法
保護(hù)方法,實(shí)現(xiàn)對象的淺復(fù)制,只有實(shí)現(xiàn)了Cloneable接口才可以調(diào)用該方法,否則拋出異常。
2.getClass方法
final方法,獲得運(yùn)行時(shí)類型。
3.toString方法
該方法用得比較多,一般子類都有覆蓋。
4.finalize方法
該方法用于釋放資源。因?yàn)闊o法確定該方法什么時(shí)候被調(diào)用,很少使用。
5.equals方法
該方法是非常重要的一個(gè)方法。一般equals和==是不一樣的,但是在Object中兩者是一樣的。子類一般都要重寫這個(gè)方法。
6.hashCode方法
該方法用于哈希查找,重寫了equals方法一般都要重寫hashCode方法。這個(gè)方法在一些具有哈希功能的Collection中用到。
一般必須滿足obj1.equals(obj2)==true。可以推出obj1.hash-
Code()==obj2.hashCode(),但是hashCode相等不一定就滿足equals。不過為了提高效率,應(yīng)該盡量使上面兩個(gè)條件接近等價(jià)。
7.wait方法
wait方法就是使當(dāng)前線程等待該對象的鎖,當(dāng)前線程必須是該對象的擁有者,也就是具有該對象的鎖。wait()方法一直等待,直到獲得鎖或者被中斷。wait(long
timeout)設(shè)定一個(gè)超時(shí)間隔,如果在規(guī)定時(shí)間內(nèi)沒有獲得鎖就返回。
調(diào)用該方法后當(dāng)前線程進(jìn)入睡眠狀態(tài),直到以下事件發(fā)生。
(1)其他線程調(diào)用了該對象的notify方法。
(2)其他線程調(diào)用了該對象的notifyAll方法。
(3)其他線程調(diào)用了interrupt中斷該線程。
(4)時(shí)間間隔到了。
此時(shí)該線程就可以被調(diào)度了,如果是被中斷的話就拋出一個(gè)InterruptedException異常。
8.notify方法
該方法喚醒在該對象上等待的某個(gè)線程。
9.notifyAll方法
該方法喚醒在該對象上等待的所有線程。
redis是key-value存儲系統(tǒng)。
key-value分布式存儲系統(tǒng)查詢速度快、存放數(shù)據(jù)量大、支持高并發(fā),非常適合通過主鍵進(jìn)行查詢,但不能進(jìn)行復(fù)雜的條件查詢。
如果輔以Real-Time Search Engine(實(shí)時(shí)搜索引擎)進(jìn)行復(fù)雜條件檢索、全文檢索,就可以替代并發(fā)性能較低的MySQL等關(guān)系型數(shù)據(jù)庫,達(dá)到高并發(fā)、高性能,節(jié)省幾十倍服務(wù)器數(shù) 量的目的。
以MemcacheDB、Tokyo Tyrant為代表的key-value分布式存儲,在上萬并發(fā)連接下,輕松地完成高速查詢。而MySQL,在幾百個(gè)并發(fā)連接下,就基本上崩潰了。
在此基礎(chǔ)上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了master-slave(主從)同步。
擴(kuò)展資料:
Jedis主存保護(hù)是存儲保護(hù)的重要環(huán)節(jié)。主存保護(hù)一般有存儲區(qū)域保護(hù)和訪問方式保護(hù)。存儲區(qū)域保護(hù)可采用界限寄存器方式,由系統(tǒng)軟件經(jīng)特權(quán)指令給定上、下界寄存器內(nèi)容,從而劃定每個(gè)用戶程序的區(qū)域,禁止越界訪問。
Jedis當(dāng)兩鍵符合時(shí)才允許執(zhí)行存取操作,從而保護(hù)別的程序區(qū)域不被侵犯,環(huán)狀保護(hù)是把系統(tǒng)程序和用戶程序按重要性分層,稱為環(huán),對每個(gè)環(huán)都規(guī)定訪問它的級別,違反規(guī)定的存取操作是非法的,以此實(shí)現(xiàn)對正在執(zhí)行的程序的保護(hù)。
參考資料來源:百度百科-Key-Value
主要有兩種方式:
① 快照持久化
在Redis配置文件中已經(jīng)自動開啟了,
格式是:save N M
表示在N秒之內(nèi),redis至少發(fā)生M次修改則redis抓快照到磁盤。
當(dāng)然我們也可以手動執(zhí)行save或者bgsave(異步)命令來做快照
②append only file AOF持久化
總共有三種模式,如
appendfsync everysec默認(rèn)的是每秒強(qiáng)制寫入磁盤一次
appendfsync always 每次執(zhí)行寫操作的時(shí)候就強(qiáng)制寫入磁盤
appendfsync no 完全取決于os,性能最好但是持久化沒法保證
其中第三種模式最好。redis默認(rèn)的也是采取第三種模式。
簡單說一下,除了一些公司自主開發(fā)的集群外。常用的一般有三種:
1. 使用redis-trib.rb,這個(gè)是安裝redis時(shí)就自帶的一種集群,采用了服務(wù)端分片的方式。Jedis使用JedisCluster類來訪問。
2. 使用Jedis帶的客戶端分片ShardedJedisPool類。
3. 使用代理進(jìn)行分片twemproxy,連接代理可以使用Jedis類(單鏈接)和JedisPool類(多鏈接)。
下面提供一個(gè)JedisCluster的例子:
JedisCluster cluster;
public void init() {
// 加載redis配置文件
ResourceBundle bundle = ResourceBundle.getBundle("redis");
if (bundle == null) {
throw new ("[redis.properties] is not found!");
}
// 創(chuàng)建jedis池配置實(shí)例
JedisPoolConfig config = new JedisPoolConfig();
// 設(shè)置池配置項(xiàng)值
config.setMaxTotal(Integer.valueOf(bundle.getString("redis.pool.maxActive").trim()));
config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle").trim()));
config.setMaxWaitMillis(Long.valueOf(bundle.getString("redis.pool.maxWait").trim()));
config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow").trim()));
config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn").trim()));
Set hps = new HashSet();
hps.add(new HostAndPort("192.168.242.133", 4001));
hps.add(new HostAndPort("192.168.242.133", 4002));
hps.add(new HostAndPort("192.168.242.133", 4003));
hps.add(new HostAndPort("192.168.242.133", 4004));
cluster = new JedisCluster(hps, 2000, 5);
}
public void test() {
// 這里就可以使用cluster進(jìn)行各種redis的操作了(與Jedis類的接口類似)
cluster.set("key", "value");
}
如果要了解其它的,請留言給我。
這些都是父類的方法
java.awt.Frame extends java.awt.Window
java.awt.Window extends java.awt.Container
java.awt.Container extends java.awt.Component
java.awt.Component extends ava.lang.Object
聲明:本網(wǎng)站尊重并保護(hù)知識產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護(hù)條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請?jiān)谝粋€(gè)月內(nèi)通知我們,我們會及時(shí)刪除。
蜀ICP備2020033479號-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時(shí)間:2.695秒