Sentinel 整合 Spring Cloud + Gateway + 控制臺(tái)Nacos持久化

項(xiàng)目版本

Spring Boot版本:2.2.9.RELEASE
Spring Cloud版本:Hoxton.SR7
Spring Cloud Alibaba版本:2.2.1.RELEASE

官方doc

所有功能文檔概況
官方文檔

介紹

本文分為以下幾部分:

  • 普通服務(wù)集成
  • 控制臺(tái)整合Nacos 自己Github重新封裝地址
  • 網(wǎng)關(guān)集成(spring cloud gateway)
  • 控制臺(tái)啟動(dòng)庵寞、參數(shù)和指定Nacos地址+namespace等

Nacos持久化最終效果圖如下:

image.png

普通服務(wù)

普通服務(wù)效果圖

注:Sentinel兼容Hystrix的FallbackFactory

從 Hystrix 遷移到 Sentinel方案(官方)

Sentinel 與 Hystrix 的對(duì)比(官方)

import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class NacosProviderClientFallback implements FallbackFactory<NacosProviderClient> {

    @Override
    public NacosProviderClient create(Throwable throwable) {
        return new NacosProviderClient() {
            @Override
            public String abc(String name, int age) {
                log.error("用 nacos-provider abc 方法失敗, 異常信息={}", throwable.getMessage());
                //throw new RuntimeException("abc:" + throwable.getMessage());
                //這里直接返回BusinessException(),因?yàn)?                throw new RuntimeException("aaaaaaadssssssssssss");
//                return throwable.getClass().getName() + " : " + throwable.getMessage();
            }

            @Override
            public String getEcho(String string) {
                log.error("用 nacos-provider getEcho 方法失敗", throwable);
                throw new RuntimeException("getEcho:" + throwable.getMessage());
            }
        };
    }
}

基礎(chǔ)包

基礎(chǔ)包大概截圖:


image.png

引入以下兩個(gè)包,一個(gè)是sentinel核心組件籽御,一個(gè)是整合nacos實(shí)現(xiàn)持久化功能組件(無(wú)關(guān)順序

        <!-- alibaba Sentinel組件 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!-- alibaba Sentinel整合nacos組件 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

添加自定義異常處理(不加會(huì)返回默認(rèn)的錯(cuò)誤信息Blocked by Sentinel: XXXX

注: 網(wǎng)上方案實(shí)現(xiàn) UrlBlockHandler 接口的版本已經(jīng)比較老了攻人,新版本已經(jīng)沒(méi)有UrlBlockHandler 接口

/**
 * 沒(méi)有配資源贾惦,默認(rèn)Block異常處理(只能是Block異常)
 */
@Slf4j
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        httpServletResponse.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
        if (e instanceof FlowException) {
            log.error("FlowException 普通服務(wù)限流启搂,資源信息:" + JSON.toJSONString(e.getRule()));
            httpServletResponse.setStatus(org.springframework.http.HttpStatus.TOO_MANY_REQUESTS.value());
            ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1000, "API interface limited flow.");
        } else if (e instanceof DegradeException) {
            log.error("DegradeException 普通服務(wù)降級(jí)窖式,資源信息:" + JSON.toJSONString(e.getRule()));
            ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1001, "API interface has been degraded.");
        } else if (e instanceof ParamFlowException) {
            ParamFlowException ex = (ParamFlowException) e;
            log.error("ParamFlowException 參數(shù)熱點(diǎn)限流潮售,資源名={}痊项,參數(shù)={},資源信息={}", ex.getResourceName(), ex.getLimitParam(), JSON.toJSONString(ex.getRule()));
            ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1002, "API interface limited flow by params.");
        } else if (e instanceof AuthorityException) {
            log.error("AuthorityException 授權(quán)規(guī)則酥诽,資源信息:" + JSON.toJSONString(e.getRule()));
            ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1003, "API interface limited by authority.");
        } else if (e instanceof SystemBlockException) {
            SystemBlockException systemBlockException = (SystemBlockException) e;
            log.error("SystemBlockException鞍泉,資源名:{},資源類型:{}", systemBlockException.getResourceName(), systemBlockException.getRuleLimitApp());
            ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1004, "API interface limited by system.");
        }
    }
}

