服务降级,限流等--sentinel(SpringCloud Alibaba)

一. 介绍
Sentinel,中文翻译为哨兵,是为微服务提供流量控制、熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的“雪崩”效应,为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维护期,不再提供新功能,Sentinel是一个不错的替代方案。

通常情况,Hystrix采用线程池对服务的调用进行隔离,Sentinel采用了用户线程对接口进行隔离,二者相比,Hystrxi是服务级别的隔离,Sentinel提供了接口级别的隔离,Sentinel隔离级别更加精细,另外Sentinel直接使用用户线程进行限制,相比Hystrix的线程池隔离,减少了线程切换的开销。另外Sentinel的DashBoard提供了在线更改限流规则的配置,也更加的优化。


二. 特征
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。

完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
————————————————

1.引入pom依赖:

    <!--<dependency>
      <groupId>com.alibaba.csp</groupId>
      <artifactId>sentinel-transport-simple-http</artifactId>
      <version>1.8.2</version>
    </dependency>-->

    <dependency>
      <groupId>com.alibaba.csp</groupId>
      <artifactId>sentinel-transport-netty-http</artifactId>
      <version>1.8.2</version>
    </dependency>

2. 启动类加初始化:InitExecutor.doInit()。

(3)监听ApolloConfig的流控规则; 

package com.siebel.api.server.config.rest;

import com.aswatson.common.sentinel.parameter.flow.datasource.ApolloDataSourceRuleManager;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class ApolloConfig {

    Logger logger = LoggerFactory.getLogger(getClass());

    @ApolloConfigChangeListener(value = {"siebel-api-server_rules"}, interestedKeys = {"siebel-api-server-flow-rules"})
    public void loadRules(ConfigChangeEvent changeEvent) {
        ConfigChange change;
        for (String key : changeEvent.changedKeys()) {

            change = changeEvent.getChange(key);
            // 打印出新增或者变化的配置 相关信息
            logger.info(String.format("Change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
                change.getPropertyName(), change.getOldValue(), change.getNewValue(),
                change.getChangeType()));

            ApolloDataSourceRuleManager.loadRules(change.getNewValue());

        }
    }

    @ApolloConfigChangeListener(value = {"siebel-api-server_rules"}, interestedKeys = {"siebel-api-server-param-rules"})
    public void loadParamRules(ConfigChangeEvent changeEvent) {
        ConfigChange change;
        for (String key : changeEvent.changedKeys()) {

            change = changeEvent.getChange(key);
            // 打印出新增或者变化的配置 相关信息
            logger.info(String.format("Change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
                change.getPropertyName(), change.getOldValue(), change.getNewValue(),
                change.getChangeType()));

            ApolloDataSourceRuleManager.loadParamRules(change.getNewValue());

        }
    }

    @Value("${siebel-api-server-flow-rules:}")
    public void initLoadRules(String flowRulesJsonStr) {
        ApolloDataSourceRuleManager.loadRules(flowRulesJsonStr);
    }

    @Value("${siebel-api-server-param-rules:}")
    public void initLoadParamRules(String rulesJsonStr) {
        ApolloDataSourceRuleManager.loadParamRules(rulesJsonStr);
    }

}

(4)apollo配置如图:siebel-api-server_rules 是自动生成到apollo的

 (5)定义限流资源,(有5种方式)1.抛出异常的方式;改造接口代码: filterSentinelRules (限流的代码)

    public ASWPOSInboundLoyaltyMember_Output aSWPOSInboundLoyaltyMember(ASWPOSInboundLoyaltyMember_Input input) throws Exception {
        String buId = buManager.getBuId(input.getBUID());
        Assert.hasText(buId, () -> String.format("get buId failed,can't find buId base on given input.input=%s", input.getBUID()));
        try {
            filterSentinelRules(ASWPOSInboundLoyaltyMember, buId);
        } catch (SentinelException e) {
            e.printStackTrace();
            return getSentinelRulesOutPut(new ASWPOSInboundLoyaltyMember_Output());
        }
        sendRequestOperationLog(ASWPOSInboundLoyaltyMember, input.getMessageXML(), input.getCardNumber(), buId, input.getBUID());
        ASW_spcPOS_spcInboundSkeletonInterface asw_spcPOS_spcInboundSkeleton = getASW_spcPOS_spcInboundSkeletonInstance();
        ASWPOSInboundLoyaltyMember_Output output = asw_spcPOS_spcInboundSkeleton.aSWPOSInboundLoyaltyMember(input);return output;
    }

    private void filterSentinelRules(String requestApiName, String buId) {
        Entry entry = null;
        try {
            entry = SphU.entry(requestApiName, EntryType.IN, 1, buId);
       Thread.sleep(2000); //模拟断开连接测试 }
catch (BlockException ex) { log.error("Current requestApiName limiting SentinelRules: apiName|{}, buId|{}, msg|{}", buId, requestApiName, ex.getMessage()); throw new SentinelException(ex.getMessage()); } finally { if (entry != null) { entry.exit(1, buId); } } }

(6)sentinel控制台定义规则:

 2.

 

 测试结果:

1. 必须要先配置sentinel的环境变量,也可以在IDEA中配置:

-Djava.net.preferIPv4Stack=true
##Sentinel Dashboard 通过此端口获取 应用流控统计数据
-Dcsp.sentinel.api.port=8443
##Sentinel Dashboard 访问url
-Dcsp.sentinel.dashboard.server=10.95.35.93:32289
#配置appid=cdcsit.cdc,@项目名
-Dproject.name=cdcsit.cdc@siebel-api-server
##配置sentinel控制台对应ip,默认的,可以不配
-Dcsp.sentinel.heartbeat.client.ip=10.95.33.131

 

 

2. 同一个bu类型,同时去访问,因为配置限流,8s内只能有一个线程访问成功,所以另一个请求返回失败,提示 异常 limit by sentinel rule:

 

posted @ 2022-08-24 11:06  威兰达  阅读(141)  评论(0编辑  收藏  举报