Sentinel-秒杀活动
一、背景
之前在博客中写过秒杀活动开发过程细节,之后用数据库锁简单实现了一次,今天再给大家介绍一个工具Sentinel。
二、sentinel是什么
Sentinel中文含义是哨兵,阿里巴巴给出的定义:Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。我们可以从定义中的简单的认识到该工具就是针对类似秒杀活动一样的高流量、高并发场景下的一个保证服务稳定的工具。具体的介绍请参考:https://github.com/alibaba/Sentinel/wiki。
三、sentinel怎么用
使用sentinel时,我们明确以下概念:
核心库:sentinel以jar包的形式加入到自己工程中,不依赖的其他库
控制台:可以管理资源、定义规则的可视化工具
资源:它就是我们工程中的一个方法、类或者业务服务。sentinel正是要控制资源的工具。很显然在我们的秒杀活动中,获取商品库存的方法即为资源。当有大流量过来时,通过sentinel的控制台指定的规则,来控制这些流量,保证我们的服务稳定性。
1、引入核心库
在自己的工程中引入sentinel-core和sentinel-transport包。
compile 'com.alibaba.csp:sentinel-core:1.6.3'
Transport 模块来与 Sentinel 控制台进行通信。
compile 'com.alibaba.csp:sentinel-transport-simple-http:1.6.3'
2、定义资源
官方给出5种方式:主流框架适配、抛异常方式、返回布尔值方式、注解、异步调用。我们这里使用抛异常方式作为示例,使用SphU提供的方法将我们的资源(获取库存代码块)包裹起来。可能有人好奇为什么没在方法上定义?这里是因为方法还有其他处理逻辑,而这些并不受高并发影响,如果我们将范围扩大至整个方法,那么会导致等个请求变慢。我们只需要在核心的逻辑上定义即可。
// sentinel-1.5后支持try-with-resource特性。CAMPAIGN_CARD_PROMOTION即为我们的资源名
boolean isHaveStock = false;
try (Entry youEntry = SphU.entry("CAMPAIGN_CARD_PROMOTION")) {
if (isNewUser && isJulyCampaignDate && isNANJINGUser && !isHadBuyCampaignCard) {
try {
// 库存数
RAtomicLong cardStock = redissonClient.getAtomicLong("JULY_CAMPAIGN_ONE_YUAN_CARD_STOCK");
boolean isSuccess = true;
if (!cardStock.isExists() || cardStock.get() <= 0) {
isSuccess = false;
} else if (cardStock.decrementAndGet() < 0) {
isSuccess = false;
}
if (isSuccess) {
// 建立用户和库存关系
RBucket<Integer> userStock = redissonClient.getBucket("JULY_CAMPAIGN_USER_STOCK_RELATION:" + uid);
userStock.set(1, 60, TimeUnit.DAYS);
// 订单抢购成功发短信通知
threadPoolTaskExecutor.submit(() -> mqService.sendRpcMessageService(uid, MessageActionEnum.PROMOTION, cardServiceConfig.getJulyCampaignSms2(), Maps.newHashMap()));