做企业网站后期还需要费用吗vps服务器购买
- 作者: 五速梦信息网
- 时间: 2026年04月18日 10:01
当前位置: 首页 > news >正文
做企业网站后期还需要费用吗,vps服务器购买,wordpress判断手机电脑,百度 网站描述概述
在《20.Redis原子操作》我们提到了应对并发问题时#xff0c;除了原子操作#xff0c;还可以通过加锁的方式#xff0c;来控制并发写操作对共享数据的修改#xff0c;从而保证数据的正确性。
但是#xff0c;Redis 属于分布式系统#xff0c;当有多个客户端需要争…概述
在《20.Redis原子操作》我们提到了应对并发问题时除了原子操作还可以通过加锁的方式来控制并发写操作对共享数据的修改从而保证数据的正确性。
但是Redis 属于分布式系统当有多个客户端需要争抢锁时我们必须保证这把锁不能是某个客户端的本地锁。否则其他客户端是无法访问这把锁的。
Redis 本身可以被多个客户端共享访问正好就是一个共享存储系统可以用来保存分布式锁。而且 Redis 的读写性能高可以对应高并发锁操作的场景。 1.单机上的锁和分布式锁的联系和区别
对于单机上运行的多线程来说锁本身可以用一个变量表示
变量值为 0 时表示没有线程获取锁。变量值为1 时表示已经有线程获取到锁了。
一个线程调用加锁操作其实就是检查锁变量是否为 0。如果是 0就把锁变量值设置为 1表示获取到锁如果不是 0就返回错误信息表示加锁失败已有其他线程获取到锁了。而一个线程释放锁操作其实就是将锁变量的值置为 0以便其他线程可以用来获取锁。
用一段伪代码来表示加锁和释放锁的操作其中 lock 为锁变量。
acquire_lock() {if lock 0lock 1return 1elsereturn 0
}release_lock() {lock 0return 1
}和单机删的锁类似分布式锁同样可以用一个变量来表示。客户端加锁和释放锁的操作逻辑也和单机上的加锁和释放锁操作逻辑一致加锁时同样需要判断锁变量的值根据锁变量值来判断能否加锁成功释放时需要把锁变量值设置为 0表名客户端不再持有锁。
但是和线程在单机上操作锁不同的是在分布式场景下锁变量需要由一个共享存储系统来维护。只有这样多个客户端才可以通过访问共享存储系统来访问锁变量。相应的加锁和释放锁的操作就变成了读取、判断和设置共享存储系统中的锁变量。
这样一来我们就可以得出实现分布式锁的两个要求
要求一分布式锁的加锁和释放锁的过程涉及多个操作。所以在实现分布式锁时我们需要保证这些锁操作的原子性。要求第二更新存储系统保存了锁变量如果共享存储系统发生故障或宕机那么客户端也就无法进行锁操作。在实现分布式锁时我们需要考虑保证共享存储系统的可靠性进而保证锁的可靠性。
2.基于单个 Redis 节点实现分布式锁
作为分布式锁实现过程中的共享存储系统Redis 可以使用键值对来保存锁变量在接收和处理不同客户端发送的加锁和释放锁的操作请求。那么键值对的键和值具体是怎么定的呢
加锁过程
如下图所示Redis 使用键值对保存锁变量以及两个客户端同时请求加锁的操作过程。 可以看到Redis 可以使用一个键值对 lock_key:0 来保存锁边量其中键是 lock_key也是锁边变量的名称锁变量的初始值是 0。
在图中客户端 A 和 C 同时请求加锁。因为 Redis 使用单线程处理请求所以即使客户端 A 和 C 同时把加锁请求发给了 RedisRedis 也会串行处理他们的请求。
假设 Redis 先处理客户端 A 的请求读取 lock_key 的值发现 lock_key 为 0所以Redis 就把 lock_key 的 value 值置为 1表示已经加锁了。紧接着Redis 处理客户端 C 的请求此时Redis 发现 lock_key 的值已经为 1 了所以就返回加锁失败的信息。
释放锁过程
下图展示的是客户端 A 请求释放锁的过程。当客户端 A 持有锁时锁变量 lock_key 的值为 1。客户端 A 执行释放锁操作后Redis 将 lock_key 的值置为 0表示已经没有客户端持有锁了。
Redis 分布式锁的原子性保证
《20.Redis原子操作》我们学过了要想保证操作的原子性有两种通用的方法分别是 Redis 单命令操作和使用 Lua 脚本。分布式加锁场景下如何应用这两个方法呢
Redis 可以用哪些单命令实现加锁操作
首先是 SETNX 命令它用于设置键值对的值这个命令在执行时会判断键值对是否存在如果不存在就不做任何设置。
SETNX key value对于释放锁来说我们可以在执行完业务逻辑后使用 DEL 命令删除所变量。不过你不用担心锁变量被删除后其他客户端无法请求加锁了。因为 SETNX 命令在执行的时候如果要设置的键值对不存在SETNX 会先创建键值对然后设置它的值。所以释放锁之后再有客户端请求加锁时SETNX 命令会创建锁变量的键值对并设置锁变量的值完成加锁。
总结来说可以用 SETNX 和 DEL 命令组合来实现加锁和释放锁操作。
// 加锁
SETNX lock_key 1
// 业务逻辑
DO THINGS
//释放锁
DEL lock_key不过用 SETNX 和 DEL 命令组合来实现分布式锁存在两个潜在风险
第一个风险是假如某个客户端在执行 SETNX 命令、加锁后紧接着发生了异常结果一致没有执行 DEL 命令释放锁。因此锁就一直被这个客户端持有其他客户端无法拿到锁也无法访问共享数据和执行后续操作。 针对这个问题一个办法是给锁变量设置一个过期时间。这样一来即使持有锁的客户端发送了异常无法主动地释放锁Redis 也会根据锁变量的过期时间在锁变量过期后把它删除。其他客户端在锁变量过期后就可以重新请求加锁。 第二个风险。如果客户端执行了 SETNX 命令加锁后假设客户端 B 执行了 DEL 命令释放锁此时 客户端 A 的锁程序就被误释放了。如果客户端 C 正好也在申请加锁就能获得锁进而开始操作共享数据。这样一来客户端 A 和 C 同时在对共享数据进行操作数据就会被修改错误。 应对第二个风险需要可以区分来自不同客户端的操作。也就是在加锁操作时可以让每个客户端给锁变量设置一个唯一值这里的唯一值可以用来标识当前操作的客户端。在释放锁时客户端需要判断当前锁变量的值是否和自已的唯一标识符相等只有在相等的清理下才能释放锁。这样就不会出现误释放的问题了。
在 Redis 中可以使用 SET 命令以及 NX 和 EX/PX 的选项实现加锁操作。
// 加锁unique_value 作为客户端唯一性的标识
SET lock_key unique_value NX PX 10000NXSET 命令的 NX 选项可以实现类似于 SETNX 的效果即对于不存在的键值对它会先创建再设置值对于已存在的则不做任何操作。 PX 10000SET 命令的 PX 选项可设置键值对的过期时间。另外key 的存活时间由 seconds 或者 milliseconds 选项值来决定。 PX 10000 表示 lock_key 会在 10 秒后过期。 因为加锁后每个客户端都使用了一个标识符所以在释放锁的过程中我们需要判断锁变量的值是否等于执行加锁操作的客户端唯一标识
// 释放锁 比较unique_value是否相等避免误释放
if redis.call(get, KEYS[1] ARGV[1]) thenreturn redis.call(del, KEYS[1])
elsereturn 0
end这是使用 Lua 脚本实现的释放锁操作的伪代码其中 KEYS[1] 表示 lock_keyARGV[1] 表示当前客户端的唯一标识这两个值都是我们在执行 Lua 脚本时作为参数传入的。
最后再执行下面的命令就可以完成释放锁操作了。
redis-cli –eval lua.script lock_key , unique_value你可能注意到了我们在释放锁时使用了 Lua 脚本这是因为释放锁操作的逻辑也包含了读取锁变量、判断值、删除锁变量的多个操作通过 Redis 的 Lua 脚本保证了释放锁操作的原子性。 注意的是 除了上述情况外还可能会出现的风险 要根据业务的情况设定好锁的过期时间。锁过期时间设置的太短。线程 A 加锁后任务还没有执行完锁变量就过期了。此时线程 B 通过加锁操作成功获得了锁。 这会导致线程 A 和 线程 B 同时操作了共享数据导致数据的不一致。避免加锁后业务执行的时间过长。其实和 1 中的风险类似如果业务执行时间过长此时锁过期了也会出现 两个线程同时操作共享数据的问题。 3. 基于 Redis 实现高可靠的分布式锁
要实现高可靠的分布式锁就不能只依赖单个的命令操作了我们要按照一定的步骤和规则进行加解锁操作否则就可能出现锁无法工作的情况。“一定的步骤和规则”其实就是分布式锁的算法。
为了避免 Redis 实例故障而导致的锁无法工作的问题Redis 开发者 Antirez 提出了分布式锁算法 Redlock。
Redlock 算法的基本思路是让客户端和多个独立的 Redis 实例一次请求加锁如果客户端和半数以上的实例成功的完成加锁操作那么我们就认为客户端成功地获得分布式锁了否则加锁失败。这样一来及时有单个 Redis 实例发生故障因为锁变量在其他实例上也有保存所以客户端仍然可以正常的进行所操作锁变量并不会丢失。
看下 Redlock 算法的执行步骤。Redlock 的算法实现需要有 N 个独立的 Redis 实例。接下来我们可以分成 3 步来完成加锁操作。 第一步客户端获取当前时间。 第二步客户端按顺序依次项 N 个 Redis 实例执行加锁操作。 这里的加锁操作和在单实例上的加锁操作一样使用了 SET 命令带上 NX EX/PX 选项以及带上客户端的唯一标识。当然如果某个 Redis 实例发生故障了为了保证这种情况下 Redlock 算法能够继续运行我们需要给加锁设置一个超时时间。 如果客户端在和一个 Redis 实例请求加锁时一直到超时都没有成功那么此时客户端会和下一个 Redis 实例继续请求加锁。加锁操作的超时时间需要远远小于锁的有效时间一般也就设置几十微妙。 第三步一旦客户端完成了和所有 Redis 实例的加锁客户端要计算整个加锁操作过程的总耗时。 客户端只有在满足下面的两个条件是才认为加锁成功。 条件一客户端从超过半数大于等于 N/2 1的 Redis 实例上成功获取到了锁条件二客户端获取锁的总耗时没有超过锁的有效时间。
在满足了这两个条件后我们需要重新计算这把锁的有效时间计算的结果是锁的最初有效时间减去客户端为获取锁的总耗时。如果锁的超时时间已经来不及完成共享数据的操作了我们可以释放锁以免出现还没有完成数据操作锁就过期了的情况。
当然如果客户端在和所有实例执行完加锁操作后没能同时满足这两个条件那么客户端向所有 Redis 节点发起释放锁的操作。
所以在实际的业务应用中如果你想要提升分布式锁的可靠性就可以通过 Redlock 算法来实现。
小结
分布式锁是由共享存储系统维护的变量多个客户端可以向共享存储系统发送命令进行加锁或释放锁操作。Redis 作为共享存储系统可以用来实现分布式锁。
在基于单个 Redis 实例实现分布式锁时对于加锁操作我们需要满足三个条件。
加锁包括了读取锁变量、检查锁变量和设置锁变量三个操作但需要已原子操作的方式完成所以使用 Set 命令带上 NX 选项来实现加锁。锁变量需要设置过期时间以免客户端拿到锁后发生异常导致锁一直无法释放所以我们在 SET 命令执行时加上 EX/PX 选项设置其过期时间。锁变量的值要能区分来不不同客户端的加锁操作以免在释放锁时出现误释放操作所以我们使用 SET 命令设置锁变量值时每个客户端设置的值是一个唯一的值用于标识客户端。
和加锁类型释放锁也包含了读取锁变量值、判断锁变量值和删除锁变量的三个操作不过我们无法使用单个命令来实现所以采用 Lua 脚本来执行释放锁操作通过 Redis 原子性的 Lua 脚本来保证释放锁操作的原子性。
不过基于单个 Redis 实例实现分布式锁时会面临实例异常或崩溃的情况这会导致实例无法提供锁操作正因为此Redis 也提供了 Redlock 算法用来实现基于多个实例的分布式锁。这样一来锁变量由多个实例维护及时有实例发生了故障锁变量仍然是存在的客户端还是可以完成锁操作。Redlock 算法是实现高可靠分布式锁的一种有效解决方案你可以在实际应用中把它用起来。 如果为了效率使用基于单个 Redis 节点的分布式锁即可此方案缺点是允许锁偶尔失效优点是简单效率高 如果是为了正确性业务对于结果要求非常严格建议使用 Redlock但缺点是使用比较重部署成本高 番外
使用单个 Redis 节点只有一个master使用分布锁如果实例宕机那么无法进行锁操作了。那么采用主从集群模式部署是否可以保证锁的可靠性
其实也是很难保证的。如果在 master 上加锁成功此时 master 宕机由于主从复制是异步的加锁操作的命令还未同步到 slave此时主从切换新 master 节点依旧会丢失锁对也业务来说相当于锁失效了。
Kaito 大神对分布式锁做了深入的剖析有兴趣的可以看下《深度剖析Redis分布式锁到底安全吗看完这篇文章彻底懂了》。
- 上一篇: 做企业网站公司c 语言可以做网站吗
- 下一篇: 做企业网站所要注意什么随机置顶wordpress
相关文章
-
做企业网站公司c 语言可以做网站吗
做企业网站公司c 语言可以做网站吗
- 技术栈
- 2026年04月18日
-
做企业网站的要点宁波制作网站的公司
做企业网站的要点宁波制作网站的公司
- 技术栈
- 2026年04月18日
-
做企业网站的费用挂什么科目婚介网站建站
做企业网站的费用挂什么科目婚介网站建站
- 技术栈
- 2026年04月18日
-
做企业网站所要注意什么随机置顶wordpress
做企业网站所要注意什么随机置顶wordpress
- 技术栈
- 2026年04月18日
-
做企业网站项目wordpress wpoptions
做企业网站项目wordpress wpoptions
- 技术栈
- 2026年04月18日
-
做企业网站需要提供什么资料网站窗口代码
做企业网站需要提供什么资料网站窗口代码
- 技术栈
- 2026年04月18日
