springcloud全套教程(學習筆記)

*** springcloud相關maven依賴介紹:
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>*********</artifactId>
    </dependency>
    
    spring-cloud-starter-parent 具備spring-boot-starter-parent同樣功能並附加Spring Cloud的依賴  
    spring-cloud-starter-config 默認的配置服務依賴,快速自動引入服務的方式,端口8888 
    spring-cloud-config-server/client 用戶自定義配置服務的服務端/客戶端依賴  
    spring-cloud-starter-eureka-server 服務發現的Eureka Server依賴  
    spring-cloud-starter-eureka 服務發現的Eureka客戶端依賴  
    spring-cloud-starter-hystrix/zuul/feign/ribbon 斷路器(Hystrix),智能路有(Zuul),客戶端負載均衡(Ribbon)的依賴  
    angular-ui-router 頁面分發路由依賴

    
    
*** springcloud相關使用註解:
 
 @EnableEurekaServer ->代表該啓動類是一個eureka server端,也就是註冊中心
 @EnableEurekaClient ->代表該啓動類是一個eureka client端,也就是服務生產者/消費者
 @EnableDiscoveryClient ->代表該服務是一個可被發現的服務提供者
 @LoadBalanced -> 代表ribbon的負載均衡開啓
 @RibbonClient -> 代表自定義ribbon的負載均衡規則機制
 @HystrixCommand(fallbackMethod = "deptGetById_GET") -> 服務熔斷機制,並指定熔斷處理方法
 @EnableCircuitBreaker   -> 表示某客戶端開啓服務熔斷機制

 

***相關概念介紹 :

  1. restTempl調用:springcloud是基於rest風格進行調用的微服務框架,所以,我們可以通過搭建一個生產者工程,提供增刪改查的API接口,在消費者中,通過注入restTemplate的bean的方式,調用生產者啓動的API接口,來完成消費者與生產者之間的相互調用(並沒有使用到eurake註冊中心)restTemplate是一個spring提供的用於訪問客戶端模板工具類
  2. lombok工具的使用: 能夠對實體類自動生成get、set等方法,通過註解的方式完成編譯

 

目錄

一:微服務簡介

1. 什麼是微服務?

2. 微服務的優缺點?

3. 微服務技術棧

二:eureka註冊中心

1. 創建註冊中心工程

2. eureka註冊中心集羣設置

3.  eureka與zookeeper註冊中心的區別

三:eurekaClient:(服務註冊與發現)

1. 引入主要pom文件

2. 創建application配置文件

3. actuator與註冊中心微服務信息完善(spring-boot-starter-actuator(健康監控)配置和使用)

   3.1 打開在註冊中心顯示服務本身IP及端口

3.2 如何點擊服務名,進入詳情頁? 

4. eureka的自我保護機制

5. 服務的發現Discovery(對外暴露微服務的信息,提供API接口)

四:ribbon負載均衡

1. 負載均衡LB(Load Balance)簡介:

2. ribbon初步配置:

3. ribbon的負載均衡調用

4. ribbon負載均衡的服務調用機制(自帶七種方式)

5. ribbon的自定義負載均衡機制設置


一:微服務簡介

1. 什麼是微服務?

拆分系統,一個模塊一個微服務,之間通過HTTP的restful風格進行互相調用。

2. 微服務的優缺點?

        優點:降低了系統之間的耦合、增加了系統的高併發可用、減少維護成本、增加了代碼的複用性。
        缺點:增加了資源使用成本...

3. 微服務技術棧

一個分佈式的微服務架構,應該是由多種維度(技術)組合搭配而成的一個完整的架構,都有哪些維度組成?

