用Memcache实现分布式的锁服务

2018-04-16 11:19:05 浏览数 (1)

一般情况下我们都用Memcache作为一个分布式的key/value缓存服务器,其实Memcache也可以实一些外门邪道的功能比如作为分布式锁来用。

原理其实非常简单就是memecach_add的时候,如果添加的key已经存在那么后面的添加就会失败。设想在高并发的场景下,如果存在被竞争的资源,我们就可以利用这个小trick来对资源加锁。知道了原理实现起来非常简单,下面是我初步实现的代码。

代码语言:javascript复制
<?php

/**
 * 锁服务(用Memcache模拟锁)
 * Author: tomheng<zhm20070928@gmail.com>
 * gist: https://gist.github.com/tomheng/6149779
 */

class Lock{

    private $mc = null;
    private $key_prefix = "memcache_lock_service_key_";
    private $all_lock_names = array();
    private $expiration = 60; //one min
    private $max_block_time = 15; //最长的阻塞时间
    /**
     * [__construct description]
     */
    public function __construct(){
        if(function_exists('memcache_init')){
            $this->mc = memcache_connect('memcache_host', 11211);
        }
    }

    /**
     * [get_key description]
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
    private function get_key($name){
        $key = $this->key_prefix.$name;
        return $key;
    }

    /**
     * 捕获锁
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
    public  function begin($name, $block = true)
    {
        if(!$this->mc || !$name){
            return false;
        }
        $max_block_time = $this->max_block_time;
        $key = $this->get_key($name);
        do{ 
            $re = memcache_add($this->mc, $key, 1, false, $this->expiration);
            if($re == true){
                $this->all_lock_names[$name] = 1;
                //$this->debug();
                break;
            }else{
                //dolog('Lock failed '.$name);
            }
            //echo '#'.PHP_EOL;
            //sleep(1);
        }while($block && $max_block_time-- && !sleep(1));
        return $re;
    }

    /**
     * 释放锁
     */
    public function release($name){
        if(!$this->mc || !$name){
            return false;
        }
        $key = $this->get_key($name);
        $re = memcache_delete($this->mc, $key);
        if($re == true){
            unset($this->all_lock_names[$name]);
        }
        return $re;
    }

    /**
     * 释放所有的锁
     */
    public function __destruct(){
        if(!$this->mc){
            return false;
        }
        foreach ($this->all_lock_names as $name => $value) {
            # code...
            $this->release($name);
        }
    }

    /**
     * 调试
     * @return [type] [description]
     */
    public function debug(){
        var_dump($this->all_lock_names);
        foreach ($this->all_lock_names as $name => $value) {
            $key = $this->get_key($name);
            if($this->mc){
                $value = memcache_get($this->mc, $key);
            }else{
                $value = "no such lock ";
            }
            echo "Lock name:$key, value:{$value}".PHP_EOL;
        }
    }
}

0 人点赞