1. 程式人生 > >【spring-cloud】spring-cloud-從入門到高可用-中

【spring-cloud】spring-cloud-從入門到高可用-中

本篇帶大家從入門走向高可用,從屌絲走向高富帥...

1.先搭一個最簡單的專案,找點自信:

最簡單的spring-cloud專案需要一個註冊中心和兩個微服務,其他元件後面引入,這裡先不提,

註冊中心eurka程式碼入下:

先看依賴: 其中spring-boot版本採用2.0.4,spring-cloud版本採用 Finchley.SR1,不明白的可以去官網:http://spring.io檢視.

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # 指定註冊中心的url
    register-with-eureka: false  # 指定不進行註冊操作,預設為true,若進行註冊的話,會顯示在Eureka資訊面板上
  server:
    enable-self-preservation: false  # 禁用eureka server的自我保護機制,建議在生產環境下開啟此配置
spring:
  application:
    name: eureka-server  # 指定應用的名稱
server:
  port: 8761  # 指定專案的埠號

啟動類:

@SpringBootApplication
@EnableEurekaServer
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

服務發現中心搭好了,就是這麼簡單~

下面來看兩個服務:

我就不一一貼原始碼了,簡單說下流程,基本上spring-cloud的套路都是這樣的:

第一步:引入依賴,這裡需要引入org.springframework.cloud 的 spring-cloud-starter-netflix-eureka-client包

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

第二步:修改配置檔案application.yml 在配置檔案中指明註冊中心,服務埠號,服務名

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: ylt-test

server:
  port: 9111

第三步:啟動類上面添加註解@EnableDiscoveryClient,這樣服務發現中心Eureka就能找到這個服務了

@SpringBootApplication
@EnableDiscoveryClient
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

至此spring-cloud兩個微服務也搭建好了,這裡省略了兩個微服務提供的介面,可以自己給每個微服務寫個介面,提供的服務可以只是列印一句話.

此時先啟動eureka發現中心,再分別啟動兩個微服務,然後訪問註冊中心地址,我這裡配的是:http://localhost:8761/eureka/,開啟瀏覽器訪問,如果可以找到自己配置的服務列表,即表示成功,如圖:

此時我需要在A服務中呼叫B服務的某個介面,那麼我只需要在A服務中新增一個Feign元件:

新建一個介面,名字隨意,然後在該介面上添加註解:@FeignClient,註解裡的name或者value填寫被呼叫服務的application.name,也就是上圖中的application ,然後該介面中的方法名可以隨便取,但返回型別一定要與被呼叫介面的返回資料型別一致,且訪問的路徑也要一致,這樣才能完成呼叫.

@FeignClient(name = "ylt-diagnose")
public interface DiagnoseClient {
    @GetMapping("/diagnose")
    String getDiagnose();
}

下面我們分別啟動A服務和B服務,然後先測試一下直接在B服務中訪問該介面:

然後我們再在A服務中呼叫B服務中的該介面:

就是這麼爽,只需要簡單的寫個介面,添加個註解,就可以享受到rpc級的呼叫快感,而且被呼叫時服務端是無感知的,也就是說A要呼叫B服務,不需要修改B中的程式碼,對B而言,A服務呼叫它的介面和別人直接在瀏覽器裡訪問是一樣的,沒什麼差異,這就是spring-cloud的強大之處,當然隨著進一步學習你會發現它有多麼強大,這僅僅只是冰山一角.

2.整合zuul和config,實現統一入口和統一配置及自動拉取配置,這一塊內容比較多,建議先去spring官網或者網上找點視訊學習一下,否則直接看我貼的demo可能看不懂,我貼這個更多的是為了總結和以後如果用到了快速回憶,免得時間太久不用忘記掉.

先來看閘道器zuul,也是經典的三部曲:

第一步:新增依賴,這裡主要用到 :spring-cloud-starter-netflix-zuul和spring-cloud-starter-netflix-eureka-client,如果需要自動拉取配置的話還需要新增兩個依賴:spring-cloud-starter-bus-amqp,spring-cloud-config-client

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
 </dependency>
 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>

第二步:修改配置檔案

spring:
  application:
    name: gateway
  cloud:
    config:
      discovery:
        enabled: true
        service-id: ylt-config #配置中心config的application.name
      profile: dev
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 7777
zuul:
  sensitive-headers: #新增後可以保留敏感頭,比如cookie

第三步:

啟動類添加註解:

@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

然後啟動測試一下: 輸入zuul的ip和埠然後接上其他服務的名稱及mapping路徑,即可訪問到其他服務的介面.

