Redis 笔记四

本文详细讲述了在高并发场景下实现秒杀系统的挑战,包括超卖bug的处理、数据库性能瓶颈的突破、Redis+MQ架构的应用、事务一致性保障以及高可用性和容灾策略。作者分享了阿里巴巴的内部实践和解决方案,如分布式锁、数据库乐观锁、Redis分片、MQ使用和故障恢复策略。
摘要由CSDN通过智能技术生成

概要

1.高并发场景秒杀抢购超卖bug实战重现

2.阿里巴巴内部高并发秒杀下单方案首次揭秘

3.基于Reddis+MQ实现秒杀下单架构

4.10万订单每秒热点数据架构优化实践

5.秒杀下单MQ如何保证不丢失消息

6.解决MQ下单消息重复消费幂等机制详解

7.线上MQ百万秒杀订单发生积压如何处理

8.Redis集群崩溃如何保证秒杀系统高可用性

9.Redis主从切换导致库存同步异常以及超卖问题

10.MQ集群崩溃时,如何保证秒杀系统高可用性

11.秒杀链路种Redis和MQ如何保证事务一致性

12.秒杀系统限流防刷攻击静态页面等方案详解

1.高并发框架

三高架构一般指:高可用性、高并发性、高可扩展性

秒杀系统就属于一个三高架构,一般单独部署,防止由于其影响其他功能

场景介绍

        秒杀主要是实现一个减库存的操作,还有就是数据信息的访问。面对高并发场景,有可能会产生超卖问题。

根据前面的笔记: 这种情况可以通过添加分布式锁来解决超卖,但是加分布式锁会导致性能很难上去

如果不加锁,怎么解决超卖问题。

    public Integer updateStock(Long productId){
        //update product set stock = stock - 1 where id = 166 and stock >0
        return productDao.seckill(productId);
    }

    @Transactional
    public String seckill(Long productId,Long userId){
        Product product=get(productId);
        if(product.getStock()<=0){
            return "库存售完";
        }

        product.setStock(product.getStock()-1);
        update(product);
        //TODO 创建订单数据
        
        return "抢购成功";
    }

2.不加锁如何解决超卖问题

1.使用数据库的并发解决超卖问题

查看更新是否成功。能更新则更新,不能更新就失败——数据库乐观锁。

问题:但是数据库不能支撑每秒十万的情况,最多每秒几千。支撑不了高并发情况

    @Transactional
    public String seckill(Long productId,Long userId){
        Product product=get(productId);
        if(product.getStock()<=0){
            return "库存售完";
        }

//        product.setStock(product.getStock()-1);
//        update(product);
        
        Integer updateCount=updateStock(productId);
        if(updateCount<1){
            return "抢购失败";
        }
        
        //TODO 创建订单数据
        
        return "抢购成功";
    }

 2.阿里解决数据库性能瓶颈

源码改造,在数据库内部实现一个内存队列,一次性接收十万请求,但是数据库每次处理几千,多处理。——以此来提升性能问题。(一般的公司没有这个实力)

3.常规解大数据量访问问题:Redis+MQ

package com.example.controller;

import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SeckillConntroller {
    @Autowired
    private ProductService productService;

    /**
     * 秒杀接口
     * 实现10万并发秒杀系统三高架构
     * @param productId 商品Id
     * @param userId 用户Id
     * @return
     */
    public String secKill(Long productId, Long userId){
        return productService.seckill(productId,userId);
    }
}

    @Transactional
    public String seckillRedis(Long productId,Long userId){
        String productStockKey = "stock:count:"+productId;
        Integer productStock = redisUtil.get(productStockKey,Integer.class);
        if(productStock<1){
            return "库存售完";
        }
        Long stockCount = redisUtil.decr(productStockKey,1);
        if(stockCount<0){
            redisUtil.incr(productStockKey);
            return "抢购失败";
        }
        //TODO 发送下单MQ,异步创建订单
        return "抢购成功";
    }

对于要秒杀的商品可以提前预热,下单时直接从redis里查,并发情况下减库存可能导致负数,所以要判断stockCount>0

下单是个异步的过程,否则前台会不断的转圈圈。直到订单生成。

当前系统还是不能支撑每秒十万,读写混合——最多每秒2万

3.Redis集群实现高并发

1.分片分散访问压力