springcloud技術維度一覽表
服務開發技術 spring、springboot、springMVC...
服務配置與管理 Netflix公司的Archaius、阿里的diamond...
服務註冊與發現(z註冊中心) Eureka、zookeeper、consul...
服務調用(服務之間通訊方式) restFul風格、RPC、GRPC
服務熔斷器(容災處理) Hystrix、Envoy等
負載均衡     Ribbon、nginx等
服務接口調用(消費者調用生產者的方式) Feign(基於ribbon封裝)等
消息隊列     kafka、rabbitMQ、activeMQ等
服務配置中心 SpringCloudConfig、Chef等
服務路由網關(通過配置路由訪問服務) Zuul等
服務監控中心 zabbix、nagios、metrics、spectator等
全鏈路追蹤(追蹤服務之間互相調用等情況) zipkin、brave、dapper等
服務部署     Docket、openStack、kubernetes
事件消息總線 Spring Cloud Bus
數據流操作開發包 Spring Cloud Stream
   

springcloud微服務架構,是一整套的微服務解決方案,通過各個不同的維度功能技術,將一個有一個的springboot服務工程連接起來,互相調用,從而形成帶有集羣的分佈式服務系統。

二:eureka註冊中心

1. 創建註冊中心工程

      1.1 引入pom文件

            <!--eurekaServer註冊中心所需要的依賴jar包-->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-eureka-server</artifactId>
			</dependency>

      1.2 創建application配置文件

            1.2.1. 設置端口號
            1.2.2. 設置eureka的服務地址以及是否發現該服務
            1.2.3. 設置註冊中心地址

      application.yml文件配置:
         

   server:
      port: 8001
   eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false  #false表示不想註冊中心註冊自己
        fetch-registry: false         #false表示自己就是註冊中心,不需要去檢索註冊中心上的服務
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eurekaServer/   #設置客戶端(消費者與生產者)進行註冊和查詢服務的地址

      1.3  通過@EnableEurekaServer在啓動類中標誌該服務是一個註冊中心,完成啓動

2. eureka註冊中心集羣設置

      設置多個eureka集羣,使服務架構變的更加高可用,能夠更好的適應高併發的場景,本例設置三個註冊中心集羣8001/8002/8003

設置方法過程:

      2.1 創建多個eureka子工程,並copy啓動類和配置文件。主要修改:

      在8001端口的eurekayml文件中:添加其他集羣註冊中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8002/eureka/,http://localhost:8003/eureka/

     在8002端口的eurekayml文件中:添加其他集羣註冊中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8001/eureka/,http://localhost:8003/eureka/

     在8003端口的eurekayml文件中:添加其他集羣註冊中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8001/eureka/,http://localhost:8002/eureka/

   2.2 客戶端訪問eureka時。同樣defaultZone註冊中心地址設置爲多個:

      eureka.client.service-url.defaultZone:

        http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/

   2.3 註冊中心集羣設置完成,此時發佈一個服務後,三個註冊中心均會被註冊進去。

3.  eureka與zookeeper註冊中心的區別

 3.1 兩者之間最大的區別:eureka是AP(可用性,分區容錯性)、zookeeper是CP(數據強一致性,分區容錯性)

 3.2 分佈式架構的設計都圍繞着一個原則:C(一致性)A(可用性)P(分區容錯性)

三:eurekaClient:(服務註冊與發現)

本文將創建一個7001/7002/7003端口的服務提供項目爲客戶端提供服務,三個端口均爲相同項目,設置爲不同端口意爲將該服務設置爲集羣。

1. 引入主要pom文件

<!--表示該服務是eureka client的客戶端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

2. 創建application配置文件

      2.1 設置端口;

      2.2 申明註冊中心地址

      2.3 業務所需配置(mybatis/jdbc等信息)

      2.4 同樣的配置創建三個項目,設置不同端口號,設置不同的eureka.instance.instance-id

            server:
			  port: 7001

			#mybatis的配置文件地址、實體類、映射文件mapper路徑
			mybatis:
			  config-location: classpath:mybatis/mybatis.cfg.xml
			  type-aliases-package: com.gugui.PO
			  mapper-locations: classpath:mybatis/mapper/**/*.xml

			spring:
			  datasource:
				url: jdbc:mysql://127.0.0.1:3306/spring_cloud?characterEncoding=UTF-8
				username: root
				password: root
				driver-class-name: org.gjt.mm.mysql.Driver
				type: com.alibaba.druid.pool.DruidDataSource
				dbcp:
				dbcp2:
				  min-idle: 5
				  max-total: 5
				  initial-size: 5
				  max-wait-millis: 2000
			  application:
				name: producer-dept   #服務名
			eureka:
			  client:
				service-url:
				  defaultZone: http://www:8001/eureka/
			  #註冊到eureka上時,該服務顯示的別名
			  instance:
				instance-id: produck-7001