下面是config配置中心:

也是一樣的三部曲:

第一步:引入依賴,因為需要自動載入配置,所以用到了rabbitmq,所以需要先在電腦上裝個rabbitmq,另外在遠端git倉庫修改配置後需要觸發遠端git的webhook,請求本地的/monitor介面來觸發修改,所以需要引入spring-cloud-config-monitor依賴.

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-monitor</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

第二步:修改配置檔案

spring:
  application:
    name: eureka-config
  cloud:
    config:
      server:
        git:
          uri: https://github.com/laohanjianshen/ylt #碼雲中建立對應的倉庫
          username: #填你自己的賬號
          password: #填你自己的密碼
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

server:
  port: 8888

第三步:啟動類添加註解

@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class ConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
    }
}

然後啟動,啟動之後在服務發現中心可以找到它,然後git倉庫中可以新增對應的配置檔案,命名與各個微服務的名字保持一致,比如我有個服務的名字叫zuul,那麼我在git倉庫中的配置檔名字就應該取為zuul.yml或者zuul-dev.yml等,然後把zuul服務中的公共配置比如資料庫連線之類的提取出來放入git中的zuul.yml,並且要把zuul中的配置檔案application.yml名字改為bootstrap.yml,這裡涉及到一個先後順序,springboot會先載入bootstrap.yml然後再載入application.yml.注意在application.name可以使用駝峰命名,但不要用符號-,例如ylt-demo否則git中的配置檔案命名也會帶-,然後就會出現無法自動載入配置的bug.

3.整合Hystrix服務降級,熔斷和dashboard(服務降級和服務監控視覺化介面)

老套路:

第一步:引入依賴

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

引入視覺化介面的依賴:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

第二步:啟動類上添加註解:

這裡特別注意,spring-cloud Finchley.SR1這個版本在圖形化介面輸入監控的服務地址後有bug,不能正常顯示監控頁面,所以啟動類裡配置了Bean,不知道什麼時候能修復.然後關於註解,可以用@SpringCloudApplication來代替前面三個註解入下圖,這樣可以少寫點註解...

且如果引用了Feign元件,其實@EnableCircuiBreaker也沒必要新增,Fei中已內建CircuiBreaker斷路器和Ribbon.

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableFeignClients
@EnableHystrixDashboard
public class YltOutpatientApplication {
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

    public static void main(String[] args) {
        SpringApplication.run(YltOutpatientApplication.class, args);
    }
}

第三步:在yml中新增配置:

feign:
  client:
    config:
      feignName:
        connectTimeout: 5000
        readTimeout: 2000
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: false
        isolation:
          thread:
            timeoutInMilliseconds: 2000

然後我們來在該服務中調其它服務,並且在其它服務中模擬呼叫場景,我傳當入的id為偶數時,被呼叫服務的執行緒不休眠,直接返回success,當我傳入的num為奇數時,被呼叫的服務休眠3秒,這樣就可以模擬出服務降級和熔斷了.

首先配置FeignClient,新建介面,然後在該介面上新增@FeignClient註解,並指明服務的name以及服務降級時fallback的類.(這裡我採用內部類方式,當然你也可以寫在外面)

@FeignClient(name = "ylt-diagnose",fallback = DiagnoseClient.DiagnoseFallBack.class)
public interface DiagnoseClient {
    @GetMapping("/diagnose")
    String getDiagnose();
    @Component
    static class DiagnoseFallBack implements DiagnoseClient{

        @Override
        public String getDiagnose() {
            return "服務被降級了";
        }
    }
}

然後我們新建一個controller來測試呼叫:

在需要啟動服務降級的方法上新增@HystrixCommand,該註解裡含有很多引數,用於配置服務降級的策略,具體的限於篇幅不多解釋,可以去spring官網:https://spring.io 去了解.

@RestController
public class HystrixController {
    @Autowired
    private DiagnoseClient diagnoseClient;

    @RequestMapping("/hystrixDiagnose")
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")
    })
    public String hystrixDiagnose(@RequestParam("num")Integer num) {
        if (num % 2 ==0){
            return "success";
        }
        return diagnoseClient.getDiagnose();
    }

    public String fb() {
        return "太擁擠了,請稍後再試";
    }

    public String fba() {
        return "fba:太擁擠了,請稍後再試";
    }

//    @RequestMapping("/fbahystrixDiagnose")
//    @HystrixCommand
//    public String fbahystrixDiagnose() {
//        return diagnoseClient.getDiagnose();
//    }
}

