1. 程式人生 > 實用技巧 >【轉】 SpringCloud

【轉】 SpringCloud

【轉】 SpringCloud

SpringCloud

轉載於狂神老師 ,本文僅作為筆記使用

1、常見面試題
2、微服務概述
3、SpringCloud入門概述
4、Rest學習環境搭建
5、Eureka服務註冊與發現
6、Ribbon負載均衡
7、Feign負載均衡
8、Hystrix服務熔斷
9、Zuul路由閘道器
10、config分散式配置
小結

回顧之前的知識~
●JavaSE
●資料庫
●前端
●Servlet
●Http
●Mybatis
●Spring
●SpringMVC
●SpringBoot
●Dubbo. Zookeeper. 分散式基礎
●Maven. Git
●Ajax. json
●...

這個階段該如何學~
三層架構+ MVC

框架:

spring IOC AOP

SprintBoot,新一代的JavaEE開發標準, 自動裝配

模組化~all in one

模組化的開發===all in one, 程式碼沒變化~

微服務架構4個核心問題?
1.服務很多,客戶端該怎麼訪問?
2.這麼多服務? 服務之間如何通訊?
3.這麼多服務? 如何治理?
4.服務掛了怎麼辦?

解決方案:
Spring Cloud 生態! SpringBoot

  1. Spring cloud NetFlix 一站式解決方案!
    api閘道器,zuu1元件
    Feign --- HttpClinet ---- Http通訊方式,同步,阻塞
    服務註冊發現: Eureka
    熔斷機制: Hystrix

。。。。

  1. Apache Dubbo Zookeeper 半自動,需要整合別人的!
    API:沒有,找第三方元件,或者自己實現
    Dubbo
    Zookeeper
    沒有:藉助Hystrix
    Dubbo這個方案並不完善~

  2. Spring cloud Alibaba - -站式解決方案!更簡單

新概念:服務網格~ Server Mesh

istio

萬變不離其宗
1.API---------->路由問題

2.HTTP ,RPC----------》通訊問題

3.註冊和發現----------》高可用問題

4.熔斷機制------------》服務降級問題,防止服務雪崩

1、匯入依賴
2、編寫配置檔案
3、開啟這個功能@Enab1eXXXXX
4、配置類

網路不可靠!

1、常見面試題

1.1、 什麼是微服務?

1.2、微服務之間是如何獨立通訊的?

1.3、SpringCloud 和Dubbo有哪些區別?

1.4、SpringBoot和SpringCloud, 請你談談對他們的理解

1.5、什麼是服務熔斷?什麼是服務降級

1.6、微服務的優缺點是分別是什麼?說下你在專案開發中遇到的坑

1.7、你所知道的微服務技術棧有哪些?請列舉一二

1.8、eureka和zookeeper都可以提供服務註冊與發現的功能,請說說兩個的區別?

2、微服務概述

2.1、什麼是微服務

什麼是微服務?

微服務(Microservice Architecture)是近幾年流行的一種架構思想,關於它的概念很難一言以蔽之。

究竟什麼是微服務呢?

我們在此引用ThoughtWorks公司的首席科學家Martin Fowler於2014年提出的一段話:

原文: https://martinfowler.com/articles/microservices.html
漢化: https://www.cnblogs.com/liuning8023/p/4493156.html

  • 就目前而言,對於微服務,業界並沒有一個統一的,標準的定義

  • 但通常而言,微服務架構是- 種架構模式,或者說是一 種架構風格,它提倡將單一的應用程式劃分成一組
    小的服務
    ,每個服務執行在其獨立的自己的程序內,服務之間互相協調,互相配置,為使用者提供最終價值。服務之間採用輕量級的通訊機制互相溝通,每個服務都圍繞著具體的業務進行構建,並且能夠被獨立的部署到
    生產環境中,另外,應儘量避免統一的, 集中式的服務管理機制,對具體的一個服務而言,應根據業務上下
    文,選擇合適的語言,工具對其進行構建,可以有一個非常輕量級的集中式管理來協調這些服務,可以使用不
    同的語言來編寫服務,也可以使用不同的資料儲存;

可能有的人覺得官方的話太過生澀,我們從技術維度來理解下:

  • 微服務化的核心就是將傳統的一站式應用,根據業務拆分成一個一個的服務,徹底地去耦合,每一個微服務提
    供單個業務功能的服務,一個服務做一件事情, 從技術角度看就是一種小而獨立的處理過程,類似程序的概
    念,能夠自行單獨啟動或銷燬,擁有自己獨立的資料庫。

2.2、微服務與微服務架構

微服務

強調的是服務的大小,他關注的是某一個點, 是具體解決某一個問題/提供落地對應服務的一 個服務應用,狹義的
看,可以看做是IDEA中的一個個微服務工程,或者Moudel

  1. IDEA 工具裡面使用Maven開發的一個個獨立的小Moudle,它具體是使用springboot開發的一個小模組,專業的事情交給專業的模組來做,一個模組就做著一件事情

  2. 強調的是一個個的個體,每個個體完成一個具體的任務或者功能!

微服務架構

一種新的架構形式, Martin Fowler, 2014提出微服務架構是一種架構模式,它提倡將單- -應用程式劃分成一組小的服務,服務之間互相協調,互相配合,為使用者提供最終價值。每個服務執行在其獨立的程序中,服務於服務間採用輕量級的通訊機制互相協作,每個服務都圍繞著具體的業務進行構建,並且能夠被獨立的部署到生產環境中,另外,應儘量避免統一的, 集中式的服務管理機制,對具體的一個服務而言,應根據業務上下文,選擇合適的語言,工具對其進行構建。

2.3、微服務優缺點

優點

  • 每個服務足夠內聚,足夠小,程式碼容易理解,這樣能聚焦一個指定的業務功能或業務需求;
  • 開發簡單,開發效率提高,-個服務可能就是專- -的只幹一 -件事;
  • 微服務能夠被小團隊單獨開發,這個小團隊是2~5人的開發人員組成;
  • 微服務是鬆耦合的,是有功能意義的服務,無論是在開發階段或部署階段都是獨立的。
  • 微服務能使用不同的語言開發。
  • 易於和第三方整合,微服務允許容易且靈活的方式整合自動部署,通過持續整合工具,如 jenkins, Hudson,bamboo
  • 微服務易於被一個開發人員理解,修改和維護,這樣小團隊能夠更關注自己的工作成果。無需通過合作才能體現價值。
  • 微服務允許你利用融合最新技術。
  • 微服務只是業務邏輯的程式碼,不會和HTML,CSS 或其他介面混合
  • 每個微服務都有自己的儲存能力,可以有自己的資料庫,也可以有統- -資料庫