非必須肮帐。配置默認(rèn)加注解 @SentinelResource(value = "abcdd",fallbackClass = DefaultBlockFallbackHandler.class, defaultFallback = "defaultFallback") 返回的異常咖驮,可以做默認(rèn)異常配置。如果默認(rèn)不符合異常需求训枢,可以在各接口自己定制自己的異常托修,可以是同類,也可以是不同類(不同類必須指定fallbackClass屬性恒界,參照上面注解例子)

以下走的默認(rèn)異常 或 不同類異常睦刃,不在同一個(gè)類中(默認(rèn)異常加fallbackClass )

@GetMapping(value = "/woqu")
    @SentinelResource(value = "abcdd",
            fallbackClass = DefaultBlockFallbackHandler.class, defaultFallback = "defaultFallback")
    public String woqu(String name){
        if(name.equals("abc")){
            throw new IllegalArgumentException("adffdgdfg");
        }
        if(name.equals("bbb")){
            try {
                Thread.sleep(900);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return "aaaaaaasdjkl" + name;
    }

以下走的自定義異常(可以用同一個(gè)類中的,也可以用不同類中的十酣,不同類加fallbackClass 屬性)

    @SentinelResource(value = "chello", blockHandler = "exceptionHandler2", defaultFallback = "fallback2")
    @GetMapping(value = "/hello")
    public String abcd(@RequestParam(value = "name") String name, int age){
        log.info("name={}",name);
        log.info("age={}",age);
        String content = nacosProviderClient.abc(name, age);
        return "我是feign: " + content;
    }

    public String exceptionHandler2(String name, int age, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "Oops, error occurred at "+ name + ","+ age;
    }

    public String fallback2(Throwable e){
        log.info("進(jìn)入sentinelResource注解測(cè)試,進(jìn)入fallback2涩拙,參數(shù)b={}", e.getMessage());
        return "defaultFallback";
    }

最后CustomRequestOriginParser這個(gè)只要是給授權(quán)黑名單或ip(AuthorityRule)生效的,可以各微服務(wù)自定義耸采,這里放到基礎(chǔ)包只是演示

簡(jiǎn)單實(shí)現(xiàn)黑名單功能:

@Component
public class CustomRequestOriginParser implements RequestOriginParser {

    @Override
    public String parseOrigin(HttpServletRequest request) {
        // <X> 從 Header 中兴泥,獲得請(qǐng)求來(lái)源
        String origin = request.getHeader("s-user");
        // <Y> 如果為空,給一個(gè)默認(rèn)的
        if (StringUtils.isEmpty(origin)) {
            origin = "default";
        }
        return origin;
    }
}

簡(jiǎn)單實(shí)現(xiàn)ip限流功能:

@Component
public class CustomRequestOriginParser2 implements RequestOriginParser {

   @Override
   public String parseOrigin(HttpServletRequest request) {
       String ip = null;
       try {
           ip = Inet4Address.getLocalHost().getHostAddress();
       } catch (UnknownHostException e) {
           e.printStackTrace();
       }
       String u = request.getRemoteUser();
       return ip;
   }

}

微服務(wù)處理

上面基礎(chǔ)包搭建完畢虾宇,各微服務(wù)只需引入上述基礎(chǔ)包:

        <!-- sentinel自定義封裝組件 -->
        <dependency>
            <groupId>com.myyshop.framework</groupId>
            <artifactId>sentinel-spring-boot-starter</artifactId>
            <version>1.0.0-RELEASE</version>
        </dependency>

整合Nacos持久化需要引入基礎(chǔ)包(上面有)搓彻。配置則引入如下配置:

注意:下面配置的信息,只有server-addr中的地址修改成自己nacos-config的地址即可,其余信息都不需要?jiǎng)有癖幔绕涫莋roupId竭沫、dataId的格式(應(yīng)用名-flow-rules、應(yīng)用名-degrade-rules骑篙、應(yīng)用名-system-rules蜕提、應(yīng)用名-authority-rules、應(yīng)用名-param-flow-rules)靶端、rule-type不能修改谎势,這個(gè)是與sentinel控制臺(tái)源碼中推送數(shù)據(jù)到nacos約定好的。

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.128.36:8081  #主要改這里杨名,其他基本不用動(dòng)
      datasource:
        # 名稱隨意脏榆,流控?cái)?shù)據(jù)規(guī)則配置
        flow:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-flow-rules
            groupId: SENTINEL_GROUP
            # 規(guī)則類型,取值見:
            # org.springframework.cloud.alibaba.sentinel.datasource.RuleType
            rule-type: flow
            namespace: ${myyshop.sentinel.nacos.namespace}
        # 名稱隨意台谍,流控?cái)?shù)據(jù)規(guī)則配置
        degrade:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-degrade-rules
            groupId: SENTINEL_GROUP
            rule-type: degrade
            namespace: ${myyshop.sentinel.nacos.namespace}
        # 名稱隨意须喂,流控?cái)?shù)據(jù)規(guī)則配置
        system:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-system-rules
            groupId: SENTINEL_GROUP
            rule-type: system
            namespace: ${myyshop.sentinel.nacos.namespace}
        # 名稱隨意,流控?cái)?shù)據(jù)規(guī)則配置
        authority:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-authority-rules
            groupId: SENTINEL_GROUP
            rule-type: authority
            namespace: ${myyshop.sentinel.nacos.namespace}
        # 名稱隨意趁蕊,流控?cái)?shù)據(jù)規(guī)則配置
        param:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-param-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: param-flow
            namespace: ${myyshop.sentinel.nacos.namespace}
      eager: true   #控制臺(tái)熱加載坞生,false為懶加載(第一次調(diào)用接口才會(huì)加載)

Sentinel控制臺(tái)整合Nacos實(shí)現(xiàn)推拉

使用Sentinel Dashboard動(dòng)態(tài)推、拉數(shù)據(jù)同步到Nacos掷伙。

個(gè)人改Alibaba重新封裝控制臺(tái)源碼:(分支 lbj_release-1.7)

具體實(shí)現(xiàn)可以參考我整理的如下大佬們的文檔:

網(wǎng)關(guān)限流(Spring Cloud Gateway)

網(wǎng)關(guān)限流文檔(官方)

網(wǎng)關(guān)限流效果圖1
網(wǎng)關(guān)限流效果圖2

Sentinel提供針對(duì)Spring Cloud Gateway的參數(shù)開關(guān)是己,該開關(guān)是針對(duì)JVM -D(java -jar -Dproject.name=***)的開關(guān),如果要開啟Sentinel控制臺(tái)對(duì)網(wǎng)關(guān)特定頁(yè)面的開關(guān)任柜,則需要配置如下(最主要是-Dcsp.sentinel.app.type=1):
-Dcsp.sentinel.dashboard.server=192.168.128.36:8081 -Dcsp.sentinel.app.type=1

如果application.yml中有如下配置卒废,則不需要加入(
-Dcsp.sentinel.dashboard.server=192.168.128.36:8081)

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.128.36:8081

添加上述jar包啟動(dòng)參數(shù)之后,需要加入如下pom包依賴(引包順序要嚴(yán)格按照下面這樣宙地,測(cè)試換位置不生效摔认,不知道為什么

       <!--sentinel gateway依賴包-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

引入上述pom包依賴后,還需加入如下配置(主要是Nacos持久化配置):

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.128.36:8081    #主要改這里宅粥,其他基本不用動(dòng)
      datasource:
        gw-flow:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-gw-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: gw-flow
            namespace: ${myyshop.sentinel.nacos.namespace}
        gw-api-group:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-gw-api-rules
            groupId: SENTINEL_GROUP
            rule-type: gw-api-group
            namespace: ${myyshop.sentinel.nacos.namespace}
        degrade:
          nacos:
            server-addr: ${spring.cloud.nacos.config.server-addr}
            dataId: ${spring.application.name}-degrade-rules
            groupId: SENTINEL_GROUP
            rule-type: degrade
            namespace: ${myyshop.sentinel.nacos.namespace}
      eager: true      #控制臺(tái)熱加載参袱,false為懶加載(第一次調(diào)用接口才會(huì)加載)

網(wǎng)關(guān)需要加入配置(主要是異常相關(guān)格式化,還有代碼限流粹胯、降級(jí)等)

@Configuration
public class SentinelGatewayConfig {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public SentinelGatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                 ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

//    @Bean
//    @Order(Ordered.HIGHEST_PRECEDENCE)
//    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
//        // Register the block exception handler for Spring Cloud Gateway.
//        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
//    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new JsonSentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

//    @Bean
//    @Order(-1)
//    public GlobalFilter sentinelGatewayFilter() {
//        return new SentinelGatewayFilter();
//    }

/*****************************************************************************/

//以下是添加 API 分組和route 維度

//    @PostConstruct
//    public void doInit() {
//        initCustomizedApis();
//        initGatewayRules();
//    }

    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("some_customized_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/Hansen666666"));
//                    add(new ApiPathPredicateItem().setPattern("/gprovider/**")
//                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }


    /**
     * 配置限流規(guī)則
     */
    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();

        rules.add(new GatewayFlowRule("some_customized_api")
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setCount(2)
                .setIntervalSec(1)
        );

//        rules.add(new GatewayFlowRule("csdn")
//                .setCount(1)
//                .setIntervalSec(1)
//        );
//
//        rules.add(new GatewayFlowRule("gateway-provider")
//            .setCount(3) // 限流閾值
//            .setIntervalSec(1) // 統(tǒng)計(jì)時(shí)間窗口蓖柔,單位是秒,默認(rèn)是 1 秒
//        );

        GatewayRuleManager.loadRules(rules);
    }
}

