Sentinel集成Nacos實(shí)現(xiàn)動(dòng)態(tài)流控規(guī)則

Sentinel的理念是只需要開(kāi)發(fā)者關(guān)注資源的定義,它默認(rèn)會(huì)對(duì)資源進(jìn)行流控。當(dāng)然,我們還是需要對(duì)定義的資源設(shè)置流控規(guī)則,主要有兩種方式:

  • 通過(guò)FlowRuleManager.loadRules()手動(dòng)加載流控規(guī)則。
  • 在Sentinel Dashboard上針對(duì)資源動(dòng)態(tài)創(chuàng)建流控規(guī)則。

針對(duì)第一種方式,如果接入Sentinel Dashboard,那么同樣支持動(dòng)態(tài)修改流控規(guī)則,但是基于Sentinel Dashboard所配置的流控規(guī)則,都是保存在內(nèi)存中的,一旦應(yīng)用重啟,這些規(guī)則都會(huì)被清除。為了解決這個(gè)問(wèn)題,Sentinel提供了動(dòng)態(tài)數(shù)據(jù)源支持。

目前,Sentinel支持Consul、Zookeeper、Redis、Nacos、Apollo、etcd等數(shù)據(jù)源的擴(kuò)展,接下來(lái)通過(guò)一個(gè)案例展示Spring Cloud Sentinel集成Nacos實(shí)現(xiàn)動(dòng)態(tài)流控規(guī)則,步驟如下:

  1. 添加Nacos數(shù)據(jù)源的依賴(lài)包
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.0</version>
</dependency>
  1. 創(chuàng)建一個(gè)REST接口,用于測(cè)試
@RestController
public class DynamicController {

    @GetMapping("/dynamic")
    public String dynamic() {
        return "Hello Dynamic Rules";
    }
}
  1. 在application.yml文件中添加數(shù)據(jù)源配置
spring:
  application:
    name: sentinel-spring-cloud-demo
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.56.1:7777
      datasource:
        - nacos:
            server-addr: 192.168.56.1:8848
            data-id: ${spring.application.name}-sentinel
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow

部分配置說(shuō)明如下:

  • datasource: 目前支持redis、apollo、zk、file、nacos,選什么類(lèi)型的數(shù)據(jù)源就配置相應(yīng)的key即可。
  • data-id:可以設(shè)置成${spring.application.name},方便區(qū)分不同應(yīng)用的配置。
  • rule-type:表示數(shù)據(jù)源中規(guī)則屬于哪種類(lèi)型,如flow、degrade、param-flow、gw-flow等。
  • data-type:指配置項(xiàng)的內(nèi)容格式,Spring Cloud Alibaba Sentinel提供了JSON和XML兩種格式,如需要自定義,則可以將值配置為custom,并配置converter-class指向converter類(lèi)。
  1. 登陸Nacos控制臺(tái),創(chuàng)建流控配置規(guī)則:


    在這里插入圖片描述
  2. 登陸Sentinel Dashboard,找到執(zhí)行項(xiàng)目名稱(chēng)菜單下的“流控規(guī)則”,就可以看到在Nacos上所配置的流控規(guī)則已經(jīng)被加載了。


    在這里插入圖片描述
  3. 當(dāng)我們?cè)贜acos的控制臺(tái)上修改流控規(guī)則后,可以同步的在Sentinel Dashboard上看到流控規(guī)則的變化。

那么問(wèn)題就來(lái)了,Nacos其實(shí)應(yīng)該作為一個(gè)流控規(guī)則的持久化平臺(tái),正常的操作過(guò)程應(yīng)該是在Sentinel Dashboard上修改流控規(guī)則,然后同步到Nacos上,但是遺憾的是,目前Sentinel Dashboard并不支持該功能。

所以,Nacos名義上是"Datasource",實(shí)際上充當(dāng)?shù)娜匀皇桥渲弥行牡慕巧_(kāi)發(fā)者可以在Nacos控制臺(tái)上動(dòng)態(tài)修改流控規(guī)則并實(shí)現(xiàn)規(guī)則同步。在實(shí)際開(kāi)發(fā)中,很難避免在不清楚情況的情況下,部分開(kāi)發(fā)者使用Sentinel Dashboard來(lái)管理流控規(guī)則,部分開(kāi)發(fā)者通過(guò)Nacos來(lái)管理流控規(guī)則,這可能導(dǎo)致非常嚴(yán)重的問(wèn)題。

要想使用Sentinel Dashboard來(lái)統(tǒng)一管理流控規(guī)則并同步到Nacos上,我們可以自己來(lái)實(shí)現(xiàn)。

Sentinel Dashboard集成Nacos實(shí)現(xiàn)規(guī)則同步

Sentinel Dashboard的流控規(guī)則下的所有操作,都會(huì)調(diào)用Sentinel-Dashboard源碼中的FlowControllerV1類(lèi),這個(gè)類(lèi)中包含流控規(guī)則本地化 的CRUD操作。