3. actuator與註冊中心微服務信息完善(spring-boot-starter-actuator(健康監控)配置和使用)

本步驟設置該服務在註冊中心上的別名以及點擊該服務別名後,顯示服務提供者的IP以及端口等詳細信息,有助於在同一個註冊中心,註冊了N個服務和集羣,方便區分方便定位

在只設置了instance-id時,註冊中心截圖如下:

   3.1 打開在註冊中心顯示服務本身IP及端口

      eureka.client.instance.prefer-ip-address=true。此時點擊服務名,即可顯示IP

3.2 如何點擊服務名,進入詳情頁? 

在不設置時,點擊服務名進去會報錯。此時就需要(健康監控)配置和使用相關內容了

添加jar包:

<!--spring-boot-starter-actuator(健康監控)配置和使用-->
				<dependency>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-actuator</artifactId>
				</dependency>

 在client微服務的yml文件中,添加info信息:

#註冊中心頁面訪問時,點擊微服務連接後進行顯示的信息
				info:
				  appName: produck-7001
				  companyName: kangce
				  buildArtifactId: $project.artifactId$
				  version: $project.version$

其中$project.artifactId$可以通過maven中pom文件設置build規則設置讀取

此時,點擊註冊中心的鏈接後,會以json形式顯示這些信息

4. eureka的自我保護機制

如果服務在更換 名稱或者長時間沒有訪問時,註冊中心頁面就會出現如此報錯,不用擔心,並不是真正的報錯了,而是eureka的自我保護機制生效了。並不會影響使用。

Eureka Server 在運行期間會去統計心跳失敗比例在 15 分鐘之內是否低於 85%,如果低於 85%,Eureka Server 會將這些實例保護起來,
        讓這些實例不會過期,但是在保護期內如果服務剛好這個服務提供者非正常下線了,此時服務消費者就會拿到一個無效的服務實例,此時會調用失敗,
        對於這個問題需要服務消費者端要有一些容錯機制,如重試,斷路器等。

        我們在單機測試的時候很容易滿足心跳失敗比例在 15 分鐘之內低於 85%,這個時候就會觸發 Eureka 的保護機制,
        一旦開啓了保護機制,則服務註冊中心維護的服務實例就不是那麼準確了,此時我們可以使用eureka.server.enable-self-preservation=false(在註冊中心服務eureka-server的yml文件中)來關閉保護機制,這樣可以確保註冊中心中不可用的實例被及時的剔除(不推薦)。
        
        當eureka在檢測服務時,如果超過了心跳檢測下限,就會啓動自我保護機制,不會強制下線連接失敗或者超時的服務,設計原則就是:寧可保留錯誤的服務註冊信息,也不盲目註銷任何可能健康的服務實例。

 

5. 服務的發現Discovery(對外暴露微服務的信息,提供API接口)

主要使用工具類:DiscoveryClient(org.springframework.cloud.client.discovery.DiscoveryClient)

作用:作用在服務提供者中,表示該 服務可以被發現,調用者可以獲取該服務的任何詳細信息

用法:

5.1 在需要 被發現的服務中,創建服務發現接口,通過DiscoveryClient來將服務的信息進行接口返回:

@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
			public Object discovery() {
				// 獲取註冊中心中所有的服務名
				List<String> allList = discoveryClient.getServices();
				//獲取服務名稱是PRODUCER_7001的所有微服務集合
				List<ServiceInstance> list = discoveryClient.getInstances("PRODUCER_7001");
				for (ServiceInstance ser : list) {
					System.out.println(ser.getHost() + "        " + ser.getServiceId() + "        "  + ser.getPort() + "        "  + ser.getUri());
				}
				return this.discoveryClient;
			}