添加自定義異常處理(不加會(huì)返回默認(rèn)的錯(cuò)誤信息Blocked by Sentinel: XXXX)风纠,下面為模仿源碼寫的自定義異常處理况鸣。
1.繼承SentinelGatewayBlockExceptionHandler類(主要為了重寫handle方法)
2.參照DefaultBlockRequestHandler類源碼handleRequest方法和acceptsHtml方法(這個(gè)是SpringBoot默認(rèn)返回的404異常頁(yè)面,也就是說(shuō)在網(wǎng)頁(yè)上會(huì)有404異常竹观,在Postman會(huì)顯示Json異常)

public class JsonSentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {

    public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        super(viewResolvers, serverCodecConfigurer);
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        } else {
            return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> {
                if(ex instanceof ParamFlowException){
                    return WebfluxResponseUtil.responseFailed(exchange, 10000, HttpStatus.TOO_MANY_REQUESTS.value(),
                            "API interface limited flow by gateway.");
                }
                if(ex instanceof DegradeException){
                    return WebfluxResponseUtil.responseFailed(exchange, 10001, HttpStatus.SERVICE_UNAVAILABLE.value(),
                            "API interface degraded by gateway.");
                }
                return WebfluxResponseUtil.responseFailed(exchange, 10000, HttpStatus.TOO_MANY_REQUESTS.value(),
                        "API interface limited flow by gateway.");
            });
        }
    }

    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }
}

