標籤:
官網:http://redis.io
定義:持久化的高效能key-value記憶體型資料庫
應用情境:資料緩衝、聊天系統、訪問量統計、訊息佇列、分布式鎖等等
優勢對比:
•輕量級 : redis非常輕量(源碼僅1.5M),就個人而言我更喜歡小而輕的東西,對於一些盡量想要完美而龐大的東西來說我是非常反感的, 有些東西儘可能的追求完美反而忽略了最本質的東西或者說是產品設計的初衷 •持久化 : redis 提供了非常有好的持久化支援,保證資料完整性 •高效能 : redis 是基於記憶體型的中介軟體,記憶體型意味著更優秀的效能(實際測試,單機單線程內網環境下可完成10000次/s的寫操作),中見間的特性使他對分布式有著很好的支援 •豐富的資料類型和命令 : redis共有String、List、Hash、Set、SortSet 5種資料類型和豐富的操作命令,這些特性使redis除了準系統之外,可以應用於多種情境 •豐富的用戶端語言支援 •使用簡單
redis應用之分一 分布式鎖實現:原理:分布式鎖主要應用了redis 的 setnx 命令特性,setnx key value,將key的值設為value,當key已存在時則不做處理,我們利用其不能同時賦值的特性實現鎖的效果代碼實現:擷取鎖
1 /** 2 * 擷取分布式鎖 DLock 3 * @param key 鎖標誌 4 * @param holder 鎖持有人(一般為uuid,唯一標識當前鎖的持有人) 5 * @param timeout 擷取鎖的逾時時間 毫秒 6 * @return 7 */ 8 public static boolean getDLock(String key, String holder, long timeout){ 9 Jedis jedis = DRJedis.getJedisPool();10 //設定擷取鎖的逾時時間11 long end = System.currentTimeMillis() + timeout;12 while (System.currentTimeMillis() < end){13 if (jedis.setnx(LOCK_PREFIX + key, holder) == 1) return true;14 try {15 Thread.sleep(10);16 } catch (InterruptedException e) {17 log.error("擷取 DLock 異常", e);18 return false;19 }20 }21 log.error("擷取 DLock 逾時");22 return false;23 }
View Code
這個方法表示如果setnx成功,表示當前沒有別的線程持有key這個鎖,則擷取鎖,同時阻止其他線程再次擷取這個鎖,如果擷取所失敗,則在timeout時間範圍內嘗試嘗試重新擷取,否則返回擷取鎖失敗
釋放鎖:釋放鎖即刪除key操作,以便於其它的線程可以setnx
1 /** 2 * 釋放鎖 3 * @param key 鎖標誌 4 * @param holder 鎖持有人(一般為uuid,唯一標識當前鎖的持有人) 5 */ 6 public static void releaseDLock(String key, String holder){ 7 Jedis jedis = DRJedis.getJedisPool(); 8 while (true){ 9 try {10 jedis.watch(LOCK_PREFIX + key);11 String value = jedis.get(LOCK_PREFIX + key);12 if(value != null && value.equals(holder)){// 保證釋放的是當前持有人的鎖13 Transaction tran = jedis.multi();14 jedis.del(LOCK_PREFIX + key);15 tran.exec();16 }17 jedis.unwatch();18 break;19 }catch (Exception e){20 log.error("釋放鎖異常", e);21 break;22 }23 }24 }
View Code
這個方法表示釋放鎖,通過事務保證同時時候放鎖操作
redis應用之分二 MQ實現:
原理:mq是基於redis list 列表資料類型的實現,右端入隊,左端出隊的先入先出特性
生產訊息代碼
1 /** 2 * 生產訊息 3 * @param key 訊息key 4 * @param message 訊息體,支援批量生產訊息,至少生產一條訊息 5 */ 6 public static void product(String key, String... message){ 7 try{ 8 DRJedis.getJedisPool().rpush(MQ_PREFIX + key, message); 9 }catch(Exception e){10 log.error("jedis product message", e);11 }12 }
View Code
rpush 從右端推入隊列
消費訊息:
1 /** 2 * 消費訊息 3 * @param key 訊息key 4 * @param customer 訊息消費業務,需要實現Customer介面的customer方法進行業務處理 5 */ 6 public static void customer(String key, ICustomer customer){ 7 try{ 8 Jedis jedis = DRJedis.getJedisPool(); 9 while (true){10 //彈出訊息11 List<String> messages = jedis.blpop(0, MQ_PREFIX + key);12 if (messages.size() >= 2){13 try {14 //消費訊息15 customer.customer(messages.get(0), messages.get(1));16 }catch (RollbackException e){17 //訊息消費失敗則要重新生產訊息,並有左側壓入隊列,保證下次第一個被消費18 jedis.lpush(messages.get(0), messages.get(1));19 }20 }21 }22 }catch(Exception e){23 log.error("jedis customer message", e);24 }25 }
View Code
blpop 從左端彈出訊息,如果隊列為空白則阻塞訊息等待,此方法使用了while(true)無限迴圈的方式類比監聽器,以便於及時的消費訊息,ICustomer 定義具體的消費業務,並拋出RollbackException異常表示,訊息消費失敗,需要復原,則重新從左端推入隊列,保證下次被第一個消費
1 /**2 * Created by xiao on 2016/5/20.3 */4 public interface ICustomer {5 6 void customer(String key, String message) throws RollbackException;7 8 }
View Code
消費訊息的業務需要實現ICustomer的customer方法,消費訊息
1 /** 2 * 復原異常 3 */ 4 public class RollbackException extends Exception { 5 6 public RollbackException(String message) { 7 super(message); 8 } 9 10 public RollbackException() {11 super();12 }13 14 public RollbackException(String message, Throwable cause) {15 super(message, cause);16 }17 18 public RollbackException(Throwable cause) {19 super(cause);20 }21 22 protected RollbackException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {23 super(message, cause, enableSuppression, writableStackTrace);24 }25 }
View Code
Redis 應用分析