5.2 接口寫好之後,在需要被發現的服務啓動類中,添加註解:@EnableDiscoveryClient
5.3 訪問該服務的該地址,即可訪問該服務的詳細信息

介紹完springcloud的註冊中心創建以及服務提供者的創建之後,就需要進行服務調用了。

兩種服務調用的方式:ribbon與feign

 ①:ribbon是通過ribbon+restTemplate的方式完成服務的調用,可通過註冊中心直接使用【服務名】+【接口地址】進行訪問微服務,類似於面向服務編程,缺點是如果一個服務被多出調用,則我們還需要將這種方式進行進一步自定義封裝,
 ②:而feign則直接設置成了面向接口的方式進行微服務的訪問,解決了這一問題。

③:ribbon:ribbon+restTempalte

       feign:接口+註解

四:ribbon負載均衡

源碼地址:https://github.com/Netflix/ribbon

1. 負載均衡LB(Load Balance)簡介:


        ribbon是基於Netflix Ribbon 實現的一套【客戶端】的【負載均衡工具】
        1.1 通過一定的負載均衡算法(簡單輪詢等),來完成服務的調用;
        1.2 負載均衡的方式:
            集中式LB:硬件的方式,在客戶端和服務端之間,通過硬件按照一定的策略完成轉發,從而達到負載均衡: 客戶端  ->  硬件(F5等)  ->  服務端
            進程內LB:將負載均衡邏輯算法集成在消費方,有消費方自主決定調用什麼服務。ribbon就是屬於進程內LB。


2. ribbon初步配置:


        2.1 修改pom文件添加依賴:
                <!--表示該服務是eureka client的客戶端-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-eureka</artifactId>
                </dependency>
                <!--此以來是標準依賴-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-config</artifactId>
                </dependency>
                <!--ribbon的依賴包-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-ribbon</artifactId>
                </dependency>
            
        2.2 修改yml文件,在消費端連接eureka註冊中心集羣,不再簡單的通過restTemplate直接轉發訪問服務提供者了,而是通過eureka通過負載均衡完成訪問。
            eureka:
              client:
                register-with-eureka: false   #不向註冊中心註冊自己
                fetch-registry: true          #但是需要從註冊中心讀取查詢服務
                service-url:
                  defaultZone: http://eureka.8001.com:8001/eureka/, http://eureka.8001.com:8001/eureka/, http://eureka.8001.com:8001/eureka/
        
        2.3 restTemplate創建Bean時添加註解@LoadBalanced,表示通過負載均衡的方式進行調用
        2.4 啓動類通過@EnableEurekaClient表明,該服務是一個客戶端(消費者)
        2.5 調用方式:由原來的通過直接明確的IP地址通過restTemplate的方式進行調用,修改爲通過微服務的服務名進行調用的方式,從而達到消費端通過註冊中心調用提供端

   // public static final String URL_PRX = "http://localhost:7001";
      public static final String URL_PRX = "http://producer-7001";  //通過服務名,來完成服務的調用


        2.6 啓動eureka集羣,啓動服務提供者,啓動客戶端,進行調用測試

3. ribbon的負載均衡調用


        3.1 當提供者部署了集羣之後,ribbon如果沒有特別設置,會按照輪詢的方式進行負載均衡依次調用。
        3.2 提供者部署多個服務到註冊中心之後,消費端會調用ribbon的負載均衡算法,進行輪詢訪問服務。算法調用機制如下:
        

4. ribbon負載均衡的服務調用機制(自帶七種方式)


        ribbon在沒有設置的情況下,默認調用輪詢方式進行調用服務,可以通過註冊bean的方式進行配置ribbon調用服務所使用的機制,設置如下:
        在服務消費端中:調用ribbon時聲明機制即可
          

  @Bean
            @LoadBalanced
            public RestTemplate getRestTemplate() {
                return new RestTemplate();
            }

            /**
             *ribbon負載均衡調用方式配置
             * 默認是RoundRobinRule
             * 需要什麼方式就返回什麼對象即可
             * ribbon提供了七中調用方式(當前版本)
             */
            @Bean
            public IRule getIRule() {
                return new RandomRule();  //設置ribbon的負載均衡機制爲隨機調用服務

            }

