服务降级,限流等--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: