网站的技术建设,wordpress-,包装设计接单网站,用手机开发app文章目录简介思考lua 对 redis 的原子操作其他解决方式一些问题简介
在分布式场景高并发环境中#xff0c;无论是抢红包还是减库存#xff0c;其实本质上都是如何处理高并发中共享资源的问题#xff0c;保证高并发资源分配的安全性
相互学习#xff0c;如有错误还请指正无论是抢红包还是减库存其实本质上都是如何处理高并发中共享资源的问题保证高并发资源分配的安全性
相互学习如有错误还请指正
思考
比如抢红包的场景高并发访问数据库会给 mysql 带来较大压力因此可以考虑把红包数据放在 redis 中通过并发请求 redis 内存的红包数据来快速响应请求
但是大量请求并发访问 redis 内存数据如何保证这个资源的安全性呢肯定要用到锁或者进行某种原子操作
lua 对 redis 的原子操作
逻辑思路
首先红包创建的时候它会对应一个红包 id创建时候预先知道它要分 10 个红包那么就把总金额随机分成 10 个数字的数组预先 random 出来然后把红包 id 对应的金额数组和红包 id 对应的 10 这个库存存到 redis 中方便后续请求直接访问 redis注意 redis 中还需要维护一个 hashmap 用来判定一个用户是否领取过红包如果用于领取过就把 userId 存进 map当多个请求并发进来这里使用 lua 原子操作保证线程安全 判定用户是否领过线程 A 会线判定 map 中用户是否领取过如果领取过直接返回如果没有领取过就开始判定库存判定库存是否充足如果库存 0那么直接返回红包被抢光如果库存 0就把库存减少一然后 map 中添加上当前 userId金额 list 弹出一个红包金额 判定如果 redis 中库存为 0 就需要写入库存同时需要考虑到红包可能还有剩余因此也需要有一种定时机制把 redis 红包领取记录同步到 mysql后续业务操作最终把金额 list 弹出的金额返回给前端
其他解决方式 分布式锁 对于一些大型打公司可能有分布式锁调用的以来包这样写起来比较方便 操作先把红包库存数据导到 redis 中然后兵法请求过来查询 redis在查询前先有分布式锁的代码来看是否要阻塞如果阻塞等在运行的运行玩之后释放就可以了锁住的内容包括查询 redis 红包库存是否充足以及 redis 内存中改库存的操作。锁释放之后可以判定红包库存如果为 0 就把 redis 记录同步到 mysql 中也需要有一种定制机制定时同步 redis 到 mysql因为可能存在红包领取不完再可以进行后续业务操作。分布式锁里头的实现本质也是用了 lua 脚本保证 redis 多个操作的原子性 特点万一某个 server 实例宕机了锁就没法释放其他人就用抢红包锁住了所以需要设置一个分布式锁的超时时间 悲观锁不推荐但是实际企业开发中可能有人在用 实际开发中偷懒的程序员可能比较喜欢用因为也最简单方便 操作其实就是事务操作中进行 select for update它只能在事务中使用先锁住数据直到事务提交才会释放锁 特点没有解决大量请求打向 mysql 的问题而且完全串行执行性能很差还需要注意一旦索引失效行级锁就变成了表级锁其他操作表里其他数据的操作也被锁住了 乐观锁 操作为了解决悲观锁效率问题使用乐观锁即 A 线程先看下版本号为 1这个时候把 mysql 红包库存 - 1 且判定条件是 version 1但是突然发现 version 2 了这是因为有线程 B 并发执行完了并且把 version 再 了这时候 A 线程执行数据库失败返回 err 给到用户并且线程 A 事务会回滚这会到大量失败并且大量回归操作也给 mysql 带来压力但我们可以再稍微优化一下就是引入重试机制如果线程 A 操作数据库更新失败了按照限定时间内重试或者设置重试次数这样可以减少很多用户抢红包扣库存失败的返回 特点适合更新的并发操作不多的场景。存在出现部分并发用户被返回数据库操作 err 的情况
一些问题
数据怎么从 mysql 存入到 redis 呢 对于促销来讲我们再开发一个定时任务把符合秒杀促销条件的商品存储到 redis 中促销前定时执行触发。对于抢红包场景原代码中加上当用户创建出红包的时候就把红包库存以及红包 random 金额数组存储到 redis 中什么场景会去查找 redis 而不是直接访问 mysql 呢 高并发访问数据库时候考虑上层加一个 redisredis 如和同步到 mysql什么时机 可以通过定时任务方式定时同步到 mysql