0%

train

Tigs:

  1. 相同的application文件优先使用公共的配置

一些没什么用的小概念

  • 并发量:同一时间内,系统中同时处理的用户请求数
  • 响应时间:系统处理一个请求所需的时间
  • 吞吐量:系统在给定时间内处理处理的业务请求数量
  • QPS(Queries Per Second) 表示系统每秒钟处理的请求数量
  • TPS(Transactions Per Second ) 表示系统每秒钟完成的事务数量

Gateway 网关负责分发前端请求

使用分布式锁来解决缓存击穿

  • 以下是要自己完成的:
    1. 使用Spring Security和GateWay完成路由转发和认证
    2. 使用kafka或rocketmq
      Redis作为缓存
  • 缓存问题:
    1. 每天的用户很多但是用户每天使用的次数很少,同时会员的信息涉及的表很多
      • 解决:使用本地缓存,因为每个会员使用次数很少,一分钟有效,
      • 问题:fullgc频繁,导致短时间内大量请求失败,因为缓存时间很短,所以大量的新生代出现,引起频繁的gc,然后大量放入老年代引起fullgc , 解决:不用本地缓存,而是用线程本地变量,放在内存中。

Senta

  • 原理:生成反向sql
  • 模式:
    1. AT模式:默认,添加undo_log,反向生成sql,回滚之后原来没数据的依然没有数据
      • 使用方法:
        1. 建立undo_log表
    2. TCC模式: try confirm/cancel 三个阶段的代码自己实现,Seata负责调度
    3. SAGA模式:长事务解决方案,需要编写两个阶段的代码,需要一个JSON文件,可以异步执行
    4. XA模式:适用于银行和金融,需要数据库支持XA协议
      try 之前的代码出现异常会直接结束,不会走finally

如何处理多并发的买票

  1. 使用synchronized ,缺点:会导致卡住,只适合单机
  2. 使用Redis分布式锁,使用日期+车次来作为锁key,然后放入Redis中,如果拿到锁则继续执行,使用的使setIfAbsent(key,value,timeout),如果这个锁不存在则设置并且返回true,买到票之后删除key 缺点:如果线程执行时间超过了超时时间,也会导致超卖 对应Redis的命令是setnx
  3. 使用Redisson看门狗,使用一个守护线程来关注超时间是,如果事务未完成但是锁即将过期则重置时间,如果事务结束则守护线程结束,lock.isHeldByCurrentThread来判断是否是当前线程的锁,缺点:Redis集群中Redis宕机,会导致获得得不到锁,然后新的线程向新的Redis主节点中获得锁,仍然可以获得锁 , 最常用 ,Redisson中的锁在释放了之后Redis就查不到了!!!
  4. 使用红锁:只有拿到半数以上的同等地位的Redis的锁才算拿到锁,Redisson中也有自带的红锁,不常用, 缺点:性能问题,并且如果都得不到锁就都会等待了,尽量去尝试获得更多的锁来解决单机宕机问题
@RestController
@Slf4j
public class RedisController {
    @Resource
    private RedissonClient redissonClient;

    @PostMapping("/buy")
    public String set(String ticket) throws InterruptedException {
        //当前日期
        String key = ticket ;
        log.info("key:{}", key);
        RLock lock = null;

            //获取锁
            lock = redissonClient.getLock(key);
            //尝试加锁,最多等待100秒,上锁以后10秒自动解锁
            boolean tryLock = lock.tryLock( 0, TimeUnit.SECONDS); //等待100秒,上锁以后10秒自动解锁
            log.info("tryLock:{}", tryLock);
            //模拟业务处理
            if(tryLock){
                Thread.sleep(10000); //单位是毫秒
                log.info("购买成功");
                if(null != lock && lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
                return "购买成功";
            } else {
                log.info("没拿到锁");
                return "购买失败";
//                throw new RuntimeException("没拿到锁");
            }


    }
}

使用Sentinal进行限流和降级

  • 常见的限流算法:
    1. 静态窗口限流:每秒限制多少个请求,例如:第2.5会统计第2秒到现在的流量
    2. 动态窗口限流:滑动窗口,往前取1秒,例如:第2.5秒会统计第1.5秒到现在的请求数
    3. 漏桶限流:队列,请求全在队列中,出队是匀速的
    4. 令牌桶限流:放的是令牌,令牌就是计数,会有一个计数器匀速产生令牌,出队不是匀速的可以适应短时间内大量请求
    5. 令牌大闸:当令牌到达一定数量就不再产生新的令牌

如何应对刷票

使用令牌大闸:令牌按照匀速生成,即使有再多的机器人刷票也会被领票的数量限制,判断令牌肯定比更新库存更快

  1. 使用令牌锁,持有令牌锁的人才能对令牌进行操作
  2. 检测令牌数量,如果有就执行,没有就不能执行
  3. 不要立刻释放令牌锁,使用固定的时间来释放令牌锁,这样即使有机器人也得等待令牌锁的释放
  • 同时也可以加入验证码来防止机器人刷票
    优化:使用缓存加速令牌锁
    将数据库查出来的令牌存在Redis中,每次对Redis中的令牌数量-1,只有当数量等于我们设定的阈值时再去更改数据库的令牌数量,所以需要在Redis中长期保持这个key

使用RocketMQ

使用RocketMQ来完成
购票之后,将请求发送给RocketMQ,然后另一边去消费这个消息,并且进行数据库的增删改查,可以将请求直接转为String 发送,之后另一端pull然后转为需要的类,之后执行具体具体的逻辑

纯手写

  1. 登录:
    • 使用gateway + SpringSecurity + JWT + Redis实现微服务登录
    • Mybatis+Mybatis-plus