Sentinel控制臺(tái)

控制臺(tái)文檔(官方)
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0

目前集成控制臺(tái)有兩種方式:

各自問(wèn)題參照官方FAQ
https://github.com/alibaba/Sentinel/wiki/FAQ

image.png

Sentinel的JVM -D啟動(dòng)參數(shù)配置項(xiàng)潜索,包含log文件指定路徑(官方)
https://github.com/alibaba/Sentinel/wiki/%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9

控制臺(tái)VM啟動(dòng)參數(shù)

下載jar或重新編譯源碼獲取jar后,然后添加啟動(dòng)參數(shù)啟動(dòng)控制臺(tái)懂酱,idea VM options啟動(dòng)參數(shù)如下:

-Dserver.port=8081
-Dcsp.sentinel.api.port=8723
-Dcsp.sentinel.dashboard.server=localhost:8081
-Dproject.name=sentinel-lbj
-Dserver.servlet.session.timeout=864000
-Dnacos.serverAddr=localhost:8849
-Dnacos.namespace=d4178075-92ee-429a-baad-6cd01d59b9b8

上面配置解釋:

  • -Dserver.port 為控制臺(tái)啟動(dòng)端口號(hào)(不配置默認(rèn)8080)
  • -Dcsp.sentinel.api.port Sentinel 客戶端監(jiān)控微服務(wù) API 的端口竹习,默認(rèn)8719
  • -Dcsp.sentinel.dashboard.server 默認(rèn)控制臺(tái)提供的監(jiān)控(就是sentinel-dashboard的地址),此配置必須配置列牺,如不配置整陌,則沒(méi)有sentinel-dashboard默認(rèn)控制臺(tái)
  • -Dproject.name 默認(rèn)控制臺(tái)名稱,默認(rèn)sentinel-dashboard
  • -Dserver.servlet.session.timeout 控制臺(tái)登錄過(guò)期時(shí)間瞎领,可以指定分鐘泌辫,默認(rèn)30分鐘,如 7200 表示 7200 秒九默,60m 表示 60 分鐘
  • -Dnacos.serverAddr 官方?jīng)]有此配置震放,自己加的自定義配置,指定Nacos配置中心地址
  • -Dnacos.namespace 官方?jīng)]有此配置驼修,自己加的自定義配置殿遂,指定Nacos持久化命名空間,例如本項(xiàng)目命名空間是sentinel(d4178075-92ee-429a-baad-6cd01d59b9b8)

