JAVA项目笔记--黑马店铺的优惠卷秒杀

功能实现介绍:
先判断优惠卷的信息保证不过期等,为了防止一个用户多次进行插入,要结合悲观锁。故
根据userId在redis生成分布式锁,使得之后的用户请求无法实现。
生成订单。是对优惠卷的数目进行更新,可以使用乐观锁,所以在插入前,判断某个值是否满足即库存是否大于0,如果大于则继续执行,

可能出现的问题(线程安全):
1.单用户多购买:
在线程a执行插入操作时,线程b绕过了当前无订单的判断也准备执行插入操作。

2.在多用户准备进行消费卷抢购时,密集执行库存减操作导致库存出现负数。

全局id生成

alt text
生成原因:使用自增id会被恶意猜测到数据的变化,所以重要id要用一个序列串

实现:保存某个时间的时间错,减去当前的。即可获得时间序列。
获得自增id,为了保证不重复性,根据日期以天的形式对自增id进行刷新。然后左翼32位通过或操作返回序列号
alt text

返回的值是一个64位,因为long的长度是64,首位会补0

优惠卷

使用优惠卷
alt text

引发线程安全问题
alt text

乐观锁适合更新数据,而不是插入数据
alt text

乐观锁解决--CAS:
在写操作时才进行判断是否写
alt text

优惠劵--一人一单

使用synchronized实现悲观锁。
alt text

alt text

出现问题:多台服务器下,服务器间线程无法干预
alt text
使用分布式锁解决
alt text
alt text

出现问题2:当运行的时间操过过期时间,再执行删除时会将其他线程的锁删除,故在删除锁前判断锁是否属于自己。
alt text

实现:根据线程id为标识执行setnx的操作,观察锁是否被使用
解析:redis的键为用户,保证setnx单个用户只能有一把锁。值为线程id(uuid),保证了不会出现误删,防止因为时间缓慢等操作导致执行删除操作时属于自己的线程锁过期,而删除了其他的线程锁。
alt text
alt text
alt text

出现问题3:确定是自己准备进行删除时发生了延迟,导致过期又没能删除正确的。理由:非原子性,需要保证命令是一次性全部执行完,才会进行其他操作。
alt text

解决:实用lua脚本
有key和argv2个数组,第一元素是在1的位置
alt text
java实现:
设置脚本参数
alt text
在执行redis命令时携带,则会将lua脚本的命令执行,实现redis,同时支持传参数

alt text

结合redisson

可重入锁

问题产生:一个线程多次对一个锁判断,如果使用上面的setnx无法实现。
alt text

实现思路:
将redis的储存转为hash多一个value的值。在进行锁判断时要进行一个锁是否为自己的判断,所以setnx失效,同时使用value的+-实现锁的多次读取。
alt text

lua脚本--获取锁
使用了hexists先判断锁是否是自己。(用于判断一个hash值是否存在)
alt text

lua脚本--释放锁
alt text

settNx的不好
alt text

异步的操作--优化秒杀

前提:商品卷的数据都要永久保存在redis中
alt text
1.在执行写操作等耗时久的操作分离出去。
alt text
alt text

alt text

实现:
通过lua判断后确认可以下单,生成要向数据库添加的信息后加入到阻塞队列中
alt text
alt text
在redis中确认可以实现操作后,将要保存传入异步操作,进行异步处理。
在init保证资源加载成功后启动这个线程,通过阻塞队列的方式,当队列有数据时开始对数据库进行操作
alt text

redis消息队列实现秒杀

将队列存入jvm中会带来错误,比如用户以为已经成功,但是jvm崩溃导致异步队列的数据无法完成等操作。故借助redis队列实现
alt text

基于list的消息队列

lpop和blpop的区别
alt text
alt text

好处:存入到redis中是数据的持久化,就算宕机后再次启动数据仍然存在。
坏处:取出后处理过程中失败,会导致数据失效。队列的数据只允许被拿走一次。
alt text

基于pubsub的消息队列

alt text
优缺点
alt text

基于stream的消息队列

alt text
alt text
alt text
alt text
alt text

基于消息组
alt text
alt text

alt text

多个消费者在一个组内去操作一个消息队列。
将队列和组建立关联。
消费者从组中读数据,实际上是从队列s1中读取数据。末尾是 >
表示读取那些还没有被消费的队列数据
alt text

通过ack从pending-list中确认数据
alt text
查看pending-list中剩余数据
alt text
当读取的方式是读取第一个 末尾是0,会读取处于消息队列的第一个元素。这种形式就算被读取了,下次读取仍然是k6 v6,因为在pendlist中没有被处理。当ack处理后将从消息队列中消失。
alt text

alt text
alt text

实现:XGROUP CREATE stream.orders g1 9 MKSTREAM

posted @ 2025-02-20 23:16    阅读(43)  评论(0)    收藏  举报