秒杀业务实现

一、秒杀

1、秒杀业务

秒杀具有瞬时高并发的特点,针对这一特点,必须做限流+异步+缓存(页面静态化)+独立部署

限流方式:

  • 前端限流:一些高并发网站直接在前端限流,例如:小米的验证码设计
  • nginx限流:直接负载部分请求错误的静态页面;令牌算法,漏斗算法。
  • 网关限流:限流的过滤器
  • 代码中使用分布式信号量
  • rabbitMq限流(能者多劳:channel.basicQos(1)),保证发挥所有服务器的性能。
2、定时任务(Quartz)
1)、cron表达式

https://cron.qqe2.com/ 可在该网站进行生成cron 表达式

spring自带的定时任务

/**
 * 定时任务
 *      1、@EnableScheduling 开启定时任务
 *      2、@Scheduled 开启一个定时任务
 *      3、自动配置类 TaskSchedulingAutoConfiguration
 * 异步任务
 *      1、@EnableAsync 开启异步任务功能
 *      2、@Async 给方法加上注解
 *      3、TaskExecutionAutoConfiguration 自动配置类
 */
@EnableScheduling
@Component
@Slf4j
@EnableAsync
public class HandSchedule {

    /**
     * 1、spring中 cron只能是六位 不能含有年
     * 2、在周几的位置 1-7代表周一到周日:MON-SUN
     * 3、定时任务不应该阻塞。默认是阻塞的
     *     1)、可以让业务运行以异步的方式,自己提交到线程池
     *               CompletableFuture.runAsync(()->{
     *                },executor);
     *     2)、支持定时任务线程池:设置 TaskSchedulingProperties
     *     3)、让定时任务异步执行
     *       异步任务
     *
     *     解决:使用异步+定时任务解决定时任务不阻塞的功能
     *
     */
    @Scheduled(cron = "* * * ? * 3")
    @Async
    public void hello(){
        log.info("hello..");
    }
}
2)、秒杀服务-幂等性问题

添加分布式锁:pom引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.24.3</version>
</dependency>
@Scheduled(cron = "* * * ? * 3")
@Async
public void hello() {
    RLock lock = redissonClient.getLock("redis_key");
    lock.lock(10, TimeUnit.SECONDS);
    try {
        log.info("hello.."); //业务逻辑
    } finally {
        lock.unlock();
    }
}

二、高并发方法论

1、秒杀系统关注问题
  • 服务单一职责+单独部署:

    秒杀服务即使扛不住挂掉也不会影响其他服务。

  • 秒杀链接加密:

    防止恶意攻击,模拟秒杀请求,1000次/s攻击,防止链接暴漏,自己工作人员,提前秒杀商品

  • 库存预热+快速扣减:

    秒杀读多写少,无需每次实时校验库存。我们库存预热,放到redis中,信号量控制进来秒杀的商品

  • 动静分离:

    nginx做好动静分离。保证只有秒杀和商品详情页的动态请求打到后端的服务集群。使用CDN网络,分担本集群压力。

  • 恶意请求拦截

    识别非法请求并进行拦截,网关拦截

  • 流量错峰

    使用各种手段,将流量分担到更大宽度的时间点。比如验证码、购物车

  • 限流&熔断&降级

    前端限流+后端限流 。 限制次数,限制总量,快速失败降级运行,熔断隔离防止雪崩

  • 队列削峰

    1万个商品,每个1000件秒杀,双11所有秒杀成功的请求,进入队列,慢慢创建订单,扣减库存即可。

1)、熔断降级限流

什么是熔断:

​ A服务调用B服务的某个功能,由于网络不稳定,或者B服务卡机,导致功能时间超长。如果这样子的次数太多。我们就可以直接将B断路了(A不在请求B的接口),凡是调用B的直接返回降级数据,不必等B的超长执行。这样B的故障问题,就不会级联影响到A。

什么是降级:

​ 整个网站都处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和页面进行有策略的降级【停止服务,所有的数据直接返回降级数据】。以此缓和服务器资源的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户得到正确的响应。

异同:

​ 相同点:

​ 1、为了保证集群大部分的可靠性和可用性,防止崩溃,选择了牺牲小我。

​ 2、用户最终都是体验到某个功能不可用

​ 不同点:

​ 1、熔断是被调用方故障,触发系统保护规则。

​ 2、降级是基于全局考虑,停止一些正常服务,释放资源。

什么是限流:

​ 对打入服务的请求的流量进行控制,使服务器能够承担不超过自己能力的流量压力。

三、Sentinel

在这里插入图片描述

1、Sentinel简介

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

  • 资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

  • 规则

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

下载地址:https://github.com/alibaba/Sentinel/releases

启动:

java -jar D:\tools\sentinel-dashboard-2.0.0-alpha-preview.jar --server.port=8333
2、整合springboot

引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2022.0.0.0</version>
</dependency>

配置

spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.transport.dashboard=localhost:8080
# 用于指定哪些端点应该暴露在web界面上
management.endpoints.web.exposure.include=*

自定义流控响应

@Component
public class SentinelUrlBlockHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code","1001");
        jsonObject.put("message","访问次数过多");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json");
        httpServletResponse.getWriter().write(JSON.toJSONString(jsonObject));
    }
}

如果引入的版本是2022.0.0.0之前的版本,那么写法是以下方式