linux 或 windows 下啟動(dòng)

下載官方j(luò)ar或拿到源碼編譯后得到j(luò)ar乙各,直接執(zhí)行下面代碼:

nohup 
  java -Dserver.port=8081 
          -Dcsp.sentinel.dashboard.server=localhost:8081
          -Dnacos.namespace=d4178075-92ee-429a-baad-6cd01d59b9b8 
          -Dnacos.serverAddr=localhost:8849 
          -Dsentinel.dashboard.auth.username=myyshop 
          -Dsentinel.dashboard.auth.password=myyshop 
-jar 
sentinel-dashboard.jar &

上述是Linux后臺(tái)運(yùn)行方式墨礁,加入 nohup **** & 就會(huì)后臺(tái)運(yùn)行,否則關(guān)閉服務(wù)就斷了觅丰。Windows類似饵溅,不需要加 nohup **** &

Sentinel控制臺(tái)部分源碼(sentinel-dashboard)

以Nacos限流配置為例,F(xiàn)lowRuleNacosPublisher 發(fā)布配置到Nacos妇萄,發(fā)布的配置是JSON格式,但是JSON沒(méi)有格式化咬荷,不美觀冠句,以下推送到Nacos實(shí)現(xiàn)美化JSON功能,這樣容易改Nacos配置幸乒。

@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @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 name cannot be empty");
        if (rules == null) {
            return;
        }

        //lbj增加格式化懦底、美化json內(nèi)容 - start
        String content = converter.convert(rules);
        JSONArray jsonArray = JSONArray.parseArray(content);
        String prettyContent = JSON.toJSONString(jsonArray, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        //lbj增加格式化、美化json內(nèi)容 - end

        configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
            NacosConfigUtil.GROUP_ID, prettyContent);
    }
}

自己加入Nacos的 -Dnacos.serverAddr 和 -Dnacos.namespace 相關(guān)參數(shù)罕扎,這樣可以直接在JVM -D啟動(dòng)參數(shù)動(dòng)態(tài)加聚唐,而不用改源碼,再編譯腔召,這樣很麻煩:

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        String namespace = System.getProperty("nacos.namespace");
        String serverAddr = Optional.ofNullable(System.getProperty("nacos.serverAddr")).orElse("localhost:8848");
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        if(StringUtil.isNotBlank(namespace)){
            properties.setProperty(PropertyKeyConst.NAMESPACE, namespace);
        }
        return ConfigFactory.createConfigService(properties);

    }

上述配置在 NacosConfig 類中掏呼,通過(guò)System.getProperty獲取啟動(dòng)參數(shù)盅安,
獲取 namespace 和 serverAddr

踩坑記錄

如果你的微服務(wù)部署在docker中,并且沒(méi)有指定host模式(--net=host),默認(rèn)docker會(huì)走bridge模式己儒,那這樣docker鏡像內(nèi)部會(huì)分配自定義虛擬ip,這樣跟主機(jī)互ping沒(méi)有問(wèn)題,但在一個(gè)局域網(wǎng)其他網(wǎng)段ip要想ping通docker內(nèi)部虛擬ip就不行了豫领。