5. ribbon的自定義負載均衡機制設置


        5.1 在消費者端啓動類中調用註解:@RibbonClient(name = "PRODUCER-DEPT", configuration = MyRule.class)
            表示對於服務名稱爲PRODUCER-DEPT的微服務,負載均衡調用方式遵循MyRule類中規定的方式
            注意:該註解使用在啓動類中,並且該註解所定義的自動以機制類,不能放在ComponentScan所掃描的當前包以及子包下,否則我們自定義的配置類就會被所有的ribbon共享,就不能達到對某一個服務進行特殊配置的目的了。
                   
        5.2 myRule.java(簡易版)
            

@Configuration
public class MyRule {
    @Bean
    public IRule getIRule() {
      return new RoundRobinRule();  //設置ribbon的負載均衡機制爲輪詢調用服務
     }
}


            
            此處配置的IRule返回對象,不會與restTemplate公共ribbon設置的IRule所返回的類型對象所衝入,因爲公共配置的(也就是能被@ComponentScan所掃描的)bean,是應用於全局的ribbon適用於所有的微服務,本處配置的bean,僅僅只針對RibbonClient註解所指定的服務,進行負載均衡配置
        
        5.3 自定義ribbon負載均衡機制
        
            我們可以自己寫ribbon的負載均衡算法,只需要按照RandomRule類中的方式實現AbstractLoadBalancerRule這個抽象類中的方法,完成自己的算法邏輯,然後再啓動類中指定服務的規則類,實例化時,返回自己定義的實體即可。
            步驟如下:
            5.3.1  創建MyStyleRule.java  根據git源碼中的 RandomRule類進行修改的,邏輯爲隨即調用,每次調用五遍
                     

  /**
                 * ribbon負載均衡自定義規則
                 * 規則:隨機調用,並且每次隨機服務被重複調用5次
                 * 規則可以自定義算法邏輯進行設置
                 * @Date 2019/9/6 13:44
                 **/
                public class MyStyleRule extends AbstractLoadBalancerRule {

                private int index = 0;
                private int times = 0;

                public Server choose(ILoadBalancer lb, Object key) {
                    if (lb == null) {
                        return null;
                    }
                    Server server = null;

                    while (server == null) {
                        if (Thread.interrupted()) {
                            return null;
                        }
                        List<Server> upList = lb.getReachableServers();
                        List<Server> allList = lb.getAllServers();

                        int serverCount = allList.size();
                        if (serverCount == 0) {
                            return null;
                        }

                        /*int index = chooseRandomInt(serverCount);
                        server = upList.get(index);*/

                        if(times < 5) {
                            server = upList.get(index);
                            times++;
                        }else {
                            times = 0;
                            index = chooseRandomInt(serverCount);
                            server = upList.get(index);
                            times++;
                        }

                        if (server == null) {
                            Thread.yield();
                            continue;
                        }

                        if (server.isAlive()) {
                            return (server);
                        }

                        server = null;
                        Thread.yield();
                    }

                    return server;

                }

                protected int chooseRandomInt(int serverCount) {
                    return ThreadLocalRandom.current().nextInt(serverCount);
                }

                @Override
                public Server choose(Object key) {
                    return choose(getLoadBalancer(), key);
                }

                @Override
                public void initWithNiwsConfig(IClientConfig iClientConfig) {

                }
            }

       
              
        5.3.2 在實例化IRule接口時,返回自己創建的規則類
            

@Bean
public IRule getIRule() {
     /**
     * 設置ribbon的負載均衡機制爲輪詢調用服務
     */
     return new MyStyleRule();
}


        此時,即可完成我們的自定義配置類
        

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章