基于redis实现的锁(用于控制nodejs的并发)


  • Lv 1

    场景:使用node+mongo搭建web应用时,常常遇到并发问题导致创建一条数据的时候会同时创建多条。

    通过redis set 方法 配合 ‘NX’ 选项即可实现锁机制。

    主要的方法有三个:

    lock(加锁)

    unlock(解锁)

    extend(更改锁过期时间)

    Redlock.prototype.lock = function(resource,ttl,callback){
     var self = this;
     var _val = _random();
     return new Promise(function(resolve, reject) {
     var lock = new Lock(self, resource, _val);
    self.client.SET(resource,_val,'EX',ttl,'NX',function(err,data){
     if(!err && data === 'OK'){
     return resolve(lock);
    }else{
     var err = err || 'resource: '+resource+' is locked.';
     self.emit('lockError', err);
     return reject(err);
    }
    })
    }).asCallback(callback);
    }
    Redlock.prototype.unlock = function(lock,callback){
     var self = this;
     return new Promise(function(resolve, reject) {
     if(typeof lock !== 'object') return reject('unlockError:lock is not object.');
    self.client.GET(lock.resource,function(err,data){
     if(!err && data === lock.value){
    self.client.DEL(lock.resource,function(err){
    if(err){
    self.emit('unlockError',err);
     return reject('unlockError:'+err);
    }else{
     return resolve(lock);
    }
    })
    }else{
     self.emit('unlockError',err || 'resource:' + lock.resource + ' unable to unlock.')
     return reject('unlockError:' + err || ('resource:' + lock.resource + ' unable to unlock.'));
    }
    })
    }).asCallback(callback);
    }
    Redlock.prototype.extend = function(lock,ttl,callback){
     var self = this;
     return new Promise(function(resolve, reject){
     if(typeof lock !== 'object') return reject('unlockError:lock is not object.');
    self.client.GET(lock.resource,function(err,data){
     if(!err && data === lock.value){
    self.client.expire(lock.resource,ttl,function(err,data){
     if(!err && data === 1){
     return resolve(lock);
    }else{
     self.emit('extendError', err);
     return reject('extendError:'+err);
    }
    });
    }else{
     self.emit('extendError', err);
     return reject('extendError:'+err);
    }
    })
    }).asCallback(callback);
    }

    用法

    var client = require('redis').createClient('port','host');
    var redlock = new RedLock(client);
    var lock;
    `callback`:
    //lock
    redlock.lock('test-resource-lock',3,function(err,lockInstance){
     lock = lockInstance;
    done(err);
    });
    //unlock
    redlock.unlock(lock,function(err,data){
    done(err);
    });
    `promise`:
    redlock.lock('test-resource-lock-promise',3).done(
    function(lock){
    //todo
    redlock.unlock(lock);
    },
    function(){
    }
    )

    PS:支持callback and promise.


  • Lv 1

    針對你提的問題"並發問題導致創建一條數據的時候會同時創建多條"有簡單範例節是一下解決方案嗎?


登录后回复
 

与 萌阔论坛 的连接断开,我们正在尝试重连,请耐心等待