分布式锁
数据库
数据库是使用唯一索引不允许重复的特性 (或自定义实现如乐观锁). 但持有锁的进程如果释放锁时异常则容易导致死锁.
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);
来源: https://www.cnblogs.com/walkinhalo/p/10710107.html