1.  整合sentinel流控

  当需要对一个接口进行流量监控时可以使用springboot整合sentinel

  (1)在common模块中导入依赖 spring-cloud-starter-alibaba-sentinel;

  (2)下载sentinel控制台并启动;

  (3)配置 sentinel 控制台地址信息

spring.cloud.sentinel.transport.dashboard=localhost:8333
spring.cloud.sentinel.transport.port=8719

  (4)在控制台调整参数(默认所有的流控规则保存在内存中,重启失效)

  对获取当前秒杀活动添加流量控制,当请求超过时,会被阻塞

  (5)添加统计审计信息,对每一个微服务都导入 spring-boot-starter-actuator,并暴露所有端点 management.endpoints.web.exposure.include=*

   (6)添加配置类,自定义 sentinel 流控返回的数据

@Configuration
public class GulimallSeckillSentinelConfig {

    public GulimallSeckillSentinelConfig() {

        WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
            @Override
            public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
                R error = R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(), BizCodeEnume.TO_MANY_REQUEST.getMsg());
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json");
                response.getWriter().write(JSON.toJSONString(error));

            }
        });

    }

}

 

2. sentinel熔断降级

  (1)服务调用方的熔断保护:feign.sentinel.enable=true

  (2)远程服务发生异常时,触发我们的熔断回调方法

  在商品服务详情中会进行远程调用秒杀服务,当秒杀服务异常时,会触发fallback方法

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();

        //1、sku基本信息的获取  pms_sku_info
        CompletableFuture<SkuInfoEntity> infoFutrue = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity info = getById(skuId);
            skuItemVo.setInfo(info);
            return info;
        }, executor);

        //3、获取spu的销售属性组合
        CompletableFuture<Void> saleAttrFuture = infoFutrue.thenAcceptAsync((res)->{
            List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(res.getSpuId());
            skuItemVo.setSaleAttr(saleAttrVos);
        },executor);

        //4、获取spu的介绍    pms_spu_info_desc
        CompletableFuture<Void> descFuture = infoFutrue.thenAcceptAsync((res)->{
            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
            skuItemVo.setDesc(spuInfoDescEntity);
        },executor);

        //5、获取spu的规格参数信息
        CompletableFuture<Void> baseAttrFuture = infoFutrue.thenAcceptAsync((res)->{
            List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            skuItemVo.setGroupAttrs(attrGroupVos);
        },executor);

        //2、sku的图片信息    pms_sku_images
        CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(images);
        }, executor);

        CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(() -> {
            //3、远程调用查询当前sku是否参与秒杀优惠活动
            R skuSeckilInfo = seckillFeignService.getSkuSeckilInfo(skuId);
            if (skuSeckilInfo.getCode() == 0) {
                //查询成功
                SeckillSkuVo seckilInfoData = skuSeckilInfo.getData("data", new TypeReference<SeckillSkuVo>() {
                });
                skuItemVo.setSeckillSkuVo(seckilInfoData);

                if (seckilInfoData != null) {
                    long currentTime = System.currentTimeMillis();
                    if (currentTime > seckilInfoData.getEndTime()) {
                        skuItemVo.setSeckillSkuVo(null);
                    }
                }
            }
        }, executor);

        //等待所有任务都完成
        CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture,seckillFuture).get();
        return skuItemVo;
    }

@FeignClient(value = "gulimall-seckill",fallback = SeckillFeignServiceImpl.class)
public interface SeckillFeignService {

    /**
     * 根据skuId查询商品是否参加秒杀活动
     * @param skuId
     * @return
     */
    @GetMapping(value = "/sku/seckill/{skuId}")
    R getSkuSeckilInfo(@PathVariable("skuId") Long skuId);

}

@Slf4j
@Component
public class SeckillFeignServiceImpl implements SeckillFeignService {

    @Override
    public R getSkuSeckilInfo(Long skuId) {
        log.info("熔断方法调用......");
        return R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(),BizCodeEnume.TO_MANY_REQUEST.getMsg());
    }
}

  也可以在控制台中对远程服务指定降级规则

 

3. 整合zipkin

  (1)docker 安装 zipkin 服务器

  docker run -d -p 9411:9411 openzipkin/zipkin

  (2)导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

  zipkin 依赖也同时包含了 sleuth,可以省略 sleuth 的引用

  (3)添加zipkin相关配置

#服务追踪
spring.zipkin.base-url=http://zipkin安装地址:9411/
#关闭服务发现
spring.zipkin.discovery-client-enabled=false
spring.zipkin.sender.type=web
#配置采样器
spring.sleuth.sampler.probability=1

  服务调用链追踪信息统计

  Zipkin 默认是将监控数据存储在内存的,如果 Zipkin 挂掉或重启的话,那么监控数据就会丢失。所以如果想要搭建生产可用的 Zipkin,就需要实现监控数据的持久化。而想要实现数据持久化,自然就是得将数据存储至数据库,通常选用Elasticsearch。

posted on 2023-10-02 17:54  homle  阅读(821)  评论(0编辑  收藏  举报