SpringCloud踩坑記錄二

前言

繼第一次搭建springcloud環(huán)境踩坑之后,時隔三個月,第二次踩坑記錄也跟著上線了,SpringCloudConfig坑系列。第一次踩坑讓我理解了用戶線程和守護線程這一塊的知識盲點,這次踩的坑就是基本就是配置上的坑。但是多踩踩坑會讓我們更容易理解具體配置起到了什么樣的作用。


坑一:拋出異常 :No instances found of configserver (myserver)

出現(xiàn)此錯誤可以檢查一下以下幾點:

  1. 需要依賴的config-server服務(wù)myserver(自己注冊的服務(wù)名)是否注冊到了eureka注冊中心上。
  2. 如果注冊上了,檢查spring.cloud.config.discovery.service-id配置是否和服務(wù)名能對應(yīng)上。
  3. eureka.client.fetch-registry是否為true(其實默認值就是true,防止手賤誤操作)。

回顧下錯誤發(fā)生點:

    public List<ServiceInstance> getConfigServerInstances(String serviceId) {
        logger.debug("Locating configserver (" + serviceId + ") via discovery");
        List<ServiceInstance> instances = this.client.getInstances(serviceId);
        if (instances.isEmpty()) {
            throw new IllegalStateException(
                    "No instances found of configserver (" + serviceId + ")");
        }
        logger.debug("Located configserver (" + serviceId
                + ") via discovery. No of instances found: " + instances.size());
        return instances;
    }

從上方代碼可以看出,在this.client.getInstances(serviceId)獲取到實例為空的時候會拋出此異常,一步步追蹤一下,發(fā)現(xiàn)最終會調(diào)用到DiscoveryClient.getInstancesByVipAddress()方法。

    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure,
                                                       @Nullable String region) {
        if (vipAddress == null) {
            throw new IllegalArgumentException(
                    "Supplied VIP Address cannot be null");
        }
        Applications applications;
        if (instanceRegionChecker.isLocalRegion(region)) {
            applications = this.localRegionApps.get();
        } else {
            applications = remoteRegionVsApps.get(region);
            if (null == applications) {
                logger.debug("No applications are defined for region {}, so returning an empty instance list for vip "
                        + "address {}.", region, vipAddress);
                return Collections.emptyList();
            }
        }

        if (!secure) {
            return applications.getInstancesByVirtualHostName(vipAddress);
        } else {
            return applications.getInstancesBySecureVirtualHostName(vipAddress);

        }

    }

從這里可以明顯看出,要么applications為空,即注冊中心沒有可用服務(wù)或者eureka.client.fetch-registry配置成了false;要么通過vipAddressapplications查詢不出實例結(jié)果,即給定的service-id在注冊中心中不存在。

①注冊中心沒有可用服務(wù),獲取不到服務(wù)列表很容易理解。
service-id對應(yīng)不上,也很容易理解。就比如拿一個不存在的key去一個collection中獲取value,肯定是獲取不到服務(wù)的。
eureka.client.fetch-registry配置成了false,這一點需要解釋一下:

要知道咱們內(nèi)存中存儲的applications列表并不是每次請求都會進行刷新,而是維護了一個CacheRefreshThread去定時輪詢獲取注冊中心中的服務(wù),然后塞到localRegionApps中,然而,這個線程開啟需要一個條件,clientConfig.shouldFetchRegistry()==true,看方法名就知道需要eureka.client.fetch-registry=true任務(wù)才會開啟。但是默認這個值就是true,當時不曉得是不是腦子抽風了配置成了false,然后找這個bug迷糊了好一會兒。具體開啟任務(wù)線程的代碼如下所示:

   private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "cacheRefresh",
                            scheduler,
                            cacheRefreshExecutor,
                            registryFetchIntervalSeconds,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }
       ...
   }

坑二:refresh的endpoints訪問不到了

訪問ip:port/actuator/refresh返回404。在搭建的過程中,很多老版本的教程都只是說引入下方依賴即可。

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

但在springboot 2.x以上的版本,默認只對healthinfo這兩個端點進行暴露出來,如下圖所示。

而對refresh端點并未暴露出來,這里就需要咱們自己去手動配置暴露,感興趣的朋友可以去Endpoints看一下具體有哪些可以暴露的端點,咱們也可以使用 management.endpoints.web.exposure.include=*將所有端點全部暴露出來,當然,實際生產(chǎn)環(huán)境中也不建議如此。目前我測試配置management.endpoints.web.exposure.include=refresh,info,health暴露了refresh,info,health三個端點。

注意

  1. 使用refresh端點時,它只會針對有@RefreshScope注解的類和方法進行刷新。
  1. 訪問這些端點時都需要加上actuator這個basePath。

最后附上config-server端和config-client端的bootstrap.yml配置。

server端:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/crazyStrongboy/config/
          searchPaths: foo
  application:
    name:  myserver
server:
  port:  8003
eureka:
  instance:
    hostname: TTT-HJ
    instance-id: ${spring.application.name}:${server.port}
  client:
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:8000/eureka/

client端:

spring:
  application:
    name: application
  cloud:
    config:
      discovery:
        service-id: myserver
        enabled: true
      profile: dev

server:
  port: 8004
eureka:
  instance:
    hostname: TTT-HJ
    instance-id: ${spring.application.name}:${server.port}
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:8000/eureka/
    fetch-registry: true

management:
  endpoints:
    web:
      exposure:
        include: refresh,info,health

后續(xù)

目前僅僅只是簡單的測試一下springcloud config注冊中心,后續(xù)會加上springcloud bus消息總線安排一下,看看還有木有坑點繼續(xù)分享~~,具體案例見github。


END

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容