@Configuration
public class SeckillSentinelConfig {

    public SeckillSentinelConfig(){
        WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
            @Override
            public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("code","1001");
                jsonObject.put("message","访问次数过多");
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setContentType("application/json");
                httpServletResponse.getWriter().write(JSON.toJSONString(jsonObject));
            }
        });
    }
}
3、Sentinel熔断降级

调用方熔断保护

feign.sentinel.enabled=true

远程调用添加fallback

@Component
public class InventoryServiceClientFallBack implements InventoryServiceClient {

    @Override
    public void insertInventory(Inventory inventory) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code","20001");
        jsonObject.put("message","请求熔断");
        System.out.println(jsonObject);
    }
}

或者在sentinel控制台中手动添加 熔断机制

在这里插入图片描述

sentinel 会将远程调用服务做降级处理,并触发熔断保护机制。

新增熔断规则

  • | 规则 | 说明 |
    | :--------------- | :----------------------------------------------------------- |
    | 资源名: | 唯一名称 |
    | 熔断策略: | a.(默认值)慢调用比列
    b.异常比列(秒级)
    c.异常数(分钟级) |
    | RT: | RT:平均响应时间,秒级。RT最大4900
    (更大的需要通过-
    Desp.sentinel.statistic.max=xxx才能生效) |
    | 熔断时长: | 窗口期过后关闭断路器 |
    | 慢调用比列阈值: | 仅慢调用比例模式有效(1.8.0有效),
    比率的阈值范围是【0,0,1.0】,代表0%~100%。 |
    | 最小请求数: | 熔断触发的最小请求数,请求数小于该值时即使异常
    比率超出阈值也不会熔断(1.7.0引入)默认值5 |
    | 统计时长: | 统计计入时长(单位ms),如60*1000代表分钟级
    (1.8.0引入)默认值1000ms |
4、自定义保护资源
1)、基于代码方式
@Override
@Transactional
@GlobalTransactional
public List<Map<String, Object>> getList(Order order) {
    try(Entry entry = SphU.entry("orderList")) {
        // 受保护资源执行
    }catch (Exception e){
        log.info("限流控制,{}",e.getMessage());
    }
    return null;
}

在这里插入图片描述

2)、基于注解方式
@SentinelResource(value = "getList")

在这里插入图片描述

被流控后接口调用会报错。

解决:

@SentinelResource(value = "getList", blockHandler = "blockHandlerList")

可使用 blockHandler 指定流控后的限流方法。

注意:

  • @SentinelResource这个注解的方法的返回值 与 blockHandlerList该方法返回值一致。
  • 参数一致
  • blockHandlerList 该方法应该多接收一个 BlockException 类型参数

示例

/**
* 在原方法降级/限流/系统保护的时候被调用  而fallback针对所有类型的异常
*/
@Override
@SentinelResource(value = "getList", blockHandler = "blockHandlerList")
public List<Map<String, Object>> getList(Order order) {}

public List<Map<String, Object>> blockHandlerList(Order order, BlockException t) {}
5、Sectinel网关流控

导入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>1.8.6</version>
</dependency>

配置

server:
  port: 8090
spring:
  application:
    name: spring-cloud-gateway
  cloud:
    gateway:
      enabled: true
      routes:
        - id: service-order
          uri: lb://service-order
          predicates:
            - Path=/order/**
    sentinel:
      transport:
        dashboard: localhost:8333
        port: 8719

feign:
  sentinel:
    enabled: true
logging:
  level:
    com:
      example: debug

创建流控
在这里插入图片描述
自定义限流返回数据:

@Configuration
public class SentinelGatewayConfig {

    public SentinelGatewayConfig() {
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            // 网关限流了请求,就会调用此回调
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("code","20001");
                jsonObject.put("message","限流");
                return ServerResponse.ok().body(Mono.just(jsonObject), JSONObject.class);
            }
        });
    }
}
  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现秒杀业务的重点有以下几个方面: 1. 高并发处理:秒杀业务的特点是短时间内有大量用户同时请求,因此需要考虑如何处理高并发请求。可以采用分布式缓存、消息队列等技术来缓解并发量,同时需要对数据库连接池、线程池等进行优化。 2. 防止超卖:秒杀业务中最重要的问题是如何防止超卖,即一个商品被多次售卖的情况。可以采用悲观锁或者乐观锁来保证商品库存的准确性,同时需要对事务进行严格控制。 3. 前端限流:前端限流可以有效地控制短时间内的请求量,避免系统崩溃。可以采用验证码、短信验证等方式来限制用户的请求频率。 4. 后端限流:后端限流可以控制系统的负载,避免系统过载。可以采用限流算法、熔断机制等技术来限制请求量,同时需要对系统进行监控和报警。 5. 异步处理:异步处理可以提高系统的响应速度和吞吐量。可以采用消息队列、线程池等技术来实现异步处理,减少用户等待的时间。 6. 安全措施:秒杀业务往往会吸引黑客的攻击,因此需要采取一些安全措施来保证系统的安全性,比如防止SQL注入、XSS攻击等。 7. 数据库优化:数据库秒杀业务中的瓶颈之一,需要对数据库进行优化,比如对索引进行优化、采用分库分表等技术来提高数据库的性能。 以上是实现秒杀业务的重点,需要综合考虑各方面的因素来保证系统的高性能、高可用性和高安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值