缺點:

  • 開發人員要處理分散式系統的複雜性

  • 多服務運維難度,隨著服務的增加,運維的壓力也在增大

  • 系統部署依賴

  • 服務間通訊成本

  • 資料一致性

  • 系統整合測試

  • 效能監控...

2.4、微服務技術棧有哪些?

2.5、為什麼選擇SpringCloud作為微服務架構

1、選型依據

  • 整體解決方案和框架成熟度
  • 社群熱度
  • 可維護性
  • 學習曲線

2、當前各大IT公司用的微服務架構有哪些?

  • 阿里: dubbo+HFS
  • 京東: JSF
  • 新浪: Motan
  • 噹噹網DubboX

3、各微服務框架對比

3、SpringCloud入門概述

3.1、SpringCloud是什麼

Spring官網:https://spring.io/

SpringCloud,基於SpringBoot提供了一套微服務解決方案,包括服務註冊與發現,配置中心,全鏈路監控,服務
閘道器,負載均衡,熔斷器等元件,除了基於NetFlix的開源元件做高度抽象封裝之外,還有一些選型中立的開源元件。

SpringCloud利用SpringBoot的開發便利性,巧妙地簡化了分散式系統基礎設施的開發, SpringCloud為開發人員
提供了快速構建分散式系統的一些工具,包括配置管理,服務發現,斷路器,路由,微代理,事件匯流排,全域性鎖,
決策競選,分散式會話等等,他們都可以用SpringBoot的開發風格做到一鍵啟動和部署。

SpringBoot並沒有重複造輪子,它只是將目前各家公司開發的比較成熟,經得起實際考研的服務框架組合起來,
通過SpringBoot風格進行再封裝,遮蔽掉了複雜的配置和實現原理,最終給開發者留出了一套簡單易懂,易部署
和易維護的分散式系統開發工具包

SpringCloud是分散式微服務架構下的一站式解決方案:是各個微服務架構落地技術的集合體,俗稱微服務全家
桶。

3.2、SpringCloud和SpringBoot關係

  • SpringBoot專注於快速方便的開發單個個體微服務。- Jar
  • SpringCloud是關注全域性的微服務協調整理治理框架,它將SpringBoot開發的一 個個單體微服務整合並管理起來,為各個微服務之間提供:配置管理,服務發現,斷路器,路由,微代理,事件匯流排,全域性鎖,決策競選,分散式會話等等整合服務。
  • SpringBoot可以離開SpringClooud獨立使用,開發專案,但是SpringCloud離不開SpringBoot, 屬於依賴關
  • SpringBoot專注於快速、 方便的開發單個個體微服務, SpringCloud關注全域性的服務治理框架

3.3、Dubbo 和SpringCloud技術選型

1、分散式+服務治理Dubbo

目前成熟的網際網路架構:應用服務化拆分+訊息中介軟體

一個完善的專案

2、Dubbo 和SpringCloud對比

可以看一下社群活躍度
https://github.com/dubbo
https://github.com/spring-cloud

結果:

最大區別: SpringCloud拋棄 了Dubbo的RPC通訊,採用的是基於HTTP的REST方式。

嚴格來說,這兩種方式各有優劣。雖然從一定程度 上來說,後者犧牲了服務呼叫的效能,但也避免了上面提到的原生RPC帶來的問題。而且REST相比RPC更為靈活,服務提供方和呼叫方的依賴只依靠一紙契約, 不存在程式碼級別的強依賴,這在強調快速演化的微服務環境下,顯得更加合適。

品牌機與組裝機的區別
很明顯,Spring Cloud的功能比DUBBO更加強大,涵蓋面更廣,而且作為Spring的拳頭專案,它也能夠與Spring
Framework. Spring Boot. Spring Data. Spring Batch等其他Spring專案完美融合,這些對於微服務而言是至
關重要的。使用Dubbo構建的微服務架構就像組裝電腦,各環節我們的選擇自由度很高,但是最終結果很有可能
因為一條記憶體質量不行就點不亮了,總是讓人不怎麼放心,但是如果你是一名高手, 那這些都不是問題;而Spring
Cloud就像品牌機,在Spring Source的整合下,做了大量的相容性測試,保證了機器擁有更高的穩定性,但是如
果要在使用非原裝元件外的東西,就需要對其基礎有足夠的瞭解。

社群支援與更新力度
最為重要的是,DUBBO停止了5年左右的更新,雖然2017.7重啟了。 對於技術發展的新需求,需要由開發者自行
拓展升級(比如噹噹網弄出了DubboX),這對於很多想要採用微服務架構的中小軟體組織, 顯然是不太合適的,
中小公司沒有這麼強大的技術能力去修改Dubbo原始碼+周邊的一整套解決方案,並不是每-個公司都有阿里的大牛
+真實的線上生產環境測試過。

設計模式+微服務拆分思想:不-定善於表達,軟實力,活躍度

總結:
曾風靡國內的開源RPC服務框架Dubbo在重啟維護後,令許多使用者為之雀躍,但同時,也迎來了一些質疑的聲
音。網際網路技術發展迅速,Dubbo 是否還能跟上時代? Dubbo 與Spring Cloud相比又有何優勢和差異?是否會
有相關舉措保證Dubbo的後續更新頻率?

人物: Dubbo重啟維護開發的劉軍,主要負責人之一
劉軍,阿里巴巴中介軟體高階研發工程師,主導了Dubbo重啟維護以後的幾個發版計劃,專注於高效能RPC框架
和微服務相關領域。曾負責網易考拉RPC框架的研發及指導在內部使用,參與了服務治理平臺、分散式跟蹤系
統、分散式-致性框架等從無到有的設計與開發過程。

解決的問題域不一樣: Dubbo的定位是-款RPC框架, Spring Cloud的目標是微服務架構下的一站式解決方案

3.4、SpringCloud能幹嘛

  • Distributed/vjersioned configuration (分散式/版本控制配置)
  • Service registration and discovery (服務註冊與發現)
  • Routing (路由)
  • Service-to-service calls (服務到服務的呼叫)
  • Load balancing (負載均衡配置)
  • Circuit Breakers (斷路器)
  • Distributed messaging (分散式訊息管理)

3.5、SpringCloud在哪下

官網:https://spring.io/projects/spring-cloud
這玩意的版本號有點特別

Spring cloud是一 一個由眾多獨立子專案組成的大型綜合專案,每個子專案有不同的發行節奏,都維護著自己的釋出版
本號。Spring cloud通過一個資源清單BOM (Bi11 of Materials)來管理每個版本的子專案清單。為避免與子項
目的釋出號混淆,所以沒有采用版本號的方式,而是通過命名的方式。

這些版本名稱的命名方式採用了倫敦地鐵站的名稱,同時根據字母表的順序來對應版本時間順序,比如:最早的
Release版本: Angel, 第二個Release版本: Brixton, 然後是Camden、Dalston、 Edgware, 目前最新的是
Finchley版本。

