Redis项目实战——优惠券秒杀

目录

  • Redis自增功能解决全局唯一ID
  • Redis实现优惠券秒杀的主要思路
  • 实现过程中出现的问题及解决方法
    • 超卖问题
      • 方案1 悲观锁
      • 方案2 乐观锁
    • 一人一单问题
      • 分布式锁
        • 如何用Redis实现分布式锁?
    • Redis优化秒杀
    • 消息队列实现异步秒杀
      • List
      • 发布订阅模式
      • Stream

Redis自增功能解决全局唯一ID

  • 如果用MySQL的自增长ID,ID的规律性太明显,会暴漏一些信息(比如销量等)
  • 数据量太大时一张表存不下,需要多张表,MySQL多张表的自增长都是独立的,会出现重复ID
  • 需要一种在分布式系统下可以生成全局唯一ID的工具,必须唯一且递增
  • 在某项目里,不管数据库的表有多少个,Redis只有一个,因此Redis递增功能生成的ID一定是全局唯一的
  • 为了保证递增的同时且没有规律,保证安全性,可以在Redis自增数值的基础上拼接一些其它信息
    在这里插入图片描述

Redis实现优惠券秒杀的主要思路

在这里插入图片描述

实现过程中出现的问题及解决方法

超卖问题

  • 在高并发场景下,多个线程同时操作共享的资源(库存),导致实际卖出的数量超出了库存数量

方案1 悲观锁

  • 态度比较悲观,认为线程安全问题肯定会发生,在操作数据之前提前获取锁
  • 例子:Synchronized、Lock
  • 优点:安全性高
  • 缺点:性能低,实现简单

方案2 乐观锁

  • 态度比较乐观,认为线程安全问题不一定会发生,因此不加锁,只在数据更新时去判断在它之前有没有其它线程修改数据。如果没有修改认为是安全的,直接更新数据,如果已经被修改说明不安全,重试或报异常
  • 版本号法:给库存增加一个版本字段,线程1查询并记录下库存和版本号,然后将库存-1,版本号+1,来表示线程1修改了一次数据,然后在更新数据之前再判断一下版本号,是否是自己当时记录的版本号+1,若是,说明没有并发线程在期间修改过数据,安全,可以放心更新,若不是,说明正好有并发线程在期间修改过了数据,不安全,重试或者报异常
  • CAS法:版本号法的简化版本,去掉版本号这个多余的字段,直接用库存本身代替版本号,根据库存本身有没有发生变化来确定是否更新
  • 优点:性能高
  • 缺点:实现复杂

一人一单问题

  • 常见的业务问题,要求同一个优惠券,一个用户只能下一单
  • 在库存充足判断成功后再增加一个判断,用用户ID和优惠券ID联合查询,来判断该用户是否已经买过一优惠券
  • 在单机模式下,可以加Synchronized锁来保证线程安全
  • 在集群模式下,Synchronized锁无效,需要用分布式锁来确保线程安全。Synchronized锁无效的原因是因为每台服务器有自己的常量池,锁监视器便保存在常量池中,用户尝试获取锁便是访问锁监视器,因此,主要问题是因为多个服务器的锁监视器是独立的,所以多个服务器上的用户能在同一时刻同时获取锁,进而导致线程安全问题

分布式锁

  • 在单机情况下,只有一个JVM,JVM中只有一个锁监视器,只有一个程序可以获取到锁。但在集群情况下,有多个JVM,多个JVM中有多个锁监视器,程序可以获取到多个锁,甚至同一个程序也可以获得多个锁,就会出现线程安全问题
  • 需要在多个JVM之外做一个共享的 多进程可见的 互斥的 锁监视器——分布式锁
  • 实现分布式锁的三大方式:MySQL、Redis、Zookeeper,MySQL和Zookeeper比Redis安全性更好,Redis性能比二者更好
    在这里插入图片描述

如何用Redis实现分布式锁?

  • 获取互斥锁:SET lock thread1 NX EX 10,NX是互斥,确保只有一个线程可以获取到锁,EX是设置超时时间。
  • 释放锁:直接手动删除。
  • 死锁问题:若获取到锁后线程宕机,容易出现死锁,应该增加过期时间,超时自动释放锁。
  • 误删问题:若线程1获取到锁,但业务执行时间过长,超过了TTL,会自动释放锁,此时线程2尝试获取锁成功,并正常执行业务,但期间线程1业务执行完毕,正常执行释放锁操作,此时就会把线程2的锁误删。为了避免这种情况,应该在获取锁时增加一个标识,来表示谁占有了这个锁,且只有它才有资格释放锁,因此在释放锁之前需要增加判断步骤
  • 基于setnx实现的分布式锁存在的问题:不可重入(同一个线程无法多次获取同一把锁),不可重试(获取锁只尝试一次,失败不会重试),超时释放(业务执行耗时较长会导致锁释放,存在安全隐患)
  • Redission组件:Redis基础上实现的分布式工具集合