然後啟動專案,開啟瀏覽器進行測試:

首先我們輸入Num為1:

輸入Num為2:

OK,沒問題,預期效果達成,下面我們來看看前面配的視覺化監控介面:

介面很酷炫,一頭豪豬... 該介面需要登入,分以下三種方式:

預設的叢集監控:通過URL:http://turbine-hostname:port/turbine.stream開啟,實現對預設叢集的監控。

指定的叢集監控:通過URL:http://turbine-hostname:port/turbine.stream?cluster=[clusterName]開啟,實現對clusterName叢集的監控。

單體應用的監控:通過URL:http://hystrix-app:port/hystrix.stream開啟,實現對具體某個服務例項的監控。

演示一下第三種,以我剛剛開啟的服務降級為例:

輸入對應地址,然後點選Montior Stream 即可跳轉到檢視頁面:

頁面長這樣,然後我們測試一下看看:

當我不斷的重新整理num=1和num=2的頁面時,監控介面會不斷改變,不同顏色的字以及圓的大小等都有不同的含義,想了解更多參見spring官網.

4.整合服務追蹤zipkin

第一步:引入依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--只有下面這兩個依賴才是核心依賴-->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
            <version>2.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
            <version>2.11.2</version>
        </dependency>

第二步:啟動類添加註解

@SpringBootApplication
@EnableDiscoveryClient
@EnableZipkinServer
public class YltzipkinApplication {

    public static void main(String[] args) {
        SpringApplication.run(YltzipkinApplication.class, args);
    }
}

第三步:yml配置(這裡zipkin配置只需要指明服務發現中心地址和自己的埠號及application-name即可,主要說一下其他需要被追蹤的微服務)

spring: 
  zipkin:
    base-url: http://localhost:9411/ #指明zipkin的地址.
    service:
      name: test #指明被追蹤的服務名,儘量與專案名保持一致方便追蹤.
    enabled: true
    sender:
      type: web #指明通過哪種方式傳送服務的鏈路追蹤,這裡通過web方式,也可以採取mq,sql等方式.
  sleuth:
    sampler:
      probability: 1 #指明抽樣比率,預設為0.1即10%,這裡為了演示故調大為1更直觀.

如此就完成了zipkin服務追蹤,下面我們來看一看,啟動zipkin並訪問其地址:

可以在其中看到所有微服務之間的呼叫關係,以及每個服務之間的呼叫耗時,以及呼叫的具體介面等,這樣就可以解決多服務之間呼叫,輔助問題排查,程式碼調優等...

5.引入多服務的監控元件turbine,這裡囉嗦下為什麼要引用turbine,因為在叢集的情況下,服務之間的呼叫很可能是被負載到了不同的伺服器上,使得相同的服務重複出現在監控頁面,而我們有時往往需要一個可以把叢集服務聚合在一起進行監控的工具,此時需要通過turbine來解決.

第一步:引入依賴

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

第二步:啟動類上添加註解

@SpringBootApplication
@EnableDiscoveryClient
@EnableTurbineStream
public class TurbineApplication {

    public static void main(String[] args) {
        SpringApplication.run(TurbineApplication.class, args);
    }
}

第三步:修改yml配置檔案

spring:
  application:
    name: turbine

server:
  port: 8767
eureka:
  client:
    service-url:
      defaultZone: http://laohan:[email protected]:8761/eureka
turbine:
  combine-host-port: true #是否合併相同的服務

combine-host-port=true,可以讓同一主機上的服務通過主機名與埠號的組合來進行區分,預設情況下會以host來區分不同的服務,這會使得在本機除錯的時候,本機上的不同服務聚合成一個服務來統計。 訪問一下來試試看(http://localhost:8767/turbine.stream,當你看到data裡有內容時就說明成功了,當然如果data裡一直處於Ping的狀態時,你需要先測試幾個呼叫feign的介面,然後再來觀察,如果仍處於Ping,只能ping到一行資料,你可以堅持rabbitmq是否已經啟動,防火牆是否關閉,埠是否已開啟,配置是否正確等...:

有了該資料之後,你可以訪問dashboard,將http://localhost:8767/turbine.stream輸入並點選Monitor Stream 按鈕便可進入監控頁面了,進入監控頁面後通過不斷呼叫介面可以觀察到服務呼叫的健康狀況:

至此,spring-cloud常用的元件整合的差不多了,下一篇【spring-cloud】spring-cloud-從入門到高可用-下

將帶領大家搭建高可用的叢集配置方案以及註冊中心加密等.還有一些不常用的元件,後續會陸續補上...