4、Rest學習環境搭建

4.1、總體介紹

  • 我們會使用- -個Dept部門模組做-個微服務通 用案例Consumer消費者(Client) 通過REST呼叫Provider提供
    者(Server)提供的服務。
  • 回憶Spring, SpringMVC, MyBatis等以往學習的知識。。.
  • Maven的分包分模組架構複習
一個簡單的Maven模組結構是這樣的:
-- app-parent: - - 個父專案(app-parent) 聚合很多子專案(app-util, app-dao, app-web...)
|-- pom. xml
|-- app-core
| l----pom. xml
| -- app -web
| |----pom. xml

一個父工程帶著多個子Module子模組
MicroServiceCloud父工程(Project) 下初次帶著3個子模組(Module)

  • microservicecloud-api [封裝的整體entity/介面/公共配置等]|

  • microservicecloud-provider-dept-8001 [服務提供者]

  • microservicecloud-consumer-dept-80 [服務消費者]

  • 動手開幹!

4.2、SpringCloud版本選擇

各大版本說明

實際開發版本關係

使用最後的這兩個

4.3、建立父工程

●新建父工程專案microservicecloud, 切記Packageing是pom模式
●主要是定義POM檔案,將後續各個子模組公用的jar包等統- 提取出來,類似-個抽象父類

父pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kuang</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>springcloud-api</module>
        <module>springcloud-priovider-dept-8001</module>
    </modules>

    <!--打包方式  pom-->
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--maven編輯器-->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <lombok.version>1.16.10</lombok.version>
        <log4j.version>1.2.7</log4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--springcloud的依賴-->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--連線資料庫-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!--druid資料來源-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <!-- 引入 myBatis,這是 MyBatis官方提供的適配 Spring Boot 的,而不是Spring Boot自己的-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--單元測試-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--日誌測試-->
            <!--日誌門面-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <!--小辣椒-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

模組一:專門放實體類的模組springcloud-api

1、pom.xml

<!---當前的Module自己需要的依賴, 如果父依賴中已經配置了版本。這裡就不用寫了-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2、建立資料庫,表

3、實體類

package com.kuang.pojo;


import lombok.experimental.Accessors;

import java.io.Serializable;
@Accessors(chain = true)//鏈式寫法
public class Dept implements Serializable {//Dept 實體類 orm 類表關係對映
    private Long deptno;//主鍵
    private String dname;
    //這個資料數存在哪個資料庫的欄位~微服務,一個服務對應一個數據庫,同一個資訊可能存在不同的資料庫
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }

    /*
    鏈式寫法
    Dept dept = new Dept();
    dept. setDeptNo(11). setDname(' 'SSSS ') . setDb_ source( '001' ) ;

     */

    public Dept() {
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getDb_source() {
        return db_source;
    }

    public void setDb_source(String db_source) {
        this.db_source = db_source;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", db_source='" + db_source + '\'' +
                '}';
    }
}

模組二:服務提供者springcloud-priovider-dept-8001

1、pom.xml

 <dependencies>
        <!--我們需要拿到實體類,所以要配置api module-->
        <dependency>
            <groupId>com.kuang</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--熱部署工具:-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

熱部署工具:程式碼修改後,無需重啟伺服器,重新整理一下即可

2、application.yml

server:
 port: 8001