redis集群架构将数据分片存储,理论上:只要节点足够多,将十万分到各个节点,基本能抗近10万并发

问题:redis将数据分散到各个节点时,恰好所有数据在一个节点上,性能又崩了,不足以支撑10W每秒

2.数据倾斜问题

redis 集群架构的数据倾斜:数据存在出在一个节点上,大量请求达到一个节点,这个节点压力非常大。

解决方案:预热及时发现数据倾斜,通过命令挪到其他节点上,数据迁移。如:hashTag前面{}里的值去hash,这样就可以控制hash结果了

3.热点商品

某一个商品特别热卖,导致大量访问访问一个商品,一个商品只在一个节点上,这就导致该节点访问压力暴增。——每秒十万并发又不行了。

解决方案:提前规划,在缓存预热时,就将其库存分在多个节点上,不同的分片

    @Transactional
    public String seckillRedis(Long productId,Long userId){
        String productStockKey = "stock:count:"+productId+"01";//02 03 数据分片存储
        Integer productStock = redisUtil.get(productStockKey,Integer.class);
        if(productStock<1){
            return "库存售完";
        }
        Long stockCount = redisUtil.decr(productStockKey,1);
        if(stockCount<0){
            redisUtil.incr(productStockKey);
            return "抢购失败";
        }
        //TODO 发送下单MQ,异步创建订单
        return "抢购成功";
    }

4.Redis集群架构+MQ

Redis+MQ可能存在哪些问题呢?

 可能存在的问题:MQ丢消息、消息积压、消费消息如何幂等。保证不丢消息?怎么做:ACK

1.MQ的简单实现

消息队列的两种模式及MQ简单实现_mq简易实现-CSDN博客

2.如何保证消费幂等

多并发可能存在的问题

如何保证幂等。https://www.cnblogs.com/wzh2010/p/15888523.html

重复消费问题(消费幂等):给每个操作MSG+唯一的ActId,保证消息不被重复消费。

                        有很多种4-5种方式,也可以用uuid, 但是uuid在性能上有影响

3.订单积压如何解决

订单排队被消费——前端一直转圈圈——会丢失客户的

1.增加消费者,加快消费速度

2.插入redis比DB快的多,如果发送时间已经很久了,积压状态——>走redis,查的时候,先数据库,后redis.

后台任务——redis——>DB

3.超过1min订单丢掉——>转1min就下单不成功,请重试——redis+1

4.降级服务

写到本地缓存|本地磁盘文件——记到日志文件;

不断访问redis,访问成功就将 定时记录的日志流水操作到redis和MQ里去

后台不断重试——数据绝对一致不可能,性能也是变差了

5.Redis集群整个崩了怎么办?

如果Redis集群整个崩了,如何保证可用性——要求保证99.9999%的概率可用,保证很小的出错概率。

Redis如果起不来,就使用备用redis集群,同步、切换。但是Redis集群切换可能存在的问题

redis异步同步——主节点-1,从节点没同步,主节点挂了,从节点变主节点——>超卖

解决方案一:问题不大|不解决——应为不能大批量超卖

解决方案二:一定要解决

1.用红锁

2.redis同步,改源码,性能下降

3.不要从节点,多个主节点

分布式架构CAP三个特性不可能全解决

6.MQ整个崩溃怎么办?

MQ集群崩溃咋办?2-3种方案——保证高可用

1.和redis一样

如何保证MQ的高可用_mq消息中间件如何保证高可用-CSDN博客

RocketMQ快速失败机制引发集群不稳定的思考和优化-CSDN博客

7.其他问题

        redis和MQ一致性怎么保证事务一致性。

        一套描述有很多其他的东西,很难。

        上亿流量又如何让解决呢。

redis,db,mq一致性_mqdb-CSDN博客

https://www.cnblogs.com/qingxuan0316/p/16594179.html

百度安全验证

百度安全验证

5.附加的概念

1.什么是雪花算法

雪花算法以及具体实现-CSDN博客

2.什么是多活架构

滴滴 Redis 异地多活的演进历程-CSDN博客

3.什么是接口限流

高并发处理之接口限流_api请求过快-CSDN博客

Rabbitmq消息积压问题如何解决以及如何进行限流_如何解决rabbitmq的消费积压问题-CSDN博客

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值