另外,在com.alibaba.csp.sentinel.dashboard.controller.v2包下存在一個(gè)FlowControllerV2類(lèi),這個(gè)類(lèi)同樣提供流控規(guī)則的CRUD,和V1版本不同的是,它可以實(shí)現(xiàn)指定數(shù)據(jù)源的規(guī)則拉取和發(fā)布。

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

    @Autowired
    @Qualifier("flowRuleDefaultProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleDefaultPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

FlowControllerV2依賴(lài)以下兩個(gè)非常重要的類(lèi):

  • DynamicRuleProvider: 動(dòng)態(tài)規(guī)則的拉取,從指定數(shù)據(jù)源中獲取流控規(guī)則后在Sentinel Dashboard中展示。
  • DynamicRulePublisher: 動(dòng)態(tài)規(guī)則的發(fā)布,將在Sentinel Dashboard中修改的規(guī)則同步到指定數(shù)據(jù)源中。

我們可以擴(kuò)展這兩個(gè)類(lèi),然后集成Nacos來(lái)實(shí)現(xiàn)Sentinel Dashboard規(guī)則的同步。

Sentinel Dashboard源碼修改

修改Sentinel Dashboard的源碼,具體實(shí)現(xiàn)步驟如下:

  1. 在GitHub中下載Sentinel Dashboard 1.7.1的源碼。
  2. 使用IDEA工具打開(kāi)sentinel-dashboard工程。
  3. 在pom.xml中把sentinel-datasource-nacos依賴(lài)的<scope>注釋掉。
<!-- for Nacos rule publisher sample -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <!--<scope>test</scope>-->
</dependency>
  1. 修改resources/app/scripts/directives/sidebar/sidebar.html文件中下面這段代碼,將dashboard.flowV1改成dashboard.flow,也就是去掉V1。修改之后,會(huì)調(diào)用FlowControllerV2中的接口。
<li ui-sref-active="active" ng-if="!entry.isGateway">
  <!--<a ui-sref="dashboard.flowV1({app: entry.app})">-->
  <a ui-sref="dashboard.flow({app: entry.app})">
    <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控規(guī)則</a>
</li>
  1. 在com.alibaba.csp.sentinel.dashboard.rule包中創(chuàng)建一個(gè)Nacos包,并創(chuàng)建一個(gè)類(lèi)用來(lái)加載外部化配置。
@ConfigurationProperties(prefix = "sentinel.nacos")
public class NacosPropertiesConfiguration {

    private String serverAddr;
    private String dataId;
    private String groupId = "DEFAULT_GROUP";
    private String namespace;
    // 省略get/set方法
}
  1. 創(chuàng)建一個(gè)Nacos配置類(lèi)NacosConfiguration
@EnableConfigurationProperties(NacosPropertiesConfiguration.class)
@Configuration
public class NacosConfiguration {

    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, FlowRuleEntity.class);
    }

    @Bean
    public ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws NacosException {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr());
        properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace());
        return ConfigFactory.createConfigService(properties);
    }

}
  1. 創(chuàng)建一個(gè)常量類(lèi)NacosConstants,分別表示默認(rèn)的GROUP_ID和DATA_ID的后綴
public class NacosConstants {

    public static final String DATA_ID_POSTFIX = "-sentinel-flow";
    public static final String GROUP_ID = "DEFAULT_GROUP";
}
  1. 實(shí)現(xiàn)動(dòng)態(tài)從Nacos配置中心獲取流控規(guī)則
@Service
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

    private static final Logger logger = LoggerFactory.getLogger(FlowRuleNacosProvider.class);

    @Autowired
    private NacosPropertiesConfiguration nacosPropertiesConfiguration;

    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<String, List<FlowRuleEntity>> converter;

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        String dataId = new StringBuilder(appName).append(NacosConstants.DATA_ID_POSTFIX).toString();
        String rules = configService.getConfig(dataId, nacosPropertiesConfiguration.getGroupId(), 3000);
        logger.info("pull flow rule from Nacos Config: {}", rules);
        if (StringUtils.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}
  1. 創(chuàng)建一個(gè)流控規(guī)則發(fā)布類(lèi),在Sentinel Dashboard上修改完配置后,需要調(diào)用該發(fā)布方法將數(shù)據(jù)持久化到Nacos中。
@Service
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @Autowired
    private NacosPropertiesConfiguration nacosPropertiesConfiguration;

    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<List<FlowRuleEntity>, String> converter;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app cannot be empty");
        if (rules == null) {
            return;
        }
        String dataId = new StringBuilder(app).append(NacosConstants.DATA_ID_POSTFIX).toString();
        configService.publishConfig(dataId, nacosPropertiesConfiguration.getGroupId(), converter.convert(rules));
    }
}
  1. 修改FlowControllerV2類(lèi),將上面配置的兩個(gè)類(lèi)注入進(jìn)來(lái),表示規(guī)則的拉取和規(guī)則的發(fā)布統(tǒng)一用我們前面定義的兩個(gè)實(shí)例,然后將FlowControllerV2這個(gè)類(lèi)中的代碼覆蓋FlowControllerV1的代碼
@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
  1. 在application.properties文件中添加Nacos服務(wù)端的配置信息
sentinel.nacos.serverAddr=192.168.56.1:8848
sentinel.nacos.namespacec=
sentinel.nacos.group-id=DEFAULT_GROUP
  1. 使用下面命令將代碼打包成一個(gè) fat jar,然后啟動(dòng)。
mvn clean package
Sentinel Dashboard規(guī)則數(shù)據(jù)同步

對(duì)于應(yīng)用程序來(lái)說(shuō),需要改動(dòng)的地方比較少,只需要注意配置文件中的data-id的命名要以-sentinel-flow結(jié)尾即可,因?yàn)樵趕entinel dashboard中我們寫(xiě)了一個(gè)固定的后綴。

spring:
  application:
    name: spring-cloud-sentinel-dynamic
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.56.1:7777
      datasource:
        - nacos:
            server-addr: 192.168.56.1:8848
            data-id: ${spring.application.name}-sentinel-flow
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow
  1. 登陸Sentinel Dashboard,進(jìn)入“流控規(guī)則”,然后針對(duì)指定的資源創(chuàng)建流控規(guī)則。
  2. 進(jìn)入Nacos控制臺(tái),就可以看到在Sentinel Dashboard中配置的流控規(guī)則。


    在這里插入圖片描述
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,409評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,569評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,360評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,895評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,123評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,559評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,742評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,981評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,363評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,622評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,354評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,707評(píng)論 2 370