#mybatis配置
mybatis:
 type-aliases-package: com.kuang.pojo
 config-location: classpath:mybatis/mybatis-config.xml
 mapper-locations: classpath:mybatis/mapper/*.xml
#spring的配置&autoReconnect=true
spring:
 application:
  name: springcloud-provider-dept
 datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  driver-class-name: org.gjt.mm.mysql.Driver
  url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
  username: root
  password: 981204

3、mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--開啟二級快取-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

4、DeptDao

@Mapper
@Repository
public interface DeptDao {
    boolean addDept(Dept dept);

    Dept queryById(Long id);

    List<Dept> queryAll();

}

5、DeptDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.DeptDao">
    <insert id="addDept" parameterType="Dept">
        insert into dept (dname, db_source)
        values (#{dname}, DATABASE())
    </insert>

    <select id="queryById" resultType="Dept" parameterType="Long">
        select * from dept where deptno = #{deptno};
    </select>

    <select id="queryAll" resultType="Dept" parameterType="Long">
        select * from dept;
    </select>

</mapper>

6、DeptService

public interface DeptService {
    boolean addDept(Dept dept);

    Dept queryById(Long id);

    List<Dept> queryAll();

}

7、DeptServiceImpl

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptDao deptDao;

    @Override
    public boolean addDept(Dept dept) {
        return deptDao.addDept(dept);
    }

    @Override
    public Dept queryById(Long id) {
        return deptDao.queryById(id);
    }

    @Override
    public List<Dept> queryAll() {
        return deptDao.queryAll();
    }
}

8、DeptController

//提供Restfui服務
@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept) {
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id) {
        return deptService.queryById(id);
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll() {
        return deptService.queryAll();
    }
}

9、啟動類:DeptPriovider_8001

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

10、啟動測試

專案結構

模組三:服務消費者springcloud-cosumer-dept-80

pom.xml

  <dependencies>
        <!--實體類+web-->
        <dependency>
            <groupId>com.kuang</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

2、application.yml

server:
 port: 80

3、配置ConfigBean

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate() {//@Configuration-- 以前在spring applicationContext.xml中配置
        return new RestTemplate();
    }
}

4、DeptConsumerController

@RestController
public class DeptConsumerController {
    // 理解: 消費者,不應該有service層
    // RestTemplate .... 供我們直接呼叫就可以了!註冊到pring中
    // (url,實體: Map , Class<T> responseType)|
    @Autowired
    private RestTemplate restTemplate; // 提供多種便捷訪問遠http服務的方法,簡單的Restful服務模板~
    private static final String REST_URL_PREFIX = "http://localhost:8001";

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept) {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")

    public Dept get(@PathVariable("id") Long id) {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> list() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
    }

}

5、啟動類

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

}

6、測試,先啟動提供者,再啟動消費者

注:80為可以省略的預設埠

專案結構:

5、Eureka服務註冊與發現

5.1、什麼是Eureka

  • Eureka: 怎麼讀? .
  • Netflix 在設計Eureka時,遵循的就是AP原則
  • Eureka是Netflix的一 個子模組,也是核心模組之一 。Eureka是一 個基於REST的服務,用於定位服務,以實現
    雲端中間層服務發現和故障轉移,服務註冊與發現對於微服務來說是非常重要的,有了服務發現與註冊,只需
    要使用服務的識別符號,就可以訪問到服務,而不需要修改服務呼叫的配置檔案了,功能類似於Dubbo的註冊
    中心,比如Zookeeper;

5.2、原理講解

  • Eureka的基本架構

    • SpringCloud封裝了NetFlix公司開發的Eureka模組來實現服務註冊和發現(對比Zookeeper)

    • Eureka採用 了C-S的架構設計,EurekaServer 作為服務註冊功能的伺服器,他是服務註冊中心

    • 而系統中的其他微服務。使用Eureka的客戶端連線到EurekaServer並維持心跳連線。這樣系統的維護人
      員就可以通過EurekaServer來監控系統中各個微服務是否正常執行,SpringCloud的一 些其他模組(比如
      Zuul)就可以通過EurekaServer來發現系統中的其他微服務,並執行相關的邏輯;

    • 和Dubbo架構對比

    • Eureka 包含兩個元件: Eureka Server和Eureka Client。

    • Eureka Server提供服務註冊服務,各個節點啟動後,會在EurekaServer中進行註冊,這樣Eureka Server
      中的服務登錄檔中將會村粗所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀的看到。

    • Eureka Client是一 個Java客戶端,用於簡化EurekaServer的互動,客戶端同時也具備一 個內建的,使用輪詢負載演算法的負載均衡器。在應用啟動後,將會向EurekaServer傳送心跳(預設週期為30秒)。如果
      Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務登錄檔中把這個
      服務節點移除掉(預設週期為90秒)

  • 三大角色

  • Eureka Server: 提供服務的註冊於發現。

  • Service Provider:將自身服務註冊到Eureka中,從而使消費方能夠找到。

  • Service Consumer:服務消費方從Eureka中獲取註冊服務列表,從而找到消費服務。

  • 盤點目前工程狀況

1、EurekaServer環境搭建

5.3模組四:Eureka服務springcloud-eureka-7001

1、pom.xml

  <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

2、application.yml

server:
  port: 7001
#Eureka配置
eureka:
  instance:
    hostname: localhost #Eureka 服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registry如果為false,則表示自己為註冊中心
    service-url: # 監控頁面~
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、啟動類EurekaServer_7001

//啟動之後,訪問http://Localhost: 7001/
@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer服務端的啟動類,可以接受別人註冊進*
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class, args);
    }
}

4、訪問測試,先啟動7001,再啟動8001

2、將服務提供者註冊進去

將8001的服務入駐到7001的eureka中!

1、pom.xml 修改8001服務的pom檔案,增加eureka的支援!

 <!--eureka-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

2、application.yml 增加配置

#Eureka的配置,服務註冊到哪裡
eureka:
 client:
  service-url:
   defaultZone: http://localhost:7001/eureka/
 instance:
  instance-id: springcloud-provider-dept8001 #修改eureka 上的預設描述資訊!

3、8001的主啟動類註解支援

啟動類中添加註解

@EnableEurekaClient //在服務啟動後自動註冊到eureka中

4、測試

現在服務端也有了,客戶端也有了
啟動7001,再啟動8001,測試訪問

3、資訊配置

1、pom.xml

 <!--actuator完善監控資訊-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2、application.yml 增加配置

#info配置
info:
 app.name: kuangshen-springcloud
 company.name: blog.kuangstudy.com

3、重啟測試

點選

可觀察到

4、自我保護機制

我們修改一個服務名,故意製造錯誤!

自我保護機制:好死不如賴活著

一句話總結:某時刻某一個微服務不可以用了,eureka不會立刻清理,依舊會對該微服務的資訊進行儲存!

  • 預設情況下,如果EurekaServer在一 定時間內沒有接收到某個微服務例項的心跳,EurekaServer將會登出該
    例項(預設90秒)。但是當網路分割槽故障發生時,微服務與Eureka之間無法正常通行,以上行為可能變得非
    常危險了--因為微服務本身其實是健康的,此時本不應該登出這個服務。Eureka通過 自我保護機制來解決這
    個問題--當EurekaServer節點在短時間內丟失過多客戶端時(可能發生了網路分割槽故障),那麼這個節點就會
    進入自我保護模式。- -旦進入該模式,EurekaServer就會保護服務登錄檔中的資訊, 不再刪除服務登錄檔中
    的資料(也就是不會登出任何微服務)。當網路故障恢復後,該EurekaServer節點會自動退出自我保護模
    式。
  • 在自我保護模式中,EurekaServer會保護服務登錄檔中的資訊,不再登出任何服務例項。當它收到的心跳數
    重新恢復到閾值以上時,該EurekaServer節 點就會自動退出自我保護模式。它的設計哲學就是寧可保留錯誤
    的服務註冊資訊,也不盲目登出任何可能健康的服務例項。-句話:好死不如賴活著
  • 綜上,自我保護模式是一種應對網路異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的
    微服務和不健康的微服務都會保留),也不盲目登出任何健康的微服務。使用自我保護模式,可以讓Eureka
    叢集更加的健壯和穩定
  • 在SpringCloud中,可以使用eureka. server . enable-self-preservation = false 禁用自我保護模式
    [不推薦關閉自我保護機制]

5、8001服務發現Discovery(擴充套件)

  • 對於註冊進eureka裡面的微服務,可以通過服務發現來獲得該服務的資訊。[對外暴露服務 ]
  • 修改microservicecloud-provider-dept-8001I程中的DeptController

可以瞭解多應的服務資訊,實現一些訊息轉換、服務發現

1、Controller中

//獲取一些配置的資訊,得到具體的微服務!
    @Autowired
    private DiscoveryClient client;


//註冊進來的微服務~,獲取-些訊息~
    @GetMapping("/dept/discovery")
    public Object discovery() {
        //獲取微服務列表的清業
        List<String> services = client.getServices();
        System.out.println("discovery=>services:" + services);
        //得到一- 個具體的微服務資訊通過具體的微服務id, appl icaioinName;
        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost() + "\t" +
                            instance.getPort() + "\t" +
                            instance.getUri() + "\t" +
                            instance.getServiceId()
            );
        }
        return this.client;
    }

2、啟動類開啟註解支援

@EnableDiscoveryClient//服務發現

@SpringBootApplication
@EnableEurekaClient //在服務啟動後自動註冊到eureka中
@EnableDiscoveryClient//服務發現
public class DeptPriovider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptPriovider_8001.class, args);
    }

}

3、訪問測試

控制器輸出

6、叢集環境配置

每臺遠端服務均可以互相訪問

這麼多服務? 如何治理?

1.建立三個專案,改上面的就行

springcloud-eureka-7001

springcloud-eureka-7002

springcloud-eureka-7003

2、新增域名

新增

叢集配置分析

3、該yml配置

三個eureka

server:
  port: 7001
#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com #Eureka 服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registry如果為false,則表示自己為註冊中心
    service-url: # 監控頁面~
      #單機 http://${eureka.instance.hostname}:${server.port}/eureka/
      #(叢集)關聯 http://eureka7002.com:7002,http://eureka7003.com:7003
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
server:
  port: 7002
#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #Eureka 服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registry如果為false,則表示自己為註冊中心
    service-url: # 監控頁面~
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
server:
  port: 7003
#Eureka配置
eureka:
  instance:
    hostname: eureka7003.com #Eureka 服務端的例項名稱
  client:
    register-with-eureka: false #表示是否向eureka註冊中心註冊自己
    fetch-registry: false #fetch-registry如果為false,則表示自己為註冊中心
    service-url: # 監控頁面~
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/

提供者中

   defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

測試,先啟動7001/7002/7003/8001三個地址可以相互訪問

三個地址服務均註冊進去

消費者只需在配置中改連結即可

5.4、對比Zookeeper

回顧CAP原則

RDBMS (Mysql. Oracle、 sqIServer) ===>ACID

NoSQL (redis. mongdb) ===> CAP

ACID是什麼?

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 隔離性
  • D (Durability) 永續性

CAP是什麼?

  • C (Consistency)強一致性
  • A (Availability) 可用性
  • P (Partition tolerance) 分割槽容錯性

CAP的三進二: CA、AP. CP .

CAP理論的核心

  • 一個分散式系統不可能同時很好的滿足-致性,可用性和分割槽容錯性這三個需求
  • 根據CAP原理,將NoSQL資料庫分成了滿足CA原則,滿足CP原則和滿足AP原則三大類:
    • CA:單點叢集,滿足一致性,可用性的系統,通常可擴充套件性較差
    • CP:滿足-致性,分割槽容錯性的系統,通常效能不是特別高
    • AP:滿足可用性,分割槽容錯性的系統,通常可能對一致性要求低- -些
作為服務註冊中心,Eureka比Zookeeper好在哪裡?

著名的CAP理論指出,一個分散式系統不可能同時滿足C (一致性)、A (可用性)、P (容錯性)。
由於分割槽容錯性P在分散式系統中是必須要保證的,因此我們只能在A和C之間進行權衡。

  • Zookeeper保證的是CP;
  • Eureka保證的是AP:

Zookeeper保證的是CP

當向註冊中心查詢服務列表時,我們可以容忍註冊中心返回的是幾分鐘以前的註冊資訊,但不能接受服務直接
down掉不可用。也就是說,服務註冊功能對可用性的要求要高於-致性。 但是zk會出現這樣一種情況, 當master
節點因為網路故障與其他節點失去聯絡時,剩餘節點會重新進行leader選舉。問題在於,選舉leader的時間太長,
30~120s,且選舉期間整個zk叢集都是不可用的,這就導致在選舉期間註冊服務癱瘓。在雲部署的環境下,因為網
絡問題使得zk叢集失去master節點是較大概率會發生的事件,雖然服務最終能夠恢復,但是漫長的選舉時間導致
的註冊長期不可用是不能容忍的。

Eureka保證的是AP

Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節 點都是平等的,幾個節點掛掉不會影
響正常節點的工作,剩餘的節點依然可以提供註冊和查詢服務。而Eureka的客戶端在向某個Eureka註冊時,如果
發現連線失敗,則會自動切換至其他節點,只要有一臺Eureka還在, 就能保住註冊服務的可用性,只不過查到的
資訊可能不是最新的,除此之外,Eureka還有一 種自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的
心跳,那麼Eureka就認為客戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:

  1. Eureka不再從註冊列表中移除因為長時間沒收到心跳而應該過期的服務

  2. Eureka仍然能夠接受新服務的註冊和查詢請求,但是不會被同步到其他節點上(即保證當前節點依然可用)

  3. 當網路穩定時,當前例項新的註冊資訊會被同步到其他節點中

因此,Eureka可以很好的應對因網路故障導致部分節點失去聯絡的情況,而不會像zookeeper那樣使整 個註冊服務癱瘓

6、Ribbon負載均衡

例如一萬個人傳送請求,負載均衡把請求平攤給五臺伺服器

ribbon怎麼讀?
ribbon是什麼?
●Spring Cloud Ribbon是基於Netflix Ribbon實現的一 套客戶端負載均衡的工具。
●簡單的說,Ribbon是Netflix釋出的開源專案, 主要功能是提供客戶端的軟體負載均衡演算法,將NetFlix的中間
層服務連線在一起。 Ribbon的客戶端元件提供-系列完整的配置項如:連線超時、重試等等。簡單的說,就
是在配置檔案中列出LoadBalancer (簡稱LB:負載均衡)後面所有的機器,Ribbon會 自動的幫助你基於某種
規則(如簡單輪詢,隨機連線等等)去連線這些機器。我們也很容易使用Ribbon實現自定義的負載均衡算
法!
ribbon能幹嘛?
●LB,即負載均衡(Load Balance) ,在微服務或分散式叢集中經常用的一種應用。
負載均衡簡單的說就是將使用者的請求平攤的分配到多個服務上,從而達到系統的HA (高可用)。
●常見的負載均衡軟體有Nginx, Lvs等等
●dubbo. SpringCloud中均給我們提供了 負載均衡,SpringCloud的負載均衡演算法可以自定義
●負載均衡簡單分類:
。集中式LB
■即在服務的消費方和提供方之間使用獨立的LB設施,如Nginx, 由該設施負責把訪問請求通過某種策
略轉發至服務的提供方!
。程序式LB
■將LB邏輯整合到消費方,消費方從服務註冊中心獲知有哪些地址可用,然後自己再從這些地址中選出
一個合適的伺服器。
■Ribbon就屬於程序內LB,它只是一個類庫,集成於消費方程序,消費方通過它來獲取到服務提供方
的地址

6.1、使用Ribbon實現負載均衡

springcloud-cosumer-dept-80中

1、新增依賴pom.xml

<!--ribbon-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--eureka-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

2、新增yml

#Eureka配置
eureka:
 client:
  register-with-eureka: false #不向Eureka註冊自己
  service-url:
   defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

3、配置類中添加註解 @LoadBalanced //Ribbon

@Configuration
public class ConfigBean {

    //配置負載均衡實現Rest Template
    @Bean
    @LoadBalanced //Ribbon
    public RestTemplate getRestTemplate() {//@Configuration-- 以前在spring applicationContext.xml中配置
        return new RestTemplate();
    }
}

4、修改DeptConsumerController

//Ribbon. 我們這裡的地址,應該是一個變數。通過服務名來訪問
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

5、啟動類中新增@EnableEurekaClient

//Ribbon和Eureka整合以後,客戶端可以直接呼叫。相關心IP地址和埠號
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }

}

6、啟動7001/7002/8001/80測試

6.2、使Ribbon實現負載均衡

1、建立三個提供者

springcloud-priovider-dept-8001

springcloud-priovider-dept-8002

springcloud-priovider-dept-8003

2、複製springcloud-priovider-dept-8001,更改裡面的配置

yml

server:
 port: 8002

#mybatis配置
mybatis:
 type-aliases-package: com.kuang.pojo
 config-location: classpath:mybatis/mybatis-config.xml
 mapper-locations: classpath:mybatis/mapper/*.xml

#spring的配置&autoReconnect=true
spring:
 application:
  name: springcloud-provider-dept #三個服務名稱一致
 datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  driver-class-name: org.gjt.mm.mysql.Driver
  url: jdbc:mysql://localhost:3306/db02?useUnicode=true&characterEncoding=utf-8
  username: root
  password: 981204

#Eureka的配置,服務註冊到哪裡
eureka:
 client:
  service-url:
   #http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
   #http://eureka7001.com:7001,http://eureka7002.com:7002,http://eureka7003.com:7003
   defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
 instance:
  instance-id: springcloud-provider-dept8002 #修改eureka 上的預設描述資訊!

#info配置
info:
 app.name: kuangshen-springcloud
 company.name: blog.kuangstudy.com

2、更改主啟動類

package com.kuang;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;


@SpringBootApplication
@EnableEurekaClient //在服務啟動後自動註冊到eureka中
@EnableDiscoveryClient//服務發現
public class DeptPriovider_8002 {
    public static void main(String[] args) {
        SpringApplication.run(DeptPriovider_8002.class, args);
    }

}

3、啟動測試

啟動7001,發現有兩個提供者註冊進去

再啟動8001/8002/8003/80,結果是輪詢,判斷自己是要連哪個

6.3、優化Ribbon實現負載均衡

1、使用隨機演算法代替預設的輪詢演算法

// IRule
// RoundRobinRule輪詢
// RandomRule隨機
// AvailabilityFilteringRule :會先過濾掉, 跳閘,訪問故障的服務~,對利下的進行輪海~
// RetryRule :會先按照輪 詢獲取服務~,如果服務獲取失敗,則會在指定的時間內進行,重試
@Configuration
public class KuangRule {
    @Bean
    public IRule myRu1e() {
        return new RandomRule();
    }

}

6.4、自定義負載均衡演算法

1、複製RandomRule,自己更改將原來的預設輪詢訪問改為每個服務訪問5次,再換下一個服務(3個)

package com.kuang.myrule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class KuangRandomRule extends AbstractLoadBalancerRule {
    //每個服務,訪問次,換下一個服務(3個)
    // total=0, 預設=0,如果=5,我們指向下一個服務節點
    // index=0. 預設=0,如果total=5, index+1.
    private int total = 0; //被呼叫的次數
    private int currentIndex = 0; //當前是誰在提供服務d


    //@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            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 = this.chooseRandomInt(serverCount);//生成區間隨機數
                //server = (Server) upList.get(index);//從活著的服務中,隨機獲取一個

                //===============================================
                if (total < 5) {
                    server = upList.get(currentIndex);
                    total++;
                } else {
                    total = 0;
                    currentIndex++;
                    if (currentIndex > upList.size()) {
                        currentIndex = 0;
                    }
                    server = upList.get(currentIndex); //從活著的服務中,獲取指定的服務來進行操作
                }
                //=================================================


                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

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

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

2、配置中呼叫該自定義負載均衡演算法

@Configuration
public class KuangRule {
    @Bean
    public IRule myRu1e() {
        return new KuangRandomRule();
    }

}

3、啟動7001/8001/8002/8003/80訪問測試

發現每個服務訪問5次,再換下一個服務(3個)

7、Feign負載均衡

7.1、簡介

feign是宣告式的web service客戶端,它讓微服務之間的呼叫變得更簡單了,類似controller呼叫service。 Spring
Cloud集成了Ribbon和Eureka,可在使用Feign時提供負載均衡的http客戶端。

只需要建立一個介面,然後添加註解即可!

feign,主要是社群,大家都習慣面向介面程式設計。這個是很多開發人員的規範。呼叫微服務訪問兩種方法

  1. 微服務名字[ribbon]
  2. 介面和註解[feign ]

Feign能幹什麼?

  • Feign旨在使編寫Java Http客戶端變得更容易
  • 前面在使用Ribbon + RestTemplate時, 利用RestTemplate對Http請求的封裝處理, 形成了一 套模板化的呼叫
    方法。但是在實際開發中,由於對服務依賴的呼叫可能不止一-處, 往往-個介面會被多處呼叫,所以通常都會
    針對每個微服務自行封裝-一些客戶端類來包裝這些依賴服務的呼叫。 所以,Feign在此基礎 上做了進一步封
    裝,由他來幫助我們定義和實現依賴服務介面的定義,在Feign的實現下,我們只需要建立一個介面並使用**
    註解的方式來配置它(類似於以前Dao介面上標註Mapper註解,現在是一個微服務介面上面標註一個Feign注
    解即可。)** 即可完成對服務提供方的介面繫結,簡化了使用Spring Cloud Ribbon時,自動封裝服務呼叫客
    戶端的開發量。

Feign集成了Ribbon

  • 利用Ribbon維護了MicroServiceCloud-Dept的服務列表資訊,並且通過輪詢實現了客戶端的負載均衡,而與
    Ribbon不同的是,通過Feign只需要定義服務繫結介面且以宣告式的方法,優雅而且簡單的實現了服務呼叫。

7.2、Feign的使用步驟

1.建立springcloud-cosumer-dept-feign匯入springcloud-cosumer-dept-80的那些配置

2.在模組springcloud-api和springcloud-cosumer-dept-feign中新增依賴

  <!--feign-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

3.在模組springcloud-api中編寫DeptClientService

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {


    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}

4.springcloud-cosumer-dept-feign中編寫DeptConsumerController

@RestController
public class DeptConsumerController {
    //@Autowired(required=true):當使用@Autowired註解的時候,其實預設就是@Autowired(required=true),表示注入的時候,該bean必須存在,否則就會注入失敗。
    @Autowired(required = false)
    private DeptClientService service = null;

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept) {
        return this.service.addDept(dept);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id) {
        return this.service.queryById(id);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> list() {
        return this.service.queryAll();
    }

}

5.編寫主啟動類

//Ribbon和Eureka整合以後,客戶端可以直接呼叫。相關心IP地址和埠號
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.kuang"})
public class FeignDeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class, args);
    }

}

6.啟動7001/8001/8002、fegin80測試訪問,發現也是預設輪詢

8、Hystrix服務熔斷

分散式系統面臨的問題

複雜分散式體系結構中的應用程式有數十個依賴關係,每個依賴關係在某些時候將不可避免的失敗!

服務雪崩

​ 多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和微服務C,微服務B和微服務(C又呼叫其他的微服務,
這就是所謂的“扇出”、如果扇出的鏈路上某個微服務的呼叫響應時間過長或者不可用,對微服務A的呼叫就會佔用
越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。
​ 對於高流量的應用來說,單- -的後端依賴可能會導致所有伺服器上的所有資源都在幾秒中內飽和。比失敗更糟
糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生
更多的級聯故障,這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程
序或系統。
​ 我們需要:棄車保帥.

什麼是Hystrix
Hystrix是一個用於處理分散式系統的延遲和容錯的開源庫, 在分散式系統裡,許多依賴不可避免的會呼叫失
敗,比如超時,異常等, Hystrix能夠保證在一個依賴出問題的情況下, 不會導致整體服務失敗,避免級聯故障,
以提高分散式系統的彈性。

​ “斷路器”本身是一種開關裝置, 當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),
呼叫方返回- -個服務預期的,可處理的備選響應(FallBack) , 而不是長時間的等待或者丟擲呼叫方法無法處理
的異常,這樣就可以保證了服務呼叫方的執行緒不會被長時間,不必要的佔用,從而避免了故障在分散式系統中的蔓
延,乃至雪崩

能幹嘛
●服務降級.
●服務熔斷
●服務限流
●接近實時的監控

官網資料
https://github.com/Netflix/Hystrix/wiki

8.1、服務熔斷

是什麼
熔斷機制是對應雪崩效應的一種微服務鏈路保護機制。

​ 當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快
速返回錯誤的響應資訊。當檢測到該節點微服務呼叫響應正常後恢復呼叫鏈路。在SpringCloud框架裡熔斷機制通
過Hystrix實現。Hystrix會監控微服務間呼叫的狀況,當失敗的呼叫到一定閾值,預設是5秒內20次呼叫失敗就會
啟動熔斷機制。熔斷機制的註解是@HystrixCommand.

步驟

1.建立一個專案springcloud-priovider-dept-hystrix-8001複製springcloud-priovider-dept-8001的配置

2.新增pom依賴

   <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

3.DeptController

//提供Restfui服務
@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @GetMapping("/dept/get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public Dept get(@PathVariable("id") Long id) {
        Dept dept = deptService.queryById(id);
        if (dept == null) {
            throw new RuntimeException("id=>" + id + ".不存在該使用者。或者資訊無法找到~");
        }
        return dept;
    }

    //備選方法
    public Dept hystrixGet(@PathVariable("id") Long id) {

        Dept dept = new Dept();
        dept.setDeptno(id);
        dept.setDname("id=>" + id + "沒有對應的資訊。null--@Hystrix");
        dept.setDb_source("no this database in MySQL");
        return dept;
    }

}

4.新增@EnableCircuitBreaker//新增對熔斷的支援

@SpringBootApplication
@EnableEurekaClient //在服務啟動後自動註冊到eureka中
@EnableDiscoveryClient//服務發現
@EnableCircuitBreaker//新增對熔斷的支援
public class DeptPrioviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptPrioviderHystrix_8001.class, args);
    }

}

5.啟動7001/7002、hystrix8001/80測試訪問:

彩蛋:顯示ip地址

配置

 prefer-ip-address: true #true 可以顯示服務的ip地址

配置前

配置後

8.2、服務降級

伺服器訪問量大時關閉部分其它伺服器

1.springcloud-api中編寫DeptClientServiceFallbackFacktory

//降級
@Component
public class DeptClientServiceFallbackFacktory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                Dept dept = new Dept();
                dept.setDeptno(id);
                dept.setDname("id=>" + id + "沒有對應的資訊。客戶端提供了降級的資訊。這個服務現在已經被關閉");
                dept.setDb_source("沒有資料~");
                return dept;
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }

}

2.DeptClientService

@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT", fallbackFactory = DeptClientServiceFallbackFacktory.class)

3.springcloud-cosumer-dept-feign中新增配置

#開啟降級feign. hystrix
feign:
 hystrix:
  enabled: true

4.啟動7001/8001、feign80測試

http://localhost/consumer/dept/get/1查詢成功

5.關閉8001

查詢結果

服務熔斷:服務券菜 個服務超時或者異常,引起熔斷,保險絲~
服務降級:客戶端從整體網站請求負載考慮。當菜個服務熔斷或者關閉之後。服務將不再被呼叫
此時在客戶端,我們可以準備一- 個FallbackFactory. 返回- - 個預設的值(預設值),整體的服務水中下降不但是,好歹能用比直按掛掉強

8.3、Dashboard流監控

寫監控頁面

1.建立springcloud-cosumer-hystrix-dashboard

2.新增依賴

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

3.設定埠號

server:
 port: 9001

4.編寫啟動類啟動

@SpringBootApplication
@EnableHystrixDashboard //開啟
public class DeptConsumerDashboard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9001.class,args);
    }

}

5、訪問測試

開始監控了

專案springcloud-priovider-dept-8001中

1.主啟動類中

@SpringBootApplication
@EnableEurekaClient //在服務啟動後自動註冊到eureka中
@EnableDiscoveryClient//服務發現
public class DeptPriovider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptPriovider_8001.class, args);
    }

    //增加一個Servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }

}

2.啟動7001/9001/8001測試

每次傳送請求觀察監控變化

**關於監控

。如何看
■7色

■一圈
實心圓:公有兩種含義,他通過顏色的變化代表了例項的健康程度
它的健康程度從綠色<黃色<橙色<紅色遞減
該實心圓除了顏色的變化之外,它的大小也會根據例項的請求流量發生變化,流量越大,該實心圓就
越大,所以通過該實心圓的展示,就可以在大量的例項中快速發現故障例項和高壓力例項。


)

■一線
曲線:用來記錄2分鐘內流量的相對變化,可以通過它來觀察到流量的上升和下降趨勢!

■整圖說明

。搞懂一個才能看懂複雜的

9、Zuul路由閘道器

概述

什麼是Zuul?

Zuul包含了對請求的路由和過濾兩個最主要的功能:
其中路由功能負責將外部請求轉發到具體的微服務例項上,實現外部訪問統-入口的基礎, 而過濾器功能則
負責對請求的處理過程進行干預,是實現請求校驗,服務聚合等功能的基礎。Zuul和Eureka進行整合,將Zuul自
身註冊為Eureka服務治理下的應用,同時從Eureka中獲得其他微服務的訊息,也即以後的訪問微服務都是通過
Zuul跳轉後獲得。

注意: Zuul服務最終還是會註冊進Eureka
提供:代理+路由+過濾三大功能!

Zuul能幹嘛?
●路由
●過濾
官網文件: https://github.com/Netflix/zuul

步驟

本地更改

1.建立springcloud-zuul-9527

2.匯入依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--ribbon-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--eureka-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--實體類+web-->
        <dependency>
            <groupId>com.kuang</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

3.新增配置

server:
  port: 9527


spring:
  application:
    name: springcloud-zuul

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

  instance:
    instance-id: zuul9527.com
    prefer-ip-address: true

info:
  app.name: kuang-springcloud
  company.name: blog.kuangstudy.com

4.啟動類

@SpringBootApplication
@EnableZuulProxy //
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class, args);
    }
}

5.啟動7001/8001/9527測試訪問

使用路由閘道器保證了本地域名不被洩漏

隱藏真實的微服務名字(閘道器的一些配置)

新增yml配置

zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/**
  ignored-services: "*" #不能再使用這個路徑訪間了ignored :忽略。隱藏全部的~
  prefix: /kuang #設定公共的字首

啟動7001/8001/9527訪問測試

10、config分散式配置

10.1、概述

分散式系統面臨的-配置檔案的問題
微服務意味著要將單體應用中的業務拆分成一個個子服務,每個服務的粒度相對較小,因此係統中會出現大量的服
務,由於每個服務都需要必要的配置資訊才能執行,所以一套集中式的,動態的配置管理設施是必不可少的。
SpringCloud提供了ConfigServer來解決這個問題,我們每一個微服務自己帶著- -個application.yml, 那上百的的
配置檔案要修改起來,豈不是要發瘋! .

什麼是SpringCloud config分散式配置中心

Spring Cloud Config為微服務架構中的微服務提供集中化的外部配置支援,配置伺服器為各個不同微服務應用
的所有環節提供了一個中心化的外部配置。

Spring Cloud Config 分為服務端客戶端兩部分;
服務端也稱為分散式配置中心,它是一 個獨立的微服務應用,用來連線配置伺服器併為客戶端提供獲取配置信
息,加密,解密資訊等訪問介面。
客戶端則是通過指定的配置中心來管理應用資源,以及與業務相關的配置內容,並在啟動的時候從配置中心獲
取和載入配置資訊。配置伺服器預設採用gjt來儲存配置資訊,這樣就有助於對環境配置進行版本管理。並且可以
通過git客戶端工具來方便的管理和訪問配置內容。

SpringCloud config分散式配置中心能幹嘛
●集中管理配置檔案
●不同環境,不同配置,動態化的配置更新,分環境部署,比如/dev /test/ /prod /beta /release-
●執行期間動態調整配置,不再需要在每個服務部署的機器上編寫配置檔案,服務會向配置中心統一拉取配置自
己的資訊。
●當配置發生變動時,服務不需要重啟,即可感知到配置的變化,並應用新的配置
●將配置資訊以REST介面的形式暴露
SpringCloud config分散式配置中心與github整合
由於Spring Cloud Config預設使用Git來儲存配置檔案(也有其他方式, 比如支援SVN和本地檔案),但是最推
薦的還是Git,而且使用的是http 1 https訪問的形式;

10.2、Git環境搭建

碼雲中新建倉庫

1、

2、

倉庫下載到本地

3、點選克隆下載,選中SSH,複製

4、建立資料夾GIT,右擊開啟Git Bash Here

輸入

git clone [email protected]:zhuanqianyangxibei/springcloud-config.git

輸入

yes

發現

第一次配出現以下許可權問題

解決辦法

1、開啟碼雲,點選設定點選SSH公鑰,生成一個公鑰

ssh-keygen -t rsa -C "[email protected]"

2、可以在這個位置找到生成的公鑰

3、新增公鑰到碼雲

4、輸入克隆命令

5、成功克隆到本地

遠端檔案提交到碼雲

1.在springcloud-config目錄下建立application.yml

2.輸入命令

切換當前目錄下

cd springcloud-config/

新增

git add .

獲得狀態

git status

提交以及設定提交名字

git commit -m "first commit"

遠端提交到碼雲

git push origin master

3、重新整理碼雲發現遠端提交成功

10.3、服務端連線Git配置

步驟

1.匯入依賴

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    <!--<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>-->
    <!--actuator完善監控資訊-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

2.編寫配置檔案

server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    #連線遠端倉庫
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/zhuanqianyangxibei/springcloud-config.git # https ,不是SSH
#通過config-server可以連線到git, 訪問其中的資源以及配置~


3、啟動類及開啟服務

@SpringBootApplication
@EnableConfigServer//
public class Config_Server_3344 {
    public static void main(String[] args) {
        SpringApplication.run(Config_Server_3344.class, args);
    }

}

4、啟動測試

實現了遠端訪問

10.4、客戶端連線服務端訪問遠端

D:\Project\IdeaProject\GIT\springcloud-config中建立一個config-client.yml

四步遠端提交到碼雲

步驟

1.匯入依賴

  <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2.編寫配置檔案

bootstrap.yml

#系統級別的配置
spring:
  cloud:
    config:
      name: config-client #需要從git上讀取的資源名稱,不要字尾
      profile: dev
      label: master
      uri: http://localhost:3344

application.yml

#使用者級別的配置
spring:
  application:
    name: springcloud-config-client-3355

3、編寫ConfigClientController

@RestController
public class ConfigClientController {

    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer;
    @Value("${server.port}")
    private String port;

    @RequestMapping("/config")
    public String getConfig() {
        return " applicationName : " + applicationName +
                "eurekaServer : " + eurekaServer +
                "port:" + port;
    }

}

4、編寫啟動類

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

}

5、啟動3344/3355測試訪問

10.5、遠端配置實戰測試

以eureka為例建立配置

spring:
  profiles:
    active: dev
  
---  
server:
  port: 7001
  
#spring配置
spring:
  profiles: dev
  application:
    name: springcloud-config-eureka
  
#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com 
  client:
    register-with-eureka: false
    fetch-registry: false 
    service-url: # 監控頁面~
      #單機 http://${eureka.instance.hostname}:${server.port}/eureka/
      #(叢集)關聯 http://eureka7002.com:7002,http://eureka7003.com:7003
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      
---  
server:
  port: 7001
  
#spring配置
spring:
  profiles: test
  application:
    name: springcloud-config-eureka
  
#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com 
  client:
    register-with-eureka: false
    fetch-registry: false 
    service-url: # 監控頁面~
      #單機 http://${eureka.instance.hostname}:${server.port}/eureka/
      #(叢集)關聯 http://eureka7002.com:7002,http://eureka7003.com:7003
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
    

編寫專案springcloud-config-eureka-7001

1、匯入pom

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

2、編寫配置檔案

bootstrap.yml(連線遠端

#系統級別的配置
spring:
  cloud:
    config:
      name: config-eureka #需要從git上讀取的資源名稱,不要字尾
      profile: dev
      label: master
      uri: http://localhost:3344

application.yml

#使用者級別的配置
spring:
  application:
    name: springcloud-config-eureka-7001

3、啟動類

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer服務端的啟動類,可以接受別人註冊進*
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class, args);
    }
}

4、先啟動3344

再啟動7001

遠端配置成功

小結

以後