IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PHP+redis实现分布式锁 -> 正文阅读

[PHP知识库]PHP+redis实现分布式锁

什么是分布式锁

定义:在分布式环境下,一个共享的可见的公共资源,各个线程通过对这个公共资源的抢占,能够使得一个代码块在同一时间只能被一个机器的一个线程执行,那这个公共资源就是分布式锁,或者说这整个机制就是分布式锁。

或者从使用场景定义:分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性

分布式锁实现方式

锁的实现方式有多种,只要能满足所有线程都能看得到这个锁标记即可。

常见的方式是使用数据库、缓存或者zookeeper来实现分布式锁,除了这些,其实一个网络中的共享可见的可读写的资源就可以用作实现锁。

锁的操作主要有两个,即lock()和unlock()。

分布式特性

  • 这把锁要是一把可重入锁 (一般是指设置过期时间,避免死锁)
  • 这把锁最好是一把阻塞锁(阻塞锁是指不断循环请求获取锁资源,一般根据业务需求需不需要阻塞)
  • 有高可用的获取锁和释放锁的功能
  • 获取锁和释放锁的性能要好

PHP+REDIS实现

  • 在多进程或者分布式执行同一份代码去处理同一份业务,在未加锁的情况下,并发下会出现重复执行。
  • 例如:多进程查询数据库库存去处理业务,可能多个任务全部拿到凭证,导致库存变成负数。这种情况下需要引入分布式锁,避免数据库修改未完成比其他任务获取,下面使用php+redis进行实现
<?php

class RedisLock
{
    public $redis;
    public $lockedNames = [];

    public function __construct()
    {
        $this->redis = new \Redis();
        $this->redis->connect('127.0.0.1', '6379');
    }

    public function lock($name, $timeout = 10, $expire = 15, $waitIntervalUs = 100000)
    {
        if ($name == null) return false;
        //获取当前时间
        $now = time();
        //获取锁失败时的等待超时时刻
        $timeoutAt = $now + $timeout;
        //锁的最大生存时刻
        $expireAt = $now + $expire;

        $redisKey = "Lock:{$name}";
        while (true) {
            //将rediskey的最大生存时刻存到redis里,过了这个时刻该锁会被自动释放
            $result = $this->redis->setnx($redisKey, $expireAt);

            if ($result) {
                //设置key的失效时间
                $this->redis->expire($redisKey, $expire);
                //将锁标志放到lockedNames数组里
                $this->lockedNames[$name] = $expireAt;
                //以秒为单位,返回给定key的剩余生存时间
                $ttl = $this->redis->ttl($redisKey);
                //ttl小于0 表示key上没有设置生存时间(key是不会不存在的,因为前面setnx会自动创建)
                //如果出现这种状况,那就是进程的某个实例setnx成功后 crash 导致紧跟着的expire没有被调用
                //这时可以直接设置expire并把锁纳为己用
                if ($ttl < 0) {
                    $this->redis->set($redisKey, $expireAt);
                    $this->lockedNames[$name] = $expireAt;
                    return true;
                }
                return true;
            }

            /*****循环请求锁部分*****/
            //如果没设置锁失败的等待时间 或者 已超过最大等待时间了,那就退出
            if ($timeout <= 0 || $timeoutAt < microtime(true)) break;
            //隔 $waitIntervalUs 后继续 请求
            usleep($waitIntervalUs);

        }

        return false;
    }

    public function isLocking($name)
    {
        return key_exists($name, $this->lockedNames);
    }

    public function unlock($name)
    {
        //先判断是否存在此锁
        if ($this->isLocking($name)) {
            //删除锁
            if ($this->redis->del("Lock:$name")) {
                //清掉lockedNames里的锁标志
                unset($this->lockedNames[$name]);
                return true;
            }
        }
        return false;
    }
}

分布式锁应用

这里简单使用workerman开启多进程进行使用

<?php
require 'RedisLock.php';

class PageLock
{
    public static function plock($name, $timeout = 10, $exp = 15)
    {
        return RedisLock::onLock($name, function () {
            $aa = time();
            return $aa;
        }, $timeout, $exp);
    }

    public static function run($name)
    {
        $time = self::plock($name);
        sleep(1);
        echo $time . PHP_EOL;
    }
}

在上面的代码中 onLock是获取到锁执行代码然后释放锁,这里只是打印时间,在调用run里面进行睡眠,这里多进程都获取到了锁进行了时间打印
在这里插入图片描述

上面的代码onLock只是简单做了打印时间,咋实际业务中onLock中进行的业务会阻塞,其他进程无法获取到锁,打印的时间将不一样,能够清晰的看到使用锁的过程

在这里插入图片描述

但是这样做,多进程将变得没有意义,加锁只是为了多进程不执行同一个任务,这里需要引入redis incr进行区分性处理,每个进程获取到锁,将redis加1,根据序号执行下面的业务 如
四个进程全部获取到锁,得到的数字是1,2,3,4那么根据需要同步执行不续等待,
如对应数据库id1234,则能同时查询出4条不重复的数据

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 11:48:41  更:2022-04-04 11:48:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 7:49:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码