redis加锁实现方式

思考

  • 是否有官方推荐(自己先思考如何实现,然后再参考其他人的实践,总结优缺点)
  • 通过哪些方式可以实现锁
  • 锁是否具有原子性
  • 锁请求失败了如何处理
  • 如果避免发生死锁
  • 如果避免发生资源抢占
  • 如果避免锁的误删

官方实现策略

  • 安全性能:互斥。在任何给定的时刻,只有一个客户可以持有锁
  • 活性属性A:无死锁。最终,即使锁定资源的客户端崩溃或被分区,也始终有可能获取锁
  • 活性性质B:容错性。只要大多数Redis节点都启动了,客户端就可以获取和释放锁

储备知识

原子操作

解释一

原子操作是指不会被线程调度机制打断操作,这种操作一旦开始,就一直到结束,
中间不会有任何context switch(切换到另外一个线程)

解释二

原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。
原子操作可以是一个步骤,也可以是多个步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分(不可中断性)。
将操作视作一个整体,资源在该次操作中保持一致,这是原子性的核心特征。

可用加锁命令

INCR SETNS SET

加锁命令优劣分析

INCR

实现思路

key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。
然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中

实现方式

  • 客户端A请求服务器获取key的值为1表示获取了锁
  • 客户端B也去请求服务器获取key的值为2表示获取锁失败
  • 客户端A执行代码完成,删除锁
  • 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功
  • 客户端B执行代码完成,删除锁

remark

加入过期时间是为了防止意外退出,锁没有删除,锁一直存在,以至于无法再次获取锁资源