而現(xiàn)在國(guó)內(nèi)大部分公司都是使用docker去部署服務(wù),Sentinel默認(rèn)拿到ip是docker內(nèi)部的虛擬ip舔琅,如果Sentinel部署在另外一臺(tái)機(jī)器上(生產(chǎn)都要分開部署)等恐,則拿不到當(dāng)前服務(wù)的簇點(diǎn)鏈路,因?yàn)镾entinel訪問(wèn)不到當(dāng)前服務(wù)的端口數(shù)據(jù)(假如當(dāng)前服務(wù)ip+端口=172.17.0.3:8719)备蚓。

注:172.17.0.3是docker內(nèi)部虛擬ip鼠锈,192.168.128.20是主機(jī)ip,8719是Sentinel客戶端監(jiān)控微服務(wù) API 的端口星著,默認(rèn)8719

host模式:使用 --net=host 指定购笆。

none模式:使用 --net=none 指定。

bridge模式:使用 --net=bridge 指定虚循,默認(rèn)設(shè)置同欠。

container模式:使用 --net=container:NAME_or_ID 指定。

因此有兩種方案可以解決此情況:

  1. 將docker默認(rèn)模式改成host模式(--net=host)
  2. 將Sentinel要監(jiān)控的API端口(默認(rèn)8719)從docker中綁定到宿主機(jī)上横缔,可以使用 -p 參數(shù)顯式將一個(gè)或者一組端口從容器里綁定到宿主機(jī)上(ip:hostPort:containerPort)

第一套方案不用說(shuō)了铺遂,如果選定第二套方案,需要每個(gè)微服務(wù)都配置一個(gè)端口暴露給Sentinel茎刚,如果10個(gè)微服務(wù)襟锐,就暴露10個(gè),不能重復(fù)膛锭,需要如下配置(這里以u(píng)aa為例):

spring:
  cloud:
    sentinel:
      transport:
        client-ip: 192.168.128.20   #如果是docker容器粮坞,需要指定宿主機(jī)ip,這樣sentinel就不會(huì)拉docker內(nèi)虛擬ip
        port: 8777    #指定Sentinel客戶端監(jiān)控微服務(wù)API的端口初狰,

上述ip+端口配置好后(以u(píng)aa為例)莫杈,通過(guò)docker run啟動(dòng)uaa服務(wù)(這里uaa暴露給sentinel的端口是8777,其他服務(wù)端口盡量不能重復(fù))奢入,配置如下:

docker run -p 7001:7001 -p 8777:8777 --name ${app_name} \
--link registry2:registry2 \
-v /usr/local/server-log/uaa-server:/logs \
-d ${app_name}:latest

注:8777是Sentinel客戶端監(jiān)控 uaa的端口筝闹,不指定默認(rèn)8719

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市腥光,隨后出現(xiàn)的幾起案子关顷,更是在濱河造成了極大的恐慌,老刑警劉巖武福,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件议双,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡艘儒,警方通過(guò)查閱死者的電腦和手機(jī)聋伦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門夫偶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人觉增,你說(shuō)我怎么就攤上這事兵拢。” “怎么了逾礁?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵说铃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我嘹履,道長(zhǎng)腻扇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任砾嫉,我火速辦了婚禮幼苛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘焕刮。我一直安慰自己舶沿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布配并。 她就那樣靜靜地躺著括荡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溉旋。 梳的紋絲不亂的頭發(fā)上畸冲,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音观腊,去河邊找鬼邑闲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恕沫,可吹牛的內(nèi)容都是我干的监憎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼婶溯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了偷霉?” 一聲冷哼從身側(cè)響起迄委,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎类少,沒(méi)想到半個(gè)月后叙身,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硫狞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年信轿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晃痴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡财忽,死狀恐怖倘核,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情即彪,我是刑警寧澤紧唱,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站隶校,受9級(jí)特大地震影響漏益,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜深胳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一绰疤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舞终,春花似錦轻庆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至攘蔽,卻和暖如春龙屉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背满俗。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工转捕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人唆垃。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓五芝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親辕万。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枢步,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容