【轉】 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
- Spring cloud NetFlix 一站式解決方案!
api閘道器,zuu1元件
Feign --- HttpClinet ---- Http通訊方式,同步,阻塞
服務註冊發現: Eureka
熔斷機制: Hystrix
。。。。
-
Apache Dubbo Zookeeper 半自動,需要整合別人的!
API:沒有,找第三方元件,或者自己實現
Dubbo
Zookeeper
沒有:藉助Hystrix
Dubbo這個方案並不完善~ -
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
-
IDEA 工具裡面使用Maven開發的一個個獨立的小Moudle,它具體是使用springboot開發的一個小模組,專業的事情交給專業的模組來做,一個模組就做著一件事情
-
強調的是一個個的個體,每個個體完成一個具體的任務或者功能!
微服務架構
一種新的架構形式, 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就認為客戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:
-
Eureka不再從註冊列表中移除因為長時間沒收到心跳而應該過期的服務
-
Eureka仍然能夠接受新服務的註冊和查詢請求,但是不會被同步到其他節點上(即保證當前節點依然可用)
-
當網路穩定時,當前例項新的註冊資訊會被同步到其他節點中
因此,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,主要是社群,大家都習慣面向介面程式設計。這個是很多開發人員的規範。呼叫微服務訪問兩種方法
- 微服務名字[ribbon]
- 介面和註解[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
遠端配置成功
小結
以後