分布式系列十一: Redis進階


分布式鎖

  • 數據庫

    數據庫是使用唯一索引不允許重復的特性(或自定義實現如樂觀鎖). 但持有鎖的進程如果釋放鎖時異常則容易導致死鎖.

  • zookeeper

    使用臨時節點, watcher可以獲得節點被刪除的通知, 當客戶端連接失效后, 臨時節點清除, 所以這種情況下不會有死鎖發生.

  • redis

    setNX實現

// 為了簡單就不用配置文件了
@Configuration
public class RedisManager {

    private JedisPool jedisPool ;

    public RedisManager(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);

        this.jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1",6379);
    }


    @Bean
    public Jedis getJedis(){
        if (this.jedisPool==null){
            return null;
        }
        return jedisPool.getResource();
    }

}
// lock, unlock 方法這里沒有用異常處理.
@Component
public class RedisLock {

    @Autowired
    private Jedis jedis;

    public String lock(String key, int timeout){
        String uuid = UUID.randomUUID().toString();
        long lockTime = System.currentTimeMillis();
        while(System.currentTimeMillis()-lockTime<timeout*1000) {
            long rs = jedis.setnx(key, uuid);
            if (rs==1){
                jedis.expire(key, (int) timeout);
                return uuid;
            }

            // 保證key被設置了超時時間
            if (jedis.ttl(key)==-1){
                jedis.expire(key, (int) timeout);
            }
        }
        return  uuid;
    }

    public boolean unlock(String key, String value){
        while(true) {
            jedis.watch(key);
            String ret = jedis.get(key);
            if (value.equals(ret)) {
                Transaction transaction = jedis.multi();
                transaction.del(key);
                List<Object> transResult = transaction.exec();
                if (transResult == null) {
                    continue;
                }
                jedis.unwatch();
                return true;
            }
            jedis.unwatch();
            break;
        }
        return false;

    }

}

lua語言

redis可以使用lua腳本. lua是動態類型語言.

  • 減少網絡開銷

  • 原子操作

  • 代碼可以復用

  • 輕量級

安裝

tar -zxvf ...
make linux
make install

出現fatal error: readline/readline.h: No such file or directory 則需要運行

sudo apt-get install libreadline-dev

命令

  • 全局變量, 局部變量
a=1
print(a)

local b=2 print(b) //局部變量,在一條語句

local array = {"a","b"} //數組定義
  • 邏輯表達式
      • / %

不等於使用~=

  • 邏輯運算

not (a and/or B)

  • 字符串連接

str1..str2

  • 字符串長度用#

#"hello"

  • 分支

if expression then elseif expression then end

  • 循環

while expression do ..... end

for i=1,100 do .... end

for i,v in iparis(array) do ..... end

  • 注釋

單行使用-- ; 范圍使用--[[ ..... ]]

  • 函數
function(params...)
    --......
    return a;
end

內置對象: String , Table tonumber()

  • lua 可以調用redis命令

redis.call() --需要引入庫支持, redis內置的lua, 可以在redis內部執行

lua在Redis中的使用

  • 執行 eval 'lua script' keynumber key...

  • KEYS[] ARGV[] 入參, 必須大寫

  • 執行lua腳本文件./redis-cli --eval luafile.lua keyparam1 , valueparam2 vlaueparam3

程序中使用lua

String lua = "local num = redis.call('incr',KEYS[1]) ... ";
jedis.eval();

可以使用摘要執行腳本, 這對大腳本文件比較有用.

jedis.evalsha(jedis.scriptLoad(lua),key,value);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM