电商模板网站免费个人做外贸网站平台有哪些

当前位置: 首页 > news >正文

电商模板网站免费,个人做外贸网站平台有哪些,网站快照时间,花都有沒有网站建设的目录 一、Redis 分布式锁 1.1、什么是分布式锁 1.2、分布式锁的基础实现 1.2.1、引入场景 1.2.2、基础实现思想 1.2.3、引入 setnx 1.3、引入过期时间 1.4、引入校验 id 1.5、引入 lua 脚本 1.5.1、引入 lua 脚本的原因 1.5.2、lua 脚本介绍 1.6、过期时间续约问题看门狗 Watch Dog 1.7、引入 redlock 算法 1.8、分布式锁扩展 一、Redis 分布式锁 1.1、什么是分布式锁 锁就是用来解决线程安全的分布式锁又是什么呢 之前所学过的 synchronized 本质上都是只能在一个进程内部生效的而在分布式系统中是有很多进程的每个服务器都是一个独立的进程多个进程之间的执行顺序也是不确定的随机的 之前的锁就很应对分布式系统中多个进程之间产生的制约. 因此就需要引入 “分布式锁” 来解决上述问题. 分布式锁本质上就是一个公共的服务器用来记录锁的状态。 Ps这个公共的服务器可以是Redis, 也可以是其他组件(比如 MySQL 或者 ZooKeeper 等), 还可以是我们自己写的⼀个服务 1.2、分布式锁的基础实现 1.2.1、引入场景 想象这样一个场景买车票. 实现思路先查询剩余票数如果剩余票数 0则设置剩余票数 - 1. 在没有引入分布式锁之前就有可能出现以下买票场景 客户端1 先执行查询余票发现剩余 1 张在即将执行 剩余票数 - 1 过程之前客户端2 也执行了查询余票发现也是剩余 1 张客户端2  也会执行 剩余票数 - 1. 的过程. 这里就出现了 “超卖” 的场景1 张票卖给了两个人. 1.2.2、基础实现思想 分布式锁的实现思路很简单本质上是使用一个/一组 单独的服务器程序通过用一个键值对来标识锁的状态来给其他服务器提供 “加锁” 这样的服务. 对于上述场景进行买票操作过程中就需要先加锁. 具体的往 redis 上设置一个特殊的 key - value接着完成买票操作再把这个 key - value 删除掉.  如果在 客户端1 买票的期间客户端2 也想去买票就也会尝试设置 key - value如果发现  key - value 已经存在就分为 “加锁失败”是放弃还是阻塞就要看具体的实现策略了. 这样就保证了 第一个服务器执行 “查询 - 更新” 过程中第二个服务器不会执行 “查询” 也就解决了上述 “超卖” 问题. Ps买票的场景使用 mysql 的事务也可以批量执行 查询 修改 操作. 但是分布式系统中要访问的共享资源不一定是 mysql ……. 也可能是其他存储介质没有事务. 也可能是执行一段特定的操作是通过统一的服务器完成指定动作. 1.2.3、引入 setnx 针对于刚刚买票的场景“key 不存在就设置成功不存在就设置失败”. 使用 setnx 就可以达到 “加锁” 的效果. 针对解锁就可以使用 del 命令来完成. 如果某个服务器加锁成功了setnx 成功执行后续逻辑中还没来得及执行 “解锁” 程序就崩溃了怎么办 以前在一个进程中为了保证解锁的操作能执行到可以把解锁的操作放到 finally 中但是这种做法只是针对进程内的锁有效针对分布式锁无效 比如服务器直接掉电进程直接异常终止这就会导致 redis 上设置的 key 无人删除也就导致其他服务器无法获取到锁了. 1.3、引入过期时间 针对上述 “没来得及解锁服务器宕机的情况”我们可以给 key 设置一个过期时间. 通过 set ex nx 这样的命令完成设置一旦时间到了key 就会自动被删除掉. 比如设置 key 的过期时间为 1000ms那么即使出现极端情况某个服务器挂了没有真正释放锁这个锁最多保持 1000ms也就自动释放了. 可以通过先 setnx 再使用 expire 的方式设置过期时间么 不可以务必要使用 set ex nx 的方式来设置 redis 上多个命令之间无法保证原子性即使使用 事务也不能保证这两个操作都能成功redis 的事务只能保证不被 “插队”不能保证操作成功. 此时就有可能出现 setnx 成功expire 失败的场景. 1.4、引入校验 id 所谓锁就是 redis 上的普通键值对. 所谓加锁就是给 redis 上设置一个 key - value. 所谓解锁就是把 redis 上这个 key - value 删除掉. 是否可能出现 服务器1  执行了加锁服务器2 执行了解锁 正常来说肯定不是故意的但是代码总会有 bug不小心执行了解锁操作就让这锁形同虚设带来严重后果比如 超卖. 为了解决上述问题就需要引入一点校验机制. 具体的如下步骤

  1. 给服务器编号让每个服务器都有一个自己的身份标识.
  2. 进行加锁的时候设置 key - value key 就表示要针对哪个资源加锁value 就表示服务器的编号. 后续在解锁的时候就可以进行校验了.  解锁的时候先查询一下这个锁对应的服务器编号然后判定这个编号是否就是当前执行解锁的服务器编号如果是才真正执行 del如果不是就失效. 通过上述操作就可以有效避免 “误解锁”. 1.5、引入 lua 脚本 1.5.1、引入 lua 脚本的原因 一个服务器内部也可能是多线程的. 此时就可能两个线程都在执行 “解锁” 操作. 例如如下场景  首先我们知道解锁的操作分为两步先通过 GET 服务器编号进行校验校验成功后在进行 DEL. 在 服务器1 中线程A 执行 GET 后 线程 B 也执行 GET然后 线程A 执行 DEL 解锁此时 线程 B 也执行 DEL 解锁. 上述情况看起来好像重复执行 DEL 好像问题不大实则不然 如果此时还有一个服务器执行加锁就可能出问题了. 在 线程A 执行完 DEL 之后线程 B 执行 DEL 之前服务器2 的 线程C 正好要执行 加锁(set ex nx)此时由于 A 已经解锁了C 的加锁能成功但是紧接着线程 B DEL 就来了就把 服务器2 刚刚的加锁操作给解除了. 归根结底还是因为 get 和 del 不是一条原子操作产生的问题. 使用事务虽然可以解决上述问题redis 事务虽然弱但是能够避免插队但是实践中往往使用更好的方案 —— lua 脚本. 1.5.2、lua 脚本介绍 lua 语言特别轻量实现一个 lua 解释器消耗的体积非常小可以使用 lua 编写一些逻辑把这个脚本上传到 redis 服务器上然后就可以让客户端来控制 redis 执行上述脚本了. 最重要的一点就是redis 执行一个 lua 脚本就相当于在 redis 上执行一个命令一样是原子的. 并且 redis 官方文档中也明确说lua 就属于是 事务 的替代方案. 例如前面的 “买票” 案例. if redis.call(get,KEYS[1]) ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end; ARGV[1]表示调用脚本给定的参数此处要传入一个服务器的 id. 如果 id 和 get 到参数匹配就进行删除操作. 1.6、过期时间续约问题看门狗 Watch Dog 加锁的时候给 key 设定 过期时间设置成多少合适 如果设置的时间过短就可能在 业务逻辑 还没有执行完就释放锁了.如果设置的时间太长就可能导致 “锁释放的不及时” 的问题. 最好的方式就是 “动态续约”. 具体的初始情况下设置一个过期时间比如 1s在还剩 300ms 的时候这里的时间不一定是 300ms数据灵活调整如果当前任务还没有执行完就把过期时间续上 1s等到时间快到了任务还没执行完就再续无限续杯~ 上述过程中如何知道当前任务还没有执行完要进行续杯呢实际上服务器这边有一个专门的线程负责续约这个事情这个线程也叫做 “看门狗”这是一个比较广义的概念很多涉及到过期时间的操作都会引入 “看门狗” . 这样即使服务器中途崩溃了没人负责续约了锁也能在短时间内自动释放. 这就好比吃自助餐老板都是鼓励大家每次少拿点少量多次  怕的就是你一次拿太多吃不完大部分都剩下了. 如果每次少拿点即使吃不下了浪费的也不多了. 1.7、引入 redlock 算法 使用 redis 作为分布式锁redis 本身有没有可能挂了呢 是很有可能的 实际工作中的 redis 都是以集群的方式部署的至少是主从不会是单机那么就有可能出现以下大冤种的情况 服务器1 向 master 节点进行加锁操作. 这个写⼊ key 的过程刚刚完成, master 挂了; slave 节点升级成了新的 master 节点. 但是由于刚才写⼊的这个 key 尚未来得及同步给 slave主节点和从节点之间的数据同步是存在延迟的, 此时 就相当于服务器1 的加锁操作形同虚设了, 服务器2 仍然可以进行加锁. 为了解决以上问题就提出了 redlock 算法redis 作者给出的方案 此处加锁就是按照一定的顺序针对这组 redis 都进行加锁操作. 如果某个节点加不上锁没关系可能是 redis 挂了继续给下一个节点加锁即可.如果写入 key 成功的节点个数超过总数的一半就视为 加锁成功.同理进行解锁的时候也会把上述节点都解锁一遍. 1.8、分布式锁扩展 上面介绍的只是简单的 “互斥锁”. 锁这里还涉及到一些其他情况 1.  读写锁. 2.  公平锁. 3.  可重入锁 …….. 基于 redis 也可以实现上述锁的特性这里大家下来可以自己尝试实现以下