小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

緩存對事務的支持

 xujin3 2018-06-17



本文節(jié)選自即將出版的《可伸縮服務架構:框架與中間件》一書,作者:李艷鵬、楊彪、李海亮、賈博巖、劉淏。


- 點擊文末原文鏈接可以直達《可伸縮服務架構:框架與中間件》書籍主頁。


在使用Redis緩存的業(yè)務場景時經常會有這樣的需求:要求遞減一個變量,如果遞減后變量小于等于0,則返回一個標志;如果成功,則返回剩余的值,類似于數(shù)據(jù)庫事務的實現(xiàn)。


在實現(xiàn)中需要注意服務器端的多線程問題及客戶端的多線程問題。在服務器端可以利用服務器單線程執(zhí)行LUA腳本來保證,或者通過WATCHEXEC、DISCARDEXEC來保證。


Redis中支持LUA腳本,由于Redis使用單線程實現(xiàn),因此我們首先給出LUA腳本的實現(xiàn)方案。在如下代碼中,我們看到變量被遞減,并判斷是否將小于0的操作放到LUA腳本里,利用Redis的單線程執(zhí)行的特性完成這個原子遞減的操作:

/**
* Implemented by LUA. Minus a key by a value, then return the left value.
* If the left value is less than 0, return -1; if error, return -1.
*
* @param key
*            the key of the redis variable.
* @param value
*            the value to minus off.
* @return the value left after minus. If it is less than 0, return -1; if
*         error, return -1.
*/

public long decrByUntil0Lua(String key, long value) {
   // If any error, return -1.
   if (value <=>0)
       return -1;

   // The logic is implemented in LUA script which is run in server thread,
   // which is single thread in one server.
   String script = ' local leftvalue = redis.call('get', KEYS[1]); '
           + ' if ARGV[1] - leftvalue > 0 then return nil; else '
           + ' return redis.call('decrby', KEYS[1], ARGV[1]); end; ';

   Long leftValue = (Long) jedis.eval(script, 1, key, '' + value);

   // If the left value is less than 0, return -1.
   if (leftValue == null)
       return -1;

   return leftValue;
}

還可以通過Redis對事務的支持方法watchmulti來實現(xiàn),類似于一個CAS方法的實現(xiàn),如果對熱數(shù)據(jù)有競爭,則會返回失敗,然后重試直到成功:

/**
* Implemented by CAS. Minus a key by a value, then return the left value.
* If the left value is less than 0, return -1; if error, return -1.
*
* No synchronization, because redis client is not shared among multiple
* threads.
*
* @param key
*            the key of the redis variable.
* @param value
*            the value to minus off.
* @return the value left after minus. If it is less than 0, return -1; if
*         error, return -1.
*/

public long decrByUntil0Cas(String key, long value) {
   // If any error, return -1.
   if (value <=>0)
       return -1;

   // Start the CAS operations.
   jedis.watch(key);

   // Start the transation.
   Transaction tx = jedis.multi();

   // Decide if the left value is less than 0, if no, terminate the
   // transation, return -1;
   String curr = tx.get(key).get();
   if (Long.valueOf(curr) - value <>0) {
       tx.discard();
       return -1;
   }

   // Minus the key by the value
   tx.decrBy(key, value);

   // Execute the transaction and then handle the result
   List result = tx.exec();

   // If error, return -1;
   if (result == null || result.isEmpty()) {
       return -1;
   }

   // Extract the first result
   for (Object rt : result) {
       return Long.valueOf(rt.toString());
   }

   // The program never comes here.
   return -1;
}

END


    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多