《掌门1对1微服务体系 Solar | 阿里巴巴 Sentinel 落地实践》
簡介:
前言
掌門1對1精耕在線教育領(lǐng)域,近幾年業(yè)務(wù)得到了快速發(fā)展,但同時(shí)也遭遇了“成長的煩惱”。隨著微服務(wù)數(shù)量不斷增加,流量進(jìn)一步暴增,硬件資源有點(diǎn)不堪重負(fù),那么,如何實(shí)現(xiàn)更好的限流熔斷降級(jí)等流量防護(hù)措施,這個(gè)課題就擺在了掌門人的面前。由于?Spring Cloud?體系已經(jīng)演進(jìn)到第二代,第一代的?Hystrix?限流熔斷降級(jí)組件已經(jīng)不大適合現(xiàn)在的業(yè)務(wù)邏輯和規(guī)模,同時(shí)它目前被?Spring Cloud?官方置于維護(hù)模式,將不再向前發(fā)展。
如何選擇一個(gè)更好的限流熔斷降級(jí)組件?經(jīng)過對?Alibaba Sentinel、Resilience4j、Hystrix?等開源組件做了深入的調(diào)研和比較,最終選定?Alibaba Sentinel?做微服務(wù)體系?Solar?中的限流熔斷降級(jí)必選組件。
Sentinel 簡介
阿里巴巴中間件部門開發(fā)的新一代以流量為切入點(diǎn),從流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性的分布式系統(tǒng)的流量防衛(wèi)兵。它承接了阿里巴巴近10年的雙十一大促流量的核心場景,例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)、消息削峰填谷、集群流量控制、實(shí)時(shí)熔斷下游不可用應(yīng)用等。
它具有非常豐富的開源生態(tài):
它和?Hystrix?相比,有如下差異:
摘自官網(wǎng)?Sentinel Roadmap
關(guān)于?Sentinel?如何使用,它的技術(shù)實(shí)現(xiàn)原理怎樣等,官方文檔或者民間博客、公眾號(hào)文章等可以提供非常詳盡且有價(jià)值的材料,這些不在本文的討論范圍內(nèi),就不一一贅述。筆者嘗試結(jié)合掌門1對1現(xiàn)有的技術(shù)棧以及中間件一體化的戰(zhàn)略,并著眼于強(qiáng)大的?Spring Cloud Alibaba?技術(shù)生態(tài)圈展開闡釋。
Sentinel 深度集成 Apollo
Sentinel?官方在?sentinel-datasource-apollo?模塊中已經(jīng)對?Apollo?做了一些擴(kuò)展,主要實(shí)現(xiàn)了?Sentinel?規(guī)則的讀取和訂閱邏輯。這些并不夠,我們需要對?Apollo?進(jìn)行更深層次的集成。
摘自官網(wǎng)?在生產(chǎn)環(huán)境中使用 Sentinel
Solar SDK 環(huán)境初始化
定制?EnvironmentPostProcessor?類,實(shí)現(xiàn)如下:
- Sentinel Dashboard?的項(xiàng)目名稱從?Apollo?AppId?的維度進(jìn)行展示
- 根據(jù)環(huán)境?env?值讀取相應(yīng)的配置文件,并訪問對應(yīng)環(huán)境的?Sentinel Dashboard?域名Sentinel Dashboard?在生產(chǎn)環(huán)境部署若干臺(tái)?ECS?實(shí)例,阿里云?SLB?做負(fù)載均衡,實(shí)現(xiàn)對集群的水平擴(kuò)展
把?SentinelClientEnvironmentPostProcessor?類放置?\resources\META-INF\spring.factories?文件中,內(nèi)容為
org.springframework.boot.env.EnvironmentPostProcessor=\ com.zhangmen.solar.component.sentinel.common.context.SentinelClientEnvironmentPostProcessor在?\resources\META-INF?目錄下,定制環(huán)境配置文件,文件名格式為?sentinel-{環(huán)境號(hào)}.properties?。下文以?dev?環(huán)境和?flow?流控配置(其它規(guī)則配置,請自行參考?Spring Cloud Alibaba Sentinel?的相關(guān)資料)為樣例。
sentinel-dev.properties
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080 spring.cloud.sentinel.datasource.ds.apollo.namespaceName=application spring.cloud.sentinel.datasource.ds.apollo.flowRulesKey=sentinel.flowRules spring.cloud.sentinel.datasource.ds.apollo.ruleType=flow ...Sentinel Dashboard 持久化改造
原生的?Sentinel Dashboard?在創(chuàng)建完規(guī)則后,規(guī)則內(nèi)容保存在服務(wù)的內(nèi)存中,當(dāng)服務(wù)重啟后所有的規(guī)則內(nèi)容都會(huì)消失。因此,在生產(chǎn)部署時(shí)需要考慮配置持久化,并且使用?Apollo?動(dòng)態(tài)規(guī)則的感知能力。
① 向外暴露 Sentinel 規(guī)則的 Restful 接口
@RestController @RequestMapping(value = "/v2/flow") public class FlowControllerV2 {@Autowired@Qualifier("apolloFlowRuleProvider")private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("apolloFlowRulePublisher")private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;.... }② 實(shí)現(xiàn) Sentinel Apollo 規(guī)則提供
@Component("apolloFlowRuleProvider") public class ApolloFlowRuleProvider extends BaseApolloRuleProvider<FlowRuleEntity> {@Overridepublic List<FlowRuleEntity> getRules(String appName) throws Exception {List<FlowRuleEntity> flowRuleEntityList = super.getRules(appName);if (!CollectionUtils.isEmpty(flowRuleEntityList)) {List<FlowRuleEntity> flowRuleEntities = JSONArray.parseArray(flowRuleEntityList.toString(), FlowRuleEntity.class);long id = 1;for (FlowRuleEntity entity : flowRuleEntities) {entity.setId(id++);entity.getClusterConfig().setFlowId(entity.getId());}return flowRuleEntities;} else {return null;}}@Overrideprotected String getDataId() {return ApolloConfigUtil.getFlowDataId();} }③ 實(shí)現(xiàn) Sentinel Apollo 規(guī)則訂閱
@Component("apolloFlowRulePublisher") public class ApolloFlowRulePublisher extends BaseApolloRulePublisher<List<FlowRuleEntity>> {@Overridepublic void publish(String app, String operator, List<FlowRuleEntity> rules) throws Exception {if (!CollectionUtils.isEmpty(rules)) {for (int i = 0; i < rules.size(); i++) {rules.get(i).setId((long) (i + 1));rules.get(i).setApp(null);rules.get(i).setGmtModified(null);rules.get(i).setGmtCreate(null);rules.get(i).setIp(null);rules.get(i).setPort(null);rules.get(i).getClusterConfig().setFlowId((long) (i + 1));}} else {rules = null;}super.publish(app, operator, rules);}@Overrideprotected String getDataId() {return ApolloConfigUtil.getFlowDataId();} }上述代碼實(shí)現(xiàn)了對?Apollo?配置讀寫操作。熟悉?Apollo?的同學(xué)應(yīng)該知道,這些操作需要基于?Apollo OpenApi?來操作;動(dòng)態(tài)感知能力的邏輯已經(jīng)由?sentinel-datasource-apollo?模塊實(shí)現(xiàn)。
Sentinel 集成 Skywalking
由于掌門1對1微服務(wù)技術(shù)棧落地的比較早,鑒于歷史的局限性(當(dāng)時(shí)沒有更先進(jìn)的技術(shù)可供選擇),除了 Hystrix 比較古老以外,另一個(gè)技術(shù)棧的痛點(diǎn)是全鏈路監(jiān)控中間件的改造也提上議事日程,CAT 作為開源界老牌作品,為公司底層全鏈路監(jiān)控提供強(qiáng)有力的保障,但隨著技術(shù)的演進(jìn),它逐漸已經(jīng)不適合公司的未來發(fā)展方向,經(jīng)過對比,最終選擇 Skywalking 將作為它的替代者(關(guān)于 Skywalking 的技術(shù)選型,將在后面掌門1對1微服務(wù)體系 Solar 的公眾號(hào)系列文章中會(huì)一一闡述)。
業(yè)務(wù)系統(tǒng)要求對限流熔斷降級(jí)實(shí)現(xiàn)全鏈路實(shí)時(shí)埋點(diǎn),并希望在?Skywalking?界面上提供限流熔斷降級(jí)埋點(diǎn)的多維度統(tǒng)計(jì)。由于?Skywalking?實(shí)現(xiàn)了?OpenTracing?標(biāo)準(zhǔn)化協(xié)議,那么以?OpenTracing?為橋梁,通過?Solar?SDK 輸出?Sentinel?埋點(diǎn)到?Skywalking?Server 不失為一個(gè)好的技術(shù)選擇。下面簡單扼要介紹一下基于?Sentinel InitFunc?的?SPI?機(jī)制實(shí)現(xiàn)埋點(diǎn)輸出:
Sentinel?將?ProcessorSlot?作為?SPI?接口進(jìn)行擴(kuò)展(1.7.2 版本以前?SlotChainBuilder?作為?SPI?),使得?Slot Chain?具備了擴(kuò)展的能力。您可以自行加入自定義的 slot 并編排 slot 間的順序,從而可以給?Sentinel?添加自定義的功能。
摘自官網(wǎng)?Sentinel 工作主流程
抽象 Sentinel ProcessorSlot 埋點(diǎn)輸出
Sentinel?的?ProcessorSlotEntryCallback?提供?onPass?和?onBlocked?兩個(gè)方法,畢竟限流熔斷降級(jí)并不是常規(guī)的功能,不會(huì)發(fā)生在大流量上面,所以?onPass?上我們不做任何處理,否則正常的調(diào)用去實(shí)現(xiàn)攔截,將為產(chǎn)生大量的埋點(diǎn)數(shù)據(jù),會(huì)讓?Skywalking?Server 承受很大的性能壓力,所以?onBlocked?將是我們關(guān)注的重點(diǎn),它除了輸出?Sentinel?本身的上下文參數(shù)之外,也會(huì)輸出微服務(wù)?Solar?指標(biāo)參數(shù),主要包括:
- 埋點(diǎn)?Span名稱,這里為?SENTINEL?,在?Skywalking?全鏈路監(jiān)控界面中,用戶可以非常容易的找到這個(gè)埋點(diǎn)
- 服務(wù)所在的組名,指服務(wù)的邏輯分組
- 服務(wù)類型,包括服務(wù)和網(wǎng)關(guān)(網(wǎng)關(guān)也是一種特殊的服務(wù)),?Sentinel?埋點(diǎn)可以支持在服務(wù)和網(wǎng)關(guān)上的輸出
- 服務(wù)的?APPID,它為?Apollo?組件的范疇概念
- 服務(wù)名,它對應(yīng)為?spring.application.name?的配置值
- 服務(wù)實(shí)例所在的?IP?地址和?Port?端口
- 服務(wù)版本號(hào)
- 服務(wù)所在的區(qū)域
- 服務(wù)所在的子環(huán)境
接下去是?Sentinel?層面的參數(shù),請自行參考?Sentinel?官方文檔和源碼,了解其含義,這里不做具體講解。
public abstract class SentinelTracerProcessorSlotEntryCallback<S> implements ProcessorSlotEntryCallback<DefaultNode> {@Overridepublic void onPass(Context context, ResourceWrapper resourceWrapper, DefaultNode param, int count, Object... args) throws Exception {}@Overridepublic void onBlocked(BlockException e, Context context, ResourceWrapper resourceWrapper, DefaultNode param, int count, Object... args) {S span = buildSpan();PluginAdapter pluginAdapter = PluginContextAware.getStaticApplicationContext().getBean(PluginAdapter.class);outputSpan(span, DiscoveryConstant.SPAN_TAG_PLUGIN_NAME, context.getName());outputSpan(span, DiscoveryConstant.N_D_SERVICE_GROUP, pluginAdapter.getGroup());outputSpan(span, DiscoveryConstant.N_D_SERVICE_TYPE, pluginAdapter.getServiceType());String serviceAppId = pluginAdapter.getServiceAppId();if (StringUtils.isNotEmpty(serviceAppId)) {outputSpan(span, DiscoveryConstant.N_D_SERVICE_APP_ID, serviceAppId);}outputSpan(span, DiscoveryConstant.N_D_SERVICE_ID, pluginAdapter.getServiceId());outputSpan(span, DiscoveryConstant.N_D_SERVICE_ADDRESS, pluginAdapter.getHost() + ":" + pluginAdapter.getPort());outputSpan(span, DiscoveryConstant.N_D_SERVICE_VERSION, pluginAdapter.getVersion());outputSpan(span, DiscoveryConstant.N_D_SERVICE_REGION, pluginAdapter.getRegion());outputSpan(span, DiscoveryConstant.N_D_SERVICE_ENVIRONMENT, pluginAdapter.getEnvironment());outputSpan(span, SentinelStrategyConstant.ORIGIN, context.getOrigin());outputSpan(span, SentinelStrategyConstant.ASYNC, String.valueOf(context.isAsync()));outputSpan(span, SentinelStrategyConstant.RESOURCE_NAME, resourceWrapper.getName());outputSpan(span, SentinelStrategyConstant.RESOURCE_SHOW_NAME, resourceWrapper.getShowName());outputSpan(span, SentinelStrategyConstant.RESOURCE_TYPE, String.valueOf(resourceWrapper.getResourceType()));outputSpan(span, SentinelStrategyConstant.ENTRY_TYPE, resourceWrapper.getEntryType().toString());outputSpan(span, SentinelStrategyConstant.RULE_LIMIT_APP, e.getRuleLimitApp());if (tracerSentinelRuleOutputEnabled) {outputSpan(span, SentinelStrategyConstant.RULE, e.getRule().toString());}outputSpan(span, SentinelStrategyConstant.CAUSE, e.getClass().getName());outputSpan(span, SentinelStrategyConstant.BLOCK_EXCEPTION, e.getMessage());outputSpan(span, SentinelStrategyConstant.COUNT, String.valueOf(count));if (tracerSentinelArgsOutputEnabled) {outputSpan(span, SentinelStrategyConstant.ARGS, JSON.toJSONString(args));}finishSpan(span);}protected abstract S buildSpan();protected abstract void outputSpan(S span, String key, String value);protected abstract void finishSpan(S span); }整合 OpenTracing & Skywalking
實(shí)現(xiàn)?SentinelTracerProcessorSlotEntryCallback?的三個(gè)核心方法:
- buildSpan?- 創(chuàng)建?Skywalking?的埋點(diǎn)?Span?對象
- outputSpan?- 輸出相關(guān)埋點(diǎn)數(shù)據(jù)的鍵值對到?Skywalking?的埋點(diǎn)?Span?對象中
- finishSpan?- 提交?Skywalking?的埋點(diǎn)?Span?對象到?Skywalking?Server
實(shí)現(xiàn) Sentinel InitFunc SPI 擴(kuò)展
實(shí)現(xiàn)?SPI?的擴(kuò)展切入類
public class SentinelSkywalkingTracerInitFunc implements InitFunc {@Overridepublic void init() throws Exception {StatisticSlotCallbackRegistry.addEntryCallback(SentinelSkywalkingTracerProcessorSlotEntryCallback.class.getName(), new SentinelSkywalkingTracerProcessorSlotEntryCallback());} }把?SPI?的擴(kuò)展切入類放置?\resources\META-INF\services\com.alibaba.csp.sentinel.init.InitFunc?文件中,內(nèi)容為
com.nepxion.discovery.plugin.strategy.sentinel.skywalking.monitor.SentinelSkywalkingTracerInitFunc摘自?Nepxion Discovery 開源社區(qū)
對于 Sentinel 跟 Opentracing, Skywalking, Jaeger 的集成可參考?https://github.com/Nepxion/Discovery?中的 discovery-plugin-strategy-sentinel-starter-opentracing, discovery-plugin-strategy-sentinel-starter-skywalking 等模塊。
最終在?Skywalking?全鏈路界面上輸出如下:
全鏈路調(diào)用鏈中,我們可以看到?solar-service-a?服務(wù)的鏈路上輸出了?SENTINEL?埋點(diǎn),表示?solar-service-a?上發(fā)生了?Sentinel?限流熔斷降級(jí)事件之一。
點(diǎn)擊?SENTINEL?埋點(diǎn),在呼出的內(nèi)容看板上,我們可以看到?solar-service-a?服務(wù)發(fā)生了限流事件,上面顯示限流的規(guī)則和異常信息以及微服務(wù)?Solar?指標(biāo)等一系列參數(shù)。
我們可以點(diǎn)擊界面上邊的【熔斷查詢】進(jìn)行?Sentinel?相關(guān)數(shù)據(jù)的分析和統(tǒng)計(jì)
Sentinel 集成 InfluxDB & Grafana
監(jiān)控?cái)?shù)據(jù)持久化到 InfluxDB
① Sentinel MetricFetcher 拉取數(shù)據(jù)
實(shí)現(xiàn)?Dashboard?服務(wù)端拉取?Sentinel?客戶端(即?Solar?微服務(wù))的監(jiān)控?cái)?shù)據(jù)
@Component public class MetricFetcher {@Autowired@Qualifier("influxDBMetricRepository")private MetricsRepository<MetricEntity> metricStore;... }② InfluxDB 實(shí)例初始化
@Configuration public class InfluxDBAutoConfiguration {@Value("${spring.influx.url}")private String influxDBUrl;@Value("${spring.influx.user}")private String userName;@Value("${spring.influx.password}")private String password;@Value("${spring.influx.database}")private String database;@Beanpublic InfluxDB influxDB() {InfluxDB influxDB = null;try {influxDB = InfluxDBFactory.connect(influxDBUrl, userName, password);influxDB.setDatabase(database).enableBatch(100, 1000, TimeUnit.MILLISECONDS);influxDB.setLogLevel(InfluxDB.LogLevel.NONE);} catch (Exception e) {LOG.error(e.getMessage());}return influxDB;} }③ Sentinel 數(shù)據(jù)寫入到 InfluxDB
@Component("influxDBMetricRepository") public class InfluxDBMetricRepository implements MetricsRepository<MetricEntity> {@Autowiredprivate InfluxDB influxDB;@Overridepublic void save(MetricEntity metric) {try {Point point = createPoint(metric);influxDB.write(point);} catch (Exception e) {LOG.error(e.getMessage());}}@Overridepublic void saveAll(Iterable<MetricEntity> metrics) {if (metrics == null) {return;}try {BatchPoints batchPoints = BatchPoints.builder().build();metrics.forEach(metric -> {Point point = createPoint(metric);batchPoints.point(point);});influxDB.write(batchPoints);} catch (Exception e) {LOG.error(e.getMessage());}} }Grafana 界面展現(xiàn)監(jiān)控?cái)?shù)據(jù)
Sentinel Limit-App 熔斷擴(kuò)展
掌門1對1已經(jīng)實(shí)現(xiàn)通過灰度藍(lán)綠發(fā)布方式,實(shí)現(xiàn)對流量的精確制導(dǎo)和調(diào)撥,但為了進(jìn)一步實(shí)施更安全的流量保障,引入了基礎(chǔ)指標(biāo)和灰度藍(lán)綠發(fā)布指標(biāo)的熔斷,同時(shí)也支持業(yè)務(wù)自定義指標(biāo)和組合指標(biāo)的熔斷。
通過對?Sentinel?Limit-App機(jī)制的擴(kuò)展并定制授權(quán)規(guī)則,實(shí)現(xiàn)微服務(wù)?Solar?的熔斷擴(kuò)展。對于授權(quán)規(guī)則中涉及到的參數(shù),簡要做如下說明:
- resource?為?@SentinelResource?注解的?value?,也可以是調(diào)用的?URL?路徑值
- limitApp?如果有多個(gè),可以通過?,?分隔。特別注意,下文為了描述簡單,只以單個(gè)為例
- strategy?為?0?表示白名單,符合條件就放行流量;?strategy?為?1?表示黑名單,符合條件就限制流量。特別注意,下文為了描述簡單,只以白名單為例
基礎(chǔ)指標(biāo)的熔斷
通過?Http Header?自動(dòng)攜帶下游服務(wù)的基礎(chǔ)指標(biāo)進(jìn)行全鏈路傳遞的方式,對下游調(diào)用實(shí)施基礎(chǔ)指標(biāo)的熔斷。支持如下指標(biāo):
① 服務(wù)名
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)名不滿足條件,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 A 服務(wù)名
② 服務(wù)的?APPID
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的?APPID?不滿足條件,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 A 服務(wù)的?APPID
③ 服務(wù)實(shí)例所在的?IP?地址和?Port?端口
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的?IP?地址和?Port?端口不滿足條件,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 A 服務(wù)實(shí)例所在的?IP?地址和?Port?端口
灰度藍(lán)綠發(fā)布指標(biāo)的熔斷
通過?Http Header?自動(dòng)攜帶下游服務(wù)的灰度藍(lán)綠發(fā)布指標(biāo)進(jìn)行全鏈路傳遞的方式,對下游調(diào)用實(shí)施灰度藍(lán)綠發(fā)布指標(biāo)的熔斷。支持如下指標(biāo):
① 服務(wù)所在的組名
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的組名和 B 服務(wù)的組名不一致,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 B 服務(wù)的組名
② 服務(wù)版本號(hào)
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的版本號(hào)和 B 服務(wù)的版本號(hào)不一致,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 B 服務(wù)的版本號(hào)
③ 服務(wù)所在的區(qū)域
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的區(qū)域值和 B 服務(wù)的區(qū)域值不一致,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 B 服務(wù)的區(qū)域值
④ 服務(wù)所在的子環(huán)境
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 服務(wù)的子環(huán)境值和 B 服務(wù)的子環(huán)境值不一致,該請求就會(huì)被 B 服務(wù)熔斷。
- B 服務(wù)增加配置項(xiàng)
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為 B 服務(wù)的子環(huán)境值
業(yè)務(wù)自定義指標(biāo)的熔斷
通過?Http Header?攜帶下游服務(wù)的業(yè)務(wù)自定義指標(biāo)進(jìn)行全鏈路傳遞的方式,對下游調(diào)用實(shí)施自定義指標(biāo)的熔斷。
當(dāng) A 服務(wù)發(fā)送請求到 B 服務(wù),所攜帶的 A 的自定義指標(biāo)不滿足條件,該請求就會(huì)被 B 服務(wù)熔斷。例如: A 服務(wù)把?userName?通過?Http Header?傳遞給 B 服務(wù),而 B 服務(wù)只接受?userName?為?zhangsan?的請求,那么我們可以通過如下方式來解決:
- B 服務(wù)通過適配類實(shí)現(xiàn)?Sentinel?Origin?值的解析
- B 服務(wù)的配置類里通過?@Bean?方式進(jìn)行適配類創(chuàng)建
- B 服務(wù)增加授權(quán)規(guī)則,?limitApp?為?zhangsan
假如該方式仍未能滿足業(yè)務(wù)場景,業(yè)務(wù)系統(tǒng)希望根據(jù)?userName?獲取?userType,根據(jù)用戶類型做統(tǒng)一熔斷,例如,用戶類型為?AUTH_USER?的請求才能放行,其它都熔斷,那么我們可以把上面的例子修改如下:
- B 服務(wù)的適配類更改如下:
- B 服務(wù)的授權(quán)規(guī)則更改如下:
組合指標(biāo)的熔斷
通過?Http Header?攜帶下游服務(wù)的業(yè)務(wù)自定義指標(biāo)、基礎(chǔ)指標(biāo)或者灰度藍(lán)綠發(fā)布指標(biāo)進(jìn)行全鏈路傳遞的方式,對下游調(diào)用實(shí)施組合指標(biāo)的熔斷,例如,根據(jù)傳入的微服務(wù)版本號(hào) + 用戶名,組合在一起進(jìn)行熔斷。下面示例表示為下游服務(wù)版本為?1.0?且?userName?為?zhangsan,同時(shí)滿足這兩個(gè)條件下,所有服務(wù)的請求允許被放行,否則被熔斷。
- B 服務(wù)的適配類更改如下:
- B 服務(wù)的授權(quán)規(guī)則更改如下:
Sentinel 網(wǎng)關(guān)流控實(shí)踐
闡述網(wǎng)關(guān)流控實(shí)踐的時(shí)候,我們使用精確匹配的方式對某個(gè)服務(wù)的請求做限流控制為例;對網(wǎng)關(guān)代理的?solar-service-a?服務(wù)的接口?/inspector/inspect?做限流控制為例。
API 分組管理
API?管理頁面里添加?solar-service-a, 并精確匹配串?/inspector/inspect
網(wǎng)關(guān)流控規(guī)則
在流控規(guī)則界面里配置相關(guān)的規(guī)則
最終在?Skywalking?全鏈路界面上輸出如下(跟?Solar?服務(wù)側(cè)?Sentinel?埋點(diǎn)相似,不一一闡述了):
Sentinel 集群限流實(shí)踐
我們采用?Sentinel?官方提供的嵌入式?Token Server?解決方案,即服務(wù)集群中選擇一個(gè)節(jié)點(diǎn)做為?Token Server?,同時(shí)該節(jié)點(diǎn)也作為?Token Client?響應(yīng)外部的請求的服務(wù)器。具體實(shí)現(xiàn)方式通過?Sentinel?實(shí)現(xiàn)預(yù)留的?SPI?InitFunc?接口,可以參考官方?sentinel-demo?模塊下面的?sentinel-demo-cluster-embedded?。
public class SentinelApolloTokenClusterInitFunc implements InitFunc {@Overridepublic void init() throws Exception {// Register client dynamic rule data source.initDynamicFlowRuleProperty();initDynamicParamRuleProperty();// Register token client related data source.// Token client common config:ClusterClientConfigInitializer.doInit();// Token client assign config (e.g. target token server) retrieved from assign map:ClusterClientAssignConfigInitializer.doInit();// Register token server related data source.// Register dynamic rule data source supplier for token server:ClusterRuleSupplierInitializer.doInit();// Token server transport config extracted from assign map:ServerTransportConfigInitializer.doInit();// Init cluster state property for extracting mode from cluster map data source.ClusterStateInitializer.doInit();// ServerFlowConfig 配置ServerFlowConfigInitializer.doInit();} }把?SPI?的擴(kuò)展切入類放置?\resources\META-INF\services\com.alibaba.csp.sentinel.init.InitFunc?文件中,內(nèi)容為
com.zhangmen.solar.sentinel.SentinelApolloTokenClusterInitFunc作者介紹
任浩軍,掌門基礎(chǔ)架構(gòu)部研發(fā)經(jīng)理。曾就職于平安銀行、萬達(dá)、惠普,曾負(fù)責(zé)平安銀行平臺(tái)架構(gòu)部?PaaS?平臺(tái)基礎(chǔ)服務(wù)框架研發(fā)。10 多年開源經(jīng)歷,Github?ID:@HaojunRen,Nepxion?開源社區(qū)創(chuàng)始人,Nacos?Group Member,Spring Cloud Alibaba?&?Nacos?&?Sentinel?&?OpenTracing?Committer。
張彬彬,掌門基礎(chǔ)架構(gòu)部架構(gòu)師。主要負(fù)責(zé)公司微服務(wù)架構(gòu)以及開源項(xiàng)目的開發(fā)和實(shí)踐,開源項(xiàng)目愛好者,多年互聯(lián)網(wǎng)開發(fā)經(jīng)驗(yàn)。
非常感謝阿里巴巴?Sentinel?項(xiàng)目負(fù)責(zé)人宿何在落地過程中的支持和幫助。
監(jiān)控?Java?中間件?API?Nacos?開發(fā)工具?時(shí)序數(shù)據(jù)庫?Sentinel?微服務(wù)?Spring
版權(quán)聲明:本文首發(fā)在云棲社區(qū),遵循云棲社區(qū)版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),版權(quán)歸用戶作者所有,云棲社區(qū)不為本文內(nèi)容承擔(dān)相關(guān)法律責(zé)任。云棲社區(qū)已升級(jí)為阿里云開發(fā)者社區(qū)。如果您發(fā)現(xiàn)本文中有涉嫌抄襲的內(nèi)容,歡迎發(fā)送郵件至:developer2020@service.aliyun.com?進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),阿里云開發(fā)者社區(qū)將協(xié)助刪除涉嫌侵權(quán)內(nèi)容。
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的《掌门1对1微服务体系 Solar | 阿里巴巴 Sentinel 落地实践》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI在出行场景的应用实践:路线规划、ET
- 下一篇: 引入阿里云GA,商米加速IoT产品和解决