Redis优化秒杀

  • 优化主要思路:将涉及到数据库的减库存创建订单等耗时操作用异步独立线程慢慢做,Redis只需要判断用户有没有抢成功并返回结果
  • 原来的秒杀流程:主要是Tomcat里面的一系列操作,有四个会直接操作数据库,耗时非常久。相当于一个饭店,来了一位顾客,派了一个服务员为这位顾客一条龙服务,从点菜(查询秒杀资格)到做饭(减库存和创建订单)都是这一个服务员做,效率非常低下。
  • 优化后的秒杀流程:在NGINX和Tomcat之家增加Redis,用于判断该用户能不能抢上优惠券,并将判断结果和优惠券id、用户id、订单id一起保存到阻塞队列,然后Tomcat从队列中读取消息,进行比较耗时的减库存和创建订单操作
    在这里插入图片描述
  • 其中Redis判断秒杀库存的操作可以封装到Lua脚本中执行,以确保该操作的原子性
    在这里插入图片描述
  • 基于阻塞队列的异步秒杀存在的问题?
  • 阻塞队列用的时JDK的,会占用JVM内存,大量消息会造成内存溢出

消息队列实现异步秒杀

  • 消息队列:存储管理消息
  • 生产者:发送消息到消息队列
  • 消费者:从消息队列获取消息并处理消息
  • Redis实现消息队列的三种方式:List、发布订阅模式、Stream

List

  • 链式的双端队列,LPUSH存,RPOP取,但并没有阻塞效果(队列空时不会阻塞等待),BRPOP有阻塞效果。
  • 优点:独立于JVM存在,不占JVM内存,不担心上限,且可以持久化,还能保证消息有序性
  • 缺点:无法避免消息丢失,只支持一对一

发布订阅模式

  • 消费者订阅一个或多个channel,生产者向对应channel发送消息
  • 优点:支持一对多,一个生产者可以把消息发给多个消费者。天生支持阻塞
  • 缺点:不支持数据持久化,无法避免消息丢失,消息堆积有上限

Stream

  • 优点:消息可回溯,支持一对多,支持阻塞读取
  • 缺点:可能会漏读消息
  • 消费者组:将多个消费者划分到一个组中,监听同一个消息队列,那么多个消费者就会竞争这些消息,可以加快处理消息的速度,避免消息堆积。消费者组还会维护一个标识,记录最后一个被处理的消息,可以很快恢复突发情况,避免漏读消息。此外,消费者拿到消息后,Redis并不会直接不管这条消息,而是将消息置为pending状态,表示这条消息取上了但还没处理完,处理完后通过XACK确认消息,标记为已处理,此时Redis才会放心地把消息从队列中移除,可以防止消息丢失。
  • 消费者组优点:消息可回溯,可以多消费者争抢消息,加快消费速度,可以阻塞读取,不会漏读消息,有消息确认机制,保证消息至少被消费一次

三种消息队列对比总结
在这里插入图片描述

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

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

相关文章

MySql013——函数

一、数据处理函数 1.1、文本处理函数 函 数 说 明 Left() 返回串左边的字符Length() 返回串的长度Locate() 找出串的一个子串Lower() 将串转换为小写LTrim() 去掉串左边的空格Right() 返回串右边的字符RTrim() 去掉串右边的空格Soundex() 返回串…

React 钩子汇总

React 钩子 一、常用的 React 钩子: 1. useState 用于在函数式组件中添加状态管理。它返回一个状态值和一个更新状态的函数,让你可以在组件中追踪和更新状态。 2. useEffect 用于在组件渲染完成后执行副作用操作,比如数据获取、订阅等。…

Relation Extraction as Open-book Examination: Retrieval-enhanced Prompt Tuning

本文是LLM系列文章,针对《Relation Extraction as Open-book Examination: Retrieval 关系提取作为开卷测试:检索增强提示调整 摘要1 引言2 方法3 实验4 相关工作5 结论 摘要 经过预训练的语言模型通过表现出显著的小样本学习能力,对关系提取…

基于python的反爬虫技术的研究设计与实现

摘 要 当下的网络是复杂的,网络上的信息非常的丰富,但也造成了大量的信息堆积,特别是大量的重复信息被反复的推送给用户。这是一个流量的时代,很多社会群体都会聚焦具备流量潜力的信息,从而发生蹭热度等行为来提升自己…

Windows环境下的Tomcat服务器安装和配置教程,包括外网远程访问的设置方法

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器,不仅名字很有趣&#xff0…

Docker consul 容器服务自动发现和更新

目录 一、什么是服务注册与发现 二、Docker-consul集群 1.Docker-consul consul提供的一些关键特性 2.registrator 3.Consul-template 三、Docker-consul实现过程 以配置nginx负载均衡为例 先配置consul-agent ,有两种模式server和client 四、Docker-cons…

ChatGPT HTML JS Echarts实现热力图展示

热力图是一种常用的数据可视化图表,主要用于展示数据的分布和密度情况。它通过使用不同颜色的热点来表示数据在地理或二维空间上的分布情况,从而直观地显示出数据的密集程度和趋势。 热力图的功能和作用如下: 1. 数据分布展示:热力图可以将大量数据以热点的形式展示在地理…

K8s 持久化存储有几种方式?一文了解本地盘/CSI 外接存储/K8s 原生存储的优缺点

当今云原生环境中,Kubernetes(K8s)已成为既定的容器编排工具。随着 K8s 的普及,存储也成为 K8s 用户关注的一个重要问题:为了满足不同的场景需求,K8s 可以支持基于不同架构的多种存储方案。这些方案间有什么…

Spark与Flink的区别

分析&回答 (1)设计理念 1、Spark的技术理念是使用微批来模拟流的计算,基于Micro-batch,数据流以时间为单位被切分为一个个批次,通过分布式数据集RDD进行批量处理,是一种伪实时。 2、Flink是基于事件驱动的,是面向流的处理框架, Flink基于…

0基础学习VR全景平台篇 第95篇:VR实景智慧导航操作手册

一、实景导航前期准备工作及点位采集 (一)实景导航前期准备工作 (1)拍摄设备 1.推荐相机:全画幅的佳能 Canon EOS​ 5D Mark IV 2.搭配镜头:原厂的佳能 Canon EF卡口 8-15mm 全画幅鱼眼镜头 3.三角架 …

vue3中的useAttrs和props的区别

在vue3中&#xff0c; 提供了一个 useAttrs 的方法 它接收到的参数一 prop中可以接收到的数据是基本一样的 如果我们想自已写一个组件&#xff0c; 把 elementPlus 中的期中一个组件封装一下。 可以这样做 1.新建一个 自定义组件 myBtnCom <template><div class"…

Java:SpringBoot实现定时任务Scheduled

代码示例 package com.example.demo.config;import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled;import java.text.SimpleDate…

stencilJs学习之构建 Drawer 组件

前言 在之前的学习中&#xff0c;我们已经掌握了 stencilJs 中的一些核心概念和基础知识&#xff0c;如装饰器 Prop、State、Event、Listen、Method、Component 以及生命周期方法。这些知识是构建复杂组件和应用的基础&#xff0c;而抽屉组件是一个很好的示例&#xff0c;能够…

服务器管理协议,以及SSH协议客户端

六种主要服务器管理协议简单概述 一、RDP RDP远程协议是一个多通道协议,让用户通过本地电脑连接远程服务器。大部分的Windows、Linux服务器都有相应的客户端。 行云管家基于B/S架构(Browser/Server,浏览器/服务器模式)设计,直接使用浏览器远程连接服务器,支持原生RDP远…

Chrome小恐龙快跑小游戏——Python实现

目录 视频演示 代码实现 视频演示 Chrome小恐龙快跑小游戏——Python实现 代码实现 import pygame import os import random pygame.init()# Global Constants SCREEN_HEIGHT 600 SCREEN_WIDTH 1100 game_over False SCREEN pygame.display.set_mode((SCREEN_WIDTH, SCR…

mysql通过.frm和.ibd 文件恢复数据库

问题背景&#xff1a;由于强制在服务关闭mysql导致部分数据表以及数据丢失 如下图只有.frm .ibd的文件为我的问题文件 查找不到表结构和表数据目录D:XXXX\mysql-5.7.24-winx64\data\mydata 从frm文件中恢复表结构 先把原来的数据备份一次 避免过程中出错 先备份之前数据的.fr…

聊聊Jasypt的StandardPBEByteEncryptor

序 本文主要研究一下Jasypt的StandardPBEByteEncryptor Jasypt Jasypt即Java Simplified Encryption&#xff0c;它主要是简化项目加解密的工作&#xff0c;内置提供了很多组件的集成&#xff0c;比如hibernate、spring、spring-security等 示例 示例1 StrongPasswordEnc…

【高危】Apache Airflow Spark Provider 反序列化漏洞 (CVE-2023-40195)

zhi.oscs1024.com​​​​​ 漏洞类型反序列化发现时间2023-08-29漏洞等级高危MPS编号MPS-qkdx-17bcCVE编号CVE-2023-40195漏洞影响广度广 漏洞危害 OSCS 描述Apache Airflow Spark Provider是Apache Airflow项目的一个插件&#xff0c;用于在Airflow中管理和调度Apache Spar…

QT使用QXlsx实现数据验证与Excel公式操作 QT基础入门【Excel的操作】

准备环境:QT中使用QtXlsx库的三种方法 1、公式操作写单行公式 //右值初始化Format rAlign;rAlign.setHorizontalAlignment(Format::AlignRight);//左值初始化Format lAlign;lAlign.setHorizontalAlignment(Format::AlignLeft);xlsx.write("B3", 40, lAlign);xlsx.wr…

Spark及其生态简介

一、Spark简介 Spark 是一个用来实现快速而通用的集群计算的平台&#xff0c;官网上的解释是&#xff1a;Apache Spark™是用于大规模数据处理的统一分析引擎。 Spark 适用于各种各样原先需要多种不同的分布式平台的场景&#xff0c;包括批处理、迭代算法、交互式查询、流处理…