demo

  • r e d i s − > i n c r ( redis->incr( redis>incr(key);
  • r e d i s − > e x p i r e ( redis->expire( redis>expire(key, $ttl); //设置生成时间为1秒

缺点
借住Expire设置,不再是原子操作。

SETNX

实现思路

如果key不存在,则将key设置为value,如果key已存在,则SETNX不做任何操作

实现方式

  • 客户端A请求服务端设置key的值,如果设置成功,表示加锁成功
  • 客户端B请求服务器设置key的值,如果返回失败,表示加锁失败
  • 客户端A执行代码完成,删除锁
  • 客户端B在等待一段时间后再去请求设置key值,设置成功
  • 客户端B执行代码完成,删除锁

demo

  • r e d i s − > s e t N X ( redis->setNX( redis>setNX(Kkey, $value);
  • r e d i s − > e x p i r e ( redis->expire( redis>expire(key, $ttl);

缺点
不是原子操作

非原子性潜在问题:无法实现互斥,出现单点故障时,比如说如果Redis主机坏了怎么办?好吧,
让我们增加一个假设!如果主机不可用,我们增加一个备机,请使用它。不幸的是,这是不可行的。
这样做我们就无法实现互斥的安全属性,因为Redis复制是异步的。

场景描述

  • 客户机A获取主机中的锁。
  • 在向从机发送对密钥的写入之前,主机崩溃。
  • 备机被提升为主机。
  • 客户端B获取已为其持有锁的同一资源A的锁。违反安全规定!(在A拥有锁的同时,B也用用了锁)
  • 有时,在特殊情况下,比如在故障期间,多个客户机可以同时持有锁,这是非常好的。
    如果是这种情况,则可以使用基于复制的解决方案。否则,我们建议实现本文档中描述的解决方案。

SET

实现思路

设置key的同时,这只过期时间

实现方式

  • 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
  • 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
  • 客户端A执行代码完成,删除锁
  • 客户端B在等待一段时间后在去请求设置key的值,设置成功
  • 客户端B执行代码完成,删除锁

demo
r e d i s − > s e t ( redis->set( redis>set(key, $value, array(‘nx’, ‘ex’ => $ttl)); //ex表示秒

存在问题

以上几种方式仍存在的问题
  1. redis发现锁失败了要怎么办?中断请求还是循环请求?
  2. 循环请求的话,如果有一个获取了锁,其它的在去获取锁的时候,是不是容易发生抢锁的可能?
  3. 锁提前过期后,客户端A还没执行完,然后客户端B获取到了锁,这时候客户端A执行完了,会不会在删锁的时候把B的锁给删(非原子操作的影响)
解决办法

针对问题1:使用循环请求,循环请求去获取锁
  针对问题2:针对第二个问题,在循环请求获取锁的时候,加入睡眠功能,等待几毫秒在执行循环
  针对问题3:在加锁的时候存入的key是随机的。这样的话,每次在删除key的时候判断下存入的key里的value和自己存的是否一样

 do { //针对问题1,使用循环$timeout = 10;$roomid = 10001;$key = 'room_lock';$value = 'room_'.$roomid; //分配一个随机的值针对问题3$isLock = Redis::set($key, $value, 'ex', $timeout, 'nx');//ex 秒if ($isLock) {if (Redis::get($key) == $value) { //防止提前过期,误删其它请求创建的锁//执行内部代码Redis::del($key);continue;//执行成功删除key并跳出循环}} else {usleep(5000); //睡眠,降低抢锁频率,缓解redis压力,针对问题2}
} while(!$isLock);

官方提供分布式redis锁说明

参考

【锁】redis加锁的几种方法
线程安全之原子操作
原子操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/676767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ansible copy模块 复制文件使用 主服务器 给副服务器 复制文件使用 指定文件权限 覆盖备份等

目录 参数复制文件然后进行同时复制操作 给定内容生成文件,并制定权限验证 关于覆盖先查看当前内容覆盖并备份查看文件权限 还有有没有备份查看文件内容 参数 这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。   其相关选项…

【iOS分类、关联对象】如何使用关联对象给分类实现一个weak的属性

如何使用关联对象给分类实现一个weak的属性 通过关联对象objc_setAssociatedObject中的策略policy可知,并不支持使用weak修饰对象属性: typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {OBJC_ASSOCIATION_ASSIGN 0, //assignOBJC_ASSOCIATION…

ARM交叉编译搭建SSH

首先搭建好arm-linux交叉编译环境,开发板和主机可以ping通。 一、下载需要的源码 下载zlib: zlib-1.2.3.tar.gz 下载ssl: openssl-0.9.8d.tar.gz 下载ssh: openssh-4.6p1.tar.gz 二、交叉编译 新建目录/home/leo/ssh,并且将三个源码复制到该目录下。…

Android:Volley框架使用

3.15 Volley框架使用 Volley框架主要作为网络请求,图片加载工具。当应用数据量小、网络请求频繁,可以使用Volley框架。 框架Github地址:https://github.com/google/volley Volley框架的简单使用,创建项目Pro_VolleyDemo。将Github上下载Volley框架源代码,volley-master.zi…

Linux中ps/kill/execl的使用

ps命令: ps -aus或者ps -ajx或者 ps -ef可以查看有哪些进程。加上 | grep "xxx" 可以查看名为”xxx"的进程。 ps -aus | grep "xxx" kill命令: kill -9 pid 杀死某个进程 kill -l 查看系统有哪些信号 execl函数&#…

MySQL索引分类

索引可以分为主键索引、唯一索引、常规索引、全文索引 1、主键索引 2、唯一索引 3、常规索引 4、唯一索引 1、主键索引 含义:针对于表中主键创建的索引 特点:默认自动创建,只能有一个 关键词:PRIMARY 2、唯一索引 含义&a…

JavaScript滚动事件

🧑‍🎓 个人主页:《爱蹦跶的大A阿》 🔥当前正在更新专栏:《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 滚动是网页交互不可或缺的一部分。监听页面和元素的滚动事件,可以帮助…

面试复盘——10

前言 又是低级错误挂了的。。自己还是太菜了。 而且这场的录屏没录好,没声音,我靠。 面试 先是自我介绍 先交流了实习项目 腾讯云实习项目:问到了协程当时具体是怎么用的,如何通信、如何控制协程的。 另一个实习项目&#x…

跟着cherno手搓游戏引擎【22】CameraController、Resize

前置: YOTO.h: #pragma once//用于YOTO APP#include "YOTO/Application.h" #include"YOTO/Layer.h" #include "YOTO/Log.h"#include"YOTO/Core/Timestep.h"#include"YOTO/Input.h" #include"YOTO/KeyCod…

力扣刷题之旅:进阶篇(五)—— 动态规划(DP)的妙用

力扣(LeetCode)是一个在线编程平台,主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目,以及它们的解题代码。 --点击进入刷题地址 引言: 在算法的世界中,动态规划&#xff…

ubuntu22.04@laptop OpenCV Get Started: 003_image_resizing

ubuntu22.04laptop OpenCV Get Started: 003_image_resizing 1. 源由2. resize应用Demo3 image_resize3.1 C应用Demo3.2 Python应用Demo3.3 重点过程分析3.3.1 根据宽高调整大小3.3.2 根据比例调整大小3.3.3 根据插值方式调整大小 4. 总结5. 参考资料 1. 源由 在OpenCV中调整图…

[HTTP协议]应用层的HTTP 协议介绍

目录 1.前言 2.使用fiddler抓包来观察HTTP协议格式 3.HTTP协议的基本格式 2.1请求 2,1.1首行 2.1.2请求头 2.1.3空行 2.2响应 2.2.1首行 2.2.2响应头 键值对 ​编辑2.2.3空行 2.2.4载荷(响应正文) 3.认识URL 3.1关于URL encode 1.前言 我们在前面的博客中,简单的…

力扣231. 2 的幂(数学,二分查找,位运算)

Problem: 231. 2 的幂 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 思路1:位运算 1.易验证2的幂为正数; 2.易得2的幂用二进制表示只能有一个位为数字1 3.即将其转换为二进制统计其二进制1的个数 思路2:数学 当给定数n大于1时…

DNS 域名系统——应用层

目录 1 域名系统 DNS 1.1 域名系统 1.2 互联网的域名结构 1.2.1 顶级域名 TLD(Top Level Domain) (1) 国家顶级域名 nTLD (2) 通用顶级域名 gTLD (3) 基础结构域名 (infrastructure domain) 1.3 域名服务器 1.3.1 域名服务器的四种类型 (1…

Springboot拦截器中跨域失效的问题、同一个接口传入参数不同,一个成功,一个有跨域问题、拦截器和@CrossOrigin和@Controller

Springboot拦截器中跨域失效的问题 一、概述 1、具体场景 起因: 同一个接口,传入不同参数进行值的修改时,一个成功,另一个竟然失败,而且是跨域问题拦截器内的request参数调用getHeader方法时,获取不到前端…

JAVA设计模式之代理模式详解

代理模式 1 代理模式介绍 在软件开发中,由于一些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称为"代理"的第三者来实现间接访问.该方案对应的设计模式被称为代理模式. 代理模式(Proxy Design Pattern ) 原始定义是:让你能够提供对象的替代…

代码随想录算法训练营29期|day41 任务以及具体任务

第九章 动态规划part03 343. 整数拆分 class Solution {public int integerBreak(int n) {//dp[i] 为正整数 i 拆分后的结果的最大乘积int[] dp new int[n1];dp[2] 1;for(int i 3; i < n; i) {for(int j 1; j < i-j; j) {// 这里的 j 其实最大值为 i-j,再大只不过是重…

单片机学习笔记---DS1302时钟

上一节我们讲了DS1302的工作原理&#xff0c;这一节我们开始代码演示。 新创建一个工程写上框架 我们需要LCD1602进行显示&#xff0c;所以我们要将LCD1602调试工具那一节的LCD1602的模块化代码给添加进来 然后我们开始创建一个DS1302.c和DS1302.h 根据原理图&#xff0c;为了…

Java项目:19 基于SpringBoot的医院管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 医院管理系统 分为三个角色 管理员、医生、病人 管理员的主要功能&#xff1a;系统管理、医生管理、患者管理、预约管理、病史管理、住院信息管理、管…

ARM PAC/BTI/MTE三剑客精讲与实战

一、PAC指针认证精讲与实战 思考 1、什么是栈溢出攻击&#xff1f;什么是代码重用攻击&#xff1f;区别与联系&#xff1f; 2、栈溢出攻击的软&硬件缓解技术有哪些&#xff1f;在TF-A&OPTEE上的应用&#xff1f; 3、什么是ROP攻击&#xff1f;对ROP攻击的缓解技术&…