# 《Seckill秒杀系统》第97章:秒杀系统实现服务容错

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★☆☆☆
  • 本章重点:了解服务容错的实现原理,重点掌握服务容错的落地实现方案,并能够灵活将实现方案应用到自身实际项目中。

大家好,我是冰河~~

不管是秒杀系统,还是其他互联网项目,亦或是体量比较大的一些传统IT项目,哪怕是对系统进行了各种优化和高可用措施,在实际生产环境中可能还是会遇到各种各样的问题。尤其是像秒杀系统这种瞬时高并发、大流量的场景,出现问题的概率就更大了。

# 一、前言

服务容错在一定程度上就是尽最大努力来兼容错误情况的发生,因为在分布式和微服务环境中,不可避免的会出现一些异常情况,我们在设计分布式和微服务系统时,就要考虑到这些异常情况的发生,使得系统具备服务容错能力。在我们研发的秒杀系统中,就更加需要具备服务容错的能力。

# 二、本章诉求

在秒杀系统中实现服务容错功能,并对实现的服务容错功能进行测试,了解服务容错实现的原理,重点掌握服务容错的落地实现方案,并能够灵活将实现方案应用到自身实际项目中。

# 三、实现服务容错

这里,我们以秒杀活动微服为例来实现服务容错,其他微服务实现容错的方式基本相同,大家获取到本章对应的源码分支后,可以根据秒杀活动微服务实现服务容错的方式,对其他微服务实现微服容错功能。好了,正式开始实现服务容错功能。

(1)新增SeckillActivityFallbackService类

SeckillActivityFallbackService类的主要作用就是当秒杀活动微服务出现异常时,会调用SeckillActivityFallbackService类中的方法实现容错功能,避免秒杀活动微服务由于异常影响到其他服务,进而引起服务雪崩效应。

源码详见:seckill-activity-application工程下的io.binghe.seckill.activity.application.service.fallback.SeckillActivityFallbackService。

@Component
public class SeckillActivityFallbackService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SeckillActivityFallbackService.class);

    public static SeckillActivityDTO getSeckillActivityBlockHandler(Long id, Long version, BlockException e){
        LOGGER.info("getSeckillActivityBlockHandler|处理lockHandler|{}|{}|{}",id, version, e.getMessage());
        Date date = new Date();
        return new SeckillActivityDTO(-1001L, "BlockHandler活动", date, date, SeckillActivityStatus.OFFLINE.getCode(), "BlockHandler活动", 0L);
    }

    public static SeckillActivityDTO getSeckillActivityFallback(Long id, Long version, Throwable t){
        LOGGER.info("getSeckillActivityBlockHandler|处理Fallback|{}|{}|{}", id, version, t.getMessage());
        Date date = new Date();
        return new SeckillActivityDTO(-1001L, "Fallback活动", date, date, SeckillActivityStatus.OFFLINE.getCode(), "Fallback活动", 0L);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以看到,在SeckillActivityFallbackService类中,定义了两个静态方法,分别为getSeckillActivityBlockHandler()方法和getSeckillActivityFallback()方法,getSeckillActivityBlockHandler()方法主要是发生BlockException异常时调用,getSeckillActivityFallback()方法主要是发生业务异常时调用。

(2)修改SeckillActivityServiceImpl类

主要是修改SeckillActivityServiceImpl类中根据秒杀活动id和版本号获取秒杀活动详情的方法,在getSeckillActivity()方法上通过@SentinelResource注解指定当发生BlockException异常时调用的方法,以及发生业务异常时调用的方法。并且为了演示实现的效果,我们还会在getSeckillActivity()方法中新增一行异常代码int i = 1 / 0;

SeckillActivityServiceImpl类的源码详见:seckill-activity-application工程下的io.binghe.seckill.activity.application.service.impl.SeckillActivityServiceImpl。

@Override
@SentinelResource(value = "QUEUE-DATA-FLOW",  blockHandlerClass = SeckillActivityFallbackService.class, blockHandler = "getSeckillActivityBlockHandler",  fallbackClass = SeckillActivityFallbackService.class, fallback = "getSeckillActivityFallback")
public SeckillActivityDTO getSeckillActivity(Long id, Long version) {
    if (id == null){
        throw new SeckillException(ErrorCode.PARAMS_INVALID);
    }
    SeckillBusinessCache<SeckillActivity> seckillActivityCache = seckillActivityCacheService.getCachedSeckillActivity(id, version);
    //稍后再试,前端需要对这个状态做特殊处理,即不去刷新数据,静默稍后再试
    if (seckillActivityCache.isRetryLater()){
        throw new SeckillException(ErrorCode.RETRY_LATER);
    }
    //缓存中的活动数据不存在
    if (!seckillActivityCache.isExist()){
        throw new SeckillException(ErrorCode.ACTIVITY_NOT_EXISTS);
    }
    SeckillActivityDTO seckillActivityDTO = SeckillActivityBuilder.toSeckillActivityDTO(seckillActivityCache.getData());
    seckillActivityDTO.setVersion(seckillActivityCache.getVersion());
    int i = 1 / 0;
    return seckillActivityDTO;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 查看完整文章

加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码