javascript
SpringCloud(笔记)
簡介
學(xué)習(xí)前提
-
熟練使用SpringBoot 微服務(wù)快速開發(fā)框架
-
了解過Dubbo + Zookeeper 分布式基礎(chǔ)
-
電腦配置內(nèi)存不低于8G(我自己的是16G)
-
給大家看下多個(gè)服務(wù)跑起來后的內(nèi)存開銷圖:
-
文章大綱
微服務(wù)架構(gòu)面臨的四個(gè)核心問題?
1.服務(wù)很多,客戶端應(yīng)該如何訪問? API網(wǎng)關(guān)
2.這么多服務(wù)?服務(wù)之間如何通信? HTTP,RPC通信
3.這么多服務(wù)?如何治理? 服務(wù)注冊(cè)與發(fā)現(xiàn)
4.服務(wù)掛了怎么辦?熔斷機(jī)制
Spring Cloud 五大組件
- 服務(wù)注冊(cè)與發(fā)現(xiàn)——Netflix Eureka
- 負(fù)載均衡:
- 客戶端負(fù)載均衡——Netflix Ribbon
- 服務(wù)端負(fù)載均衡:——Feign(其也是依賴于Ribbon,只是將調(diào)用方式RestTemplete 更改成Service 接口)
- 斷路器——Netflix Hystrix
- 服務(wù)網(wǎng)關(guān)——Netflix Zuul
- 分布式配置——Spring Cloud Config
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-qZHjHspt-1610725250868)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114163141181.png)]
1.3 常見面試題
1.1 什么是微服務(wù)?
1.2 微服務(wù)之間是如何獨(dú)立通訊的?
1.3 SpringCloud 和 Dubbo有那些區(qū)別?
1.4 SpringBoot 和 SpringCloud,請(qǐng)談?wù)勀銓?duì)他們的理解
1.5 什么是服務(wù)熔斷?什么是服務(wù)降級(jí)?
1.6 微服務(wù)的優(yōu)缺點(diǎn)分別是什么?說下你在項(xiàng)目開發(fā)中遇到的坑
1.7 你所知道的微服務(wù)技術(shù)棧有哪些?列舉一二
1.8 Eureka和Zookeeper都可以提供服務(wù)注冊(cè)與發(fā)現(xiàn)的功能,請(qǐng)說說兩者的區(qū)別
…
微服務(wù)概述
什么是微服務(wù)?
什么是微服務(wù)?
微服務(wù)(Microservice Architecture) 是近幾年流行的一種架構(gòu)思想,關(guān)于它的概念很難一言以蔽之。
究竟什么是微服務(wù)呢?我們?cè)诖艘肨houghtWorks 公司的首席科學(xué)家 Martin Fowler 于2014年提出的一段話:
原文:https://martinfowler.com/articles/microservices.html
漢化:https://www.cnblogs.com/liuning8023/p/4493156.html
- 就目前而言,對(duì)于微服務(wù),業(yè)界并沒有一個(gè)統(tǒng)一的,標(biāo)準(zhǔn)的定義。
- 但通常而言,微服務(wù)架構(gòu)是一種架構(gòu)模式,或者說是一種架構(gòu)風(fēng)格,它體長將單一的應(yīng)用程序劃分成一組小的服務(wù),每個(gè)服務(wù)運(yùn)行在其獨(dú)立的自己的進(jìn)程內(nèi),服務(wù)之間互相協(xié)調(diào),互相配置,為用戶提供最終價(jià)值,服務(wù)之間采用輕量級(jí)的通信機(jī)制(HTTP)互相溝通,每個(gè)服務(wù)都圍繞著具體的業(yè)務(wù)進(jìn)行構(gòu)建,并且能狗被獨(dú)立的部署到生產(chǎn)環(huán)境中,另外,應(yīng)盡量避免統(tǒng)一的,集中式的服務(wù)管理機(jī)制,對(duì)具體的一個(gè)服務(wù)而言,應(yīng)該根據(jù)業(yè)務(wù)上下文,選擇合適的語言,工具(Maven)對(duì)其進(jìn)行構(gòu)建,可以有一個(gè)非常輕量級(jí)的集中式管理來協(xié)調(diào)這些服務(wù),可以使用不同的語言來編寫服務(wù),也可以使用不同的數(shù)據(jù)存儲(chǔ)。
再來從技術(shù)維度角度理解下:
- 微服務(wù)化的核心就是將傳統(tǒng)的一站式應(yīng)用,根據(jù)業(yè)務(wù)拆分成一個(gè)一個(gè)的服務(wù),徹底地去耦合,每一個(gè)微服務(wù)提供單個(gè)業(yè)務(wù)功能的服務(wù),一個(gè)服務(wù)做一件事情,從技術(shù)角度看就是一種小而獨(dú)立的處理過程,類似進(jìn)程的概念,能夠自行單獨(dú)啟動(dòng)或銷毀,擁有自己獨(dú)立的數(shù)據(jù)庫。
微服務(wù)與微服務(wù)架構(gòu)
微服務(wù)
強(qiáng)調(diào)的是服務(wù)的大小,它關(guān)注的是某一個(gè)點(diǎn),是具體解決某一個(gè)問題/提供落地對(duì)應(yīng)服務(wù)的一個(gè)服務(wù)應(yīng)用,狹義的看,可以看作是IDEA中的一個(gè)個(gè)微服務(wù)工程,或者M(jìn)oudel。IDEA 工具里面使用Maven開發(fā)的一個(gè)個(gè)獨(dú)立的小Moudel,它具體是使用SpringBoot開發(fā)的一個(gè)小模塊,專業(yè)的事情交給專業(yè)的模塊來做,一個(gè)模塊就做著一件事情。強(qiáng)調(diào)的是一個(gè)個(gè)的個(gè)體,每個(gè)個(gè)體完成一個(gè)具體的任務(wù)或者功能。
微服務(wù)架構(gòu)
一種新的架構(gòu)形式,Martin Fowler 于2014年提出。
微服務(wù)架構(gòu)是一種架構(gòu)模式,它體長將單一應(yīng)用程序劃分成一組小的服務(wù),服務(wù)之間相互協(xié)調(diào),互相配合,為用戶提供最終價(jià)值。每個(gè)服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中,服務(wù)與服務(wù)之間采用輕量級(jí)的通信機(jī)制**(如HTTP)互相協(xié)作,每個(gè)服務(wù)都圍繞著具體的業(yè)務(wù)進(jìn)行構(gòu)建,并且能夠被獨(dú)立的部署到生產(chǎn)環(huán)境中,另外,應(yīng)盡量避免統(tǒng)一的,集中式的服務(wù)管理機(jī)制,對(duì)具體的一個(gè)服務(wù)而言,應(yīng)根據(jù)業(yè)務(wù)上下文,選擇合適的語言、工具(如Maven)**對(duì)其進(jìn)行構(gòu)建。
微服務(wù)優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 單一職責(zé)原則;
- 每個(gè)服務(wù)足夠內(nèi)聚,足夠小,代碼容易理解,這樣能聚焦一個(gè)指定的業(yè)務(wù)功能或業(yè)務(wù)需求;
- 開發(fā)簡單,開發(fā)效率高,一個(gè)服務(wù)可能就是專一的只干一件事;
- 微服務(wù)能夠被小團(tuán)隊(duì)單獨(dú)開發(fā),這個(gè)團(tuán)隊(duì)只需2-5個(gè)開發(fā)人員組成;
- 微服務(wù)是松耦合的,是有功能意義的服務(wù),無論是在開發(fā)階段或部署階段都是獨(dú)立的;
- 微服務(wù)能使用不同的語言開發(fā);
- 易于和第三方集成,微服務(wù)允許容易且靈活的方式集成自動(dòng)部署,通過持續(xù)集成工具,如jenkins,Hudson,bamboo;
- 微服務(wù)易于被一個(gè)開發(fā)人員理解,修改和維護(hù),這樣小團(tuán)隊(duì)能夠更關(guān)注自己的工作成果,無需通過合作才能體現(xiàn)價(jià)值;
- 微服務(wù)允許利用和融合最新技術(shù);
- 微服務(wù)只是業(yè)務(wù)邏輯的代碼,不會(huì)和HTML,CSS,或其他的界面混合;
- 每個(gè)微服務(wù)都有自己的存儲(chǔ)能力,可以有自己的數(shù)據(jù)庫,也可以有統(tǒng)一的數(shù)據(jù)庫;
缺點(diǎn)
- 開發(fā)人員要處理分布式系統(tǒng)的復(fù)雜性;
- 多服務(wù)運(yùn)維難度,隨著服務(wù)的增加,運(yùn)維的壓力也在增大;
- 系統(tǒng)部署依賴問題;
- 服務(wù)間通信成本問題;
- 數(shù)據(jù)一致性問題;
- 系統(tǒng)集成測試問題;
- 性能和監(jiān)控問題;
微服務(wù)技術(shù)棧有那些?
| 服務(wù)開發(fā) | SpringBoot、Spring、SpringMVC等 |
| 服務(wù)配置與管理 | Netfix公司的Archaius、阿里的Diamond等 |
| 服務(wù)注冊(cè)與發(fā)現(xiàn) | Eureka、Consul、Zookeeper等 |
| 服務(wù)調(diào)用 | Rest、PRC、gRPC |
| 服務(wù)熔斷器 | Hystrix、Envoy等 |
| 負(fù)載均衡 | Ribbon、Nginx等 |
| 服務(wù)接口調(diào)用(客戶端調(diào)用服務(wù)的簡化工具) | Fegin等 |
| 消息隊(duì)列 | Kafka、RabbitMQ、ActiveMQ等 |
| 服務(wù)配置中心管理 | SpringCloudConfig、Chef等 |
| 服務(wù)路由(API網(wǎng)關(guān)) | Zuul等 |
| 服務(wù)監(jiān)控 | Zabbix、Nagios、Metrics、Specatator等 |
| 全鏈路追蹤 | Zipkin、Brave、Dapper等 |
| 數(shù)據(jù)流操作開發(fā)包 | SpringCloud Stream(封裝與Redis,Rabbit,Kafka等發(fā)送接收消息) |
| 時(shí)間消息總棧 | SpringCloud Bus |
| 服務(wù)部署 | Docker、OpenStack、Kubernetes等 |
為什么選擇SpringCloud作為微服務(wù)架構(gòu)
選型依據(jù)
- 整體解決方案和框架成熟度
- 社區(qū)熱度
- 可維護(hù)性
- 學(xué)習(xí)曲線
當(dāng)前各大IT公司用的微服務(wù)架構(gòu)有那些?
-
阿里:dubbo+HFS
-
京東:JFS
-
新浪:Motan
-
當(dāng)當(dāng)網(wǎng):DubboX
…
各微服務(wù)框架對(duì)比
| 功能定位 | 完整的微服務(wù)框架 | RPC框架,但整合了ZK或Consul,實(shí)現(xiàn)集群環(huán)境的基本服務(wù)注冊(cè)發(fā)現(xiàn) | RPC框架 | RPC框架 | 服務(wù)框架 |
| 支持Rest | 是,Ribbon支持多種可拔插的序列號(hào)選擇 | 否 | 否 | 否 | 否 |
| 支持RPC | 否 | 是(Hession2) | 是 | 是 | 是 |
| 支持多語言 | 是(Rest形式) | 否 | 是 | 是 | 否 |
| 負(fù)載均衡 | 是(服務(wù)端zuul+客戶端Ribbon),zuul-服務(wù),動(dòng)態(tài)路由,云端負(fù)載均衡Eureka(針對(duì)中間層服務(wù)器) | 是(客戶端) | 否 | 否 | 是(客戶端) |
| 配置服務(wù) | Netfix Archaius,Spring Cloud Config Server 集中配置 | 是(Zookeeper提供) | 否 | 否 | 否 |
| 服務(wù)調(diào)用鏈監(jiān)控 | 是(zuul),zuul提供邊緣服務(wù),API網(wǎng)關(guān) | 否 | 否 | 否 | 否 |
| 高可用/容錯(cuò) | 是(服務(wù)端Hystrix+客戶端Ribbon) | 是(客戶端) | 否 | 否 | 是(客戶端) |
| 典型應(yīng)用案例 | Netflix | Sina | |||
| 社區(qū)活躍程度 | 高 | 一般 | 高 | 一般 | 2017年后重新開始維護(hù),之前中斷了5年 |
| 學(xué)習(xí)難度 | 中等 | 低 | 高 | 高 | 低 |
| 文檔豐富程度 | 高 | 一般 | 一般 | 一般 | 高 |
| 其他 | Spring Cloud Bus為我們的應(yīng)用程序帶來了更多管理端點(diǎn) | 支持降級(jí) | Netflix內(nèi)部在開發(fā)集成gRPC | IDL定義 | 實(shí)踐的公司比較多 |
SpringCloud入門概述
SpringCloud是什么?
Spring官網(wǎng):https://spring.io/
SpringCloud和SpringBoot的關(guān)系
- SpringBoot專注于開蘇方便的開發(fā)單個(gè)個(gè)體微服務(wù);-jar
- SpringCloud是關(guān)注全局的微服務(wù)協(xié)調(diào)整理治理框架,它將SpringBoot開發(fā)的一個(gè)個(gè)單體微服務(wù),整合并管理起來,為各個(gè)微服務(wù)之間提供:配置管理、服務(wù)發(fā)現(xiàn)、斷路器、路由、為代理、事件總棧、全局鎖、決策競選、分布式會(huì)話等等集成服務(wù);
- SpringBoot可以離開SpringCloud獨(dú)立使用,開發(fā)項(xiàng)目,但SpringCloud離不開SpringBoot,屬于依賴關(guān)系;
- SpringBoot專注于快速、方便的開發(fā)單個(gè)個(gè)體微服務(wù),SpringCloud關(guān)注全局的服務(wù)治理框架;
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-thoChIwl-1610725250901)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114165746964.png)]
Dubbo 和 SpringCloud技術(shù)選型
目前成熟的互聯(lián)網(wǎng)架構(gòu),應(yīng)用服務(wù)化拆分 + 消息中間件
可以看一下社區(qū)活躍度:
https://github.com/dubbo
https://github.com/spring-cloud
對(duì)比結(jié)果:
| 服務(wù)注冊(cè)中心 | Zookeeper | Spring Cloud Netfilx Eureka |
| 服務(wù)調(diào)用方式 | RPC | REST API |
| 服務(wù)監(jiān)控 | Dubbo-monitor | Spring Boot Admin |
| 斷路器 | 不完善 | Spring Cloud Netfilx Hystrix |
| 服務(wù)網(wǎng)關(guān) | 無 | Spring Cloud Netfilx Zuul |
| 分布式配置 | 無 | Spring Cloud Config |
| 服務(wù)跟蹤 | 無 | Spring Cloud Sleuth |
| 消息總棧 | 無 | Spring Cloud Bus |
| 數(shù)據(jù)流 | 無 | Spring Cloud Stream |
| 批量任務(wù) | 無 | Spring Cloud Task |
最大區(qū)別:Spring Cloud 拋棄了Dubbo的RPC通信,采用的是基于HTTP的REST方式
嚴(yán)格來說,這兩種方式各有優(yōu)劣。雖然從一定程度上來說,后者犧牲了服務(wù)調(diào)用的性能,但也避免了上面提到的原生RPC帶來的問題。而且REST相比RPC更為靈活,服務(wù)提供方和調(diào)用方的依賴只依靠一紙契約,不存在代碼級(jí)別的強(qiáng)依賴,這個(gè)優(yōu)點(diǎn)在當(dāng)下強(qiáng)調(diào)快速演化的微服務(wù)環(huán)境下,顯得更加合適。
品牌機(jī)和組裝機(jī)的區(qū)別
社區(qū)支持與更新力度的區(qū)別
**總結(jié):**二者解決的問題域不一樣:Dubbo的定位是一款RPC框架,而SpringCloud的目標(biāo)是微服務(wù)架構(gòu)下的一站式解決方案。
SpringCloud作用
- Distributed/versioned configuration 分布式/版本控制配置
- Service registration and discovery 服務(wù)注冊(cè)與發(fā)現(xiàn)
- Routing 路由
- Service-to-service calls 服務(wù)到服務(wù)的調(diào)用
- Load balancing 負(fù)載均衡配置
- Circuit Breakers 斷路器
- Distributed messaging 分布式消息管理
- …
3.5 SpringCloud下載
官網(wǎng):http://projects.spring.io/spring-cloud/
版本號(hào)有點(diǎn)特別:
SpringCloud沒有采用數(shù)字編號(hào)的方式命名版本號(hào),而是采用了倫敦地鐵站的名稱,同時(shí)根據(jù)字母表的順序來對(duì)應(yīng)版本時(shí)間順序,比如最早的Realse版本:Angel,第二個(gè)Realse版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Hoxton SR4 CURRENT GA通用穩(wěn)定版。
自學(xué)參考書:
- SpringCloud Netflix 中文文檔:https://springcloud.cc/spring-cloud-netflix.html
- SpringCloud 中文API文檔(官方文檔翻譯版):https://springcloud.cc/spring-cloud-dalston.html
- SpringCloud中國社區(qū):http://springcloud.cn/
- SpringCloud中文網(wǎng):https://springcloud.cc
Rest環(huán)境搭建:服務(wù)提供者和消費(fèi)者
4.1 介紹
- 我們會(huì)使用一個(gè)Dept部門模塊做一個(gè)微服務(wù)通用案例Consumer消費(fèi)者(Client)通過REST調(diào)用Provider提供者(Server)提供的服務(wù)。
- 回顧Spring,SpringMVC,Mybatis等以往學(xué)習(xí)的知識(shí)。
- Maven的分包分模塊架構(gòu)復(fù)習(xí)。
一個(gè)父工程帶著多個(gè)Moudule子模塊
MicroServiceCloud父工程(Project)下初次帶著3個(gè)子模塊(Module)
- microservicecloud-api 【封裝的整體entity/接口/公共配置等】
- microservicecloud-consumer-dept-80 【服務(wù)消費(fèi)者】
- microservicecloud-provider-dept-8001 【服務(wù)提供者】
版本選擇
大版本說明
| 1.2.x | Angel版本(天使) | 兼容SpringBoot1.2x |
| 1.3.x | Brixton版本(布里克斯頓) | 兼容SpringBoot1.3x,也兼容SpringBoot1.4x |
| 1.4.x | Camden版本(卡姆登) | 兼容SpringBoot1.4x,也兼容SpringBoot1.5x |
| 1.5.x | Dalston版本(多爾斯頓) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 1.5.x | Edgware版本(埃奇韋爾) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 2.0.x | Finchley版本(芬奇利) | 兼容SpringBoot2.0x,不兼容SpringBoot1.5x |
| 2.1.x | Greenwich版本(格林威治) |
實(shí)際開發(fā)版本關(guān)系
| 版本號(hào) | 發(fā)布日期 | 版本號(hào) | 發(fā)布日期 |
| 1.5.2.RELEASE | 2017-03 | Dalston.RC1 | 2017-x |
| 1.5.9.RELEASE | 2017-11 | Edgware.RELEASE | 2017-11 |
| 1.5.16.RELEASE | 2018-04 | Edgware.SR5 | 2018-10 |
| 1.5.20.RELEASE | 2018-09 | Edgware.SR5 | 2018-10 |
| 2.0.2.RELEASE | 2018-05 | Fomchiey.BULD-SNAPSHOT | 2018-x |
| 2.0.6.RELEASE | 2018-10 | Fomchiey-SR2 | 2018-10 |
| 2.1.4.RELEASE | 2019-04 | Greenwich.SR1 | 2019-03 |
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-YQMJStT4-1610725250911)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114191102105.png)]
使用后兩個(gè)
創(chuàng)建父工程
- 新建父工程項(xiàng)目springcloud,切記Packageing是pom模式
- 主要是定義POM文件,將后續(xù)各個(gè)子模塊公用的jar包等統(tǒng)一提取出來,類似一個(gè)抽象父類
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.haust</groupId><artifactId>springcloud</artifactId><version>1.0-SNAPSHOT</version><modules><module>springcloud-api</module><module>springcloud-provider-dept-8001</module><module>springcloud-consumer-dept-80</module><module>springcloud-eureka-7001</module><module>springcloud-eureka-7002</module><module>springcloud-eureka-7003</module><module>springcloud-provider-dept-8002</module><module>springcloud-provider-dept-8003</module><module>springcloud-consumer-dept-feign</module><module>springcloud-provider-dept-hystrix-8001</module><module>springcloud-consumer-hystrix-dashboard</module><module>springcloud-zuul-9527</module><module>springcloud-config-server-3344</module><module>springcloud-config-client-3355</module><module>springcloud-config-eureka-7001</module><module>springcloud-config-dept-8001</module></modules><!--打包方式 pom--><packaging>pom</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>0.2.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--springCloud的依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR1</version><type>pom</type><scope>import</scope></dependency><!--SpringBoot--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.4.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--數(shù)據(jù)庫--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--SpringBoot 啟動(dòng)器--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><!--日志測試~--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency></dependencies></dependencyManagement></project>父工程為springcloud,其下有多個(gè)子mudule,詳情參考完整代碼了解
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-HFnBrn3k-1610725250913)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114203950885.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-Rt1agP63-1610725250915)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114205910420.png)]
springcloud-provider-dept-8001(提供者)
server:port: 8001 mybatis:type-aliases-package: com.kuang.springcloud.pojoconfig-location: classpath:mybatis/mapper-config.xmlmapper-locations: classpath:mybatis/mapper/*.xml# spring配置 spring:application:name: springcloud-provider-deptdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db01?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: 123456springcloud-consumer-dept-80訪問springcloud-provider-dept-8001下的controller使用REST方式
springcloud-consumer-dept-80(消費(fèi)者)
80端口請(qǐng)求的時(shí)候不用帶端口號(hào)
如DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {/*** 理解:消費(fèi)者,不應(yīng)該有service層~* RestTemplate .... 供我們直接調(diào)用就可以了! 注冊(cè)到Spring中* (地址:url, 實(shí)體:Map ,Class<T> responseType)* <p>* 提供多種便捷訪問遠(yuǎn)程http服務(wù)的方法,簡單的Restful服務(wù)模板~*/@Autowiredprivate RestTemplate restTemplate;/*** 服務(wù)提供方地址前綴* <p>* Ribbon:我們這里的地址,應(yīng)該是一個(gè)變量,通過服務(wù)名來訪問*/private static final String REST_URL_PREFIX = "http://localhost:8001";//private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";/*** 消費(fèi)方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {// postForObject(服務(wù)提供方地址(接口),參數(shù)實(shí)體,返回類型.class)return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);}/*** 消費(fèi)方根據(jù)id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {// getForObject(服務(wù)提供方地址(接口),返回類型.class)return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);}/*** 消費(fèi)方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);} }RestTemplete
使用RestTemplete先需要放入Spring容器中
提供多種便捷訪問遠(yuǎn)程http服務(wù)的方法,簡單的Restful服務(wù)模板~
ConfigBean.java
@Configuration public class ConfigBean {//@Configuration -- spring applicationContext.xml//配置負(fù)載均衡實(shí)現(xiàn)RestTemplate// IRule// RoundRobinRule 輪詢// RandomRule 隨機(jī)// AvailabilityFilteringRule : 會(huì)先過濾掉,跳閘,訪問故障的服務(wù)~,對(duì)剩下的進(jìn)行輪詢~// RetryRule : 會(huì)先按照輪詢獲取服務(wù)~,如果服務(wù)獲取失敗,則會(huì)在指定的時(shí)間內(nèi)進(jìn)行,重試@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();} }springcloud-provider-dept-8001的dao接口調(diào)用springcloud-api模塊下的pojo,可使用在springcloud-provider-dept-8001的pom文件導(dǎo)入springcloud-api模塊依賴的方式:
<!--我們需要拿到實(shí)體類,所以要配置api module--><dependency><groupId>com.haust</groupId><artifactId>springcloud-api</artifactId><version>1.0-SNAPSHOT</version></dependency>springcloud-consumer-dept-80和springcloud-provider-dept-8001的pom.xml和父工程下的依賴基本一樣,直接看完整代碼即可,不再添加重復(fù)筆記。
進(jìn)行測試
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-ccdx5yrc-1610725250918)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114231512178.png)]
Eureka服務(wù)注冊(cè)中心
5.1 什么是Eureka
- Netflix在涉及Eureka時(shí),遵循的就是API原則.
- Eureka是Netflix的有個(gè)子模塊,也是核心模塊之一。Eureka是基于REST的服務(wù),用于定位服務(wù),以實(shí)現(xiàn)云端中間件層服務(wù)發(fā)現(xiàn)和故障轉(zhuǎn)移,服務(wù)注冊(cè)與發(fā)現(xiàn)對(duì)于微服務(wù)來說是非常重要的,有了服務(wù)注冊(cè)與發(fā)現(xiàn),只需要使用服務(wù)的標(biāo)識(shí)符,就可以訪問到服務(wù),而不需要修改服務(wù)調(diào)用的配置文件了,功能類似于Dubbo的注冊(cè)中心,比如Zookeeper.
原理
- Eureka基本的架構(gòu)
- Springcloud 封裝了Netflix公司開發(fā)的Eureka模塊來實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn) (對(duì)比Zookeeper).
- Eureka采用了C-S的架構(gòu)設(shè)計(jì),EurekaServer作為服務(wù)注冊(cè)功能的服務(wù)器,他是服務(wù)注冊(cè)中心.
- 而系統(tǒng)中的其他微服務(wù),使用Eureka的客戶端連接到EurekaServer并維持心跳連接。這樣系統(tǒng)的維護(hù)人員就可以通過EurekaServer來監(jiān)控系統(tǒng)中各個(gè)微服務(wù)是否正常運(yùn)行,Springcloud 的一些其他模塊 (比如Zuul) 就可以通過EurekaServer來發(fā)現(xiàn)系統(tǒng)中的其他微服務(wù),并執(zhí)行相關(guān)的邏輯.
-
和Dubbo架構(gòu)對(duì)比.
-
Eureka 包含兩個(gè)組件:Eureka Server 和 Eureka Client.
-
Eureka Server 提供服務(wù)注冊(cè),各個(gè)節(jié)點(diǎn)啟動(dòng)后,回在EurekaServer中進(jìn)行注冊(cè),這樣Eureka Server中的服務(wù)注冊(cè)表中將會(huì)儲(chǔ)存所有課用服務(wù)節(jié)點(diǎn)的信息,服務(wù)節(jié)點(diǎn)的信息可以在界面中直觀的看到.
-
Eureka Client 是一個(gè)Java客戶端,用于簡化EurekaServer的交互,客戶端同時(shí)也具備一個(gè)內(nèi)置的,使用輪詢負(fù)載算法的負(fù)載均衡器。在應(yīng)用啟動(dòng)后,將會(huì)向EurekaServer發(fā)送心跳 (默認(rèn)周期為30秒) 。如果Eureka Server在多個(gè)心跳周期內(nèi)沒有接收到某個(gè)節(jié)點(diǎn)的心跳,EurekaServer將會(huì)從服務(wù)注冊(cè)表中把這個(gè)服務(wù)節(jié)點(diǎn)移除掉 (默認(rèn)周期為90s).
-
三大角色
- Eureka Server:提供服務(wù)的注冊(cè)與發(fā)現(xiàn)
- Service Provider:服務(wù)生產(chǎn)方,將自身服務(wù)注冊(cè)到Eureka中,從而使服務(wù)消費(fèi)方能狗找到
- Service Consumer:服務(wù)消費(fèi)方,從Eureka中獲取注冊(cè)服務(wù)列表,從而找到消費(fèi)服務(wù)
-
目前工程狀況
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-tJMcXLHL-1610725250919)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210114232936013.png)]
eureka-server
springcloud-eureka-7001 模塊建立
pom.xml 配置
<!--導(dǎo)包~--> <dependencies><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><!--導(dǎo)入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>application.yml
server:port: 7001# Eureka配置 eureka:instance:# Eureka服務(wù)端的實(shí)例名字hostname: 127.0.0.1client:# 表示是否向 Eureka 注冊(cè)中心注冊(cè)自己(這個(gè)模塊本身是服務(wù)器,所以不需要)register-with-eureka: false# fetch-registry如果為false,則表示自己為注冊(cè)中心,客戶端的化為 turefetch-registry: false# Eureka監(jiān)控頁面~service-url:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/源碼中Eureka的默認(rèn)端口以及訪問路徑:
主啟動(dòng)類
/*** @Auther: csp1999* @Date: 2020/05/18/10:26* @Description: 啟動(dòng)之后,訪問 http://127.0.0.1:7001/*/ @SpringBootApplication // @EnableEurekaServer 服務(wù)端的啟動(dòng)類,可以接受別人注冊(cè)進(jìn)來~ @EnableEurekaServer public class EurekaServer_7001 {public static void main(String[] args) {SpringApplication.run(EurekaServer_7001.class,args);} }啟動(dòng)成功后訪問 http://localhost:7001/ 得到以下頁面
eureka-client
調(diào)整之前創(chuàng)建的springlouc-provider-dept-8001
導(dǎo)入Eureca依賴
<!--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>application中新增Eureca配置
# Eureka配置:配置服務(wù)注冊(cè)中心地址 eureka:client:service-url:defaultZone: http://localhost:7001/eureka/為主啟動(dòng)類添加@EnableEurekaClient注解
/*** @Auther: csp1999* @Date: 2020/05/17/22:09* @Description: 啟動(dòng)類*/ @SpringBootApplication // @EnableEurekaClient 開啟Eureka客戶端注解,在服務(wù)啟動(dòng)后自動(dòng)向注冊(cè)中心注冊(cè)服務(wù) @EnableEurekaClient public class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);} }先啟動(dòng)7001服務(wù)端后啟動(dòng)8001客戶端進(jìn)行測試,然后訪問監(jiān)控頁http://localhost:7001/ 產(chǎn)看結(jié)果如圖,成功
修改Eureka上的默認(rèn)描述信息
# Eureka配置:配置服務(wù)注冊(cè)中心地址 eureka:client:service-url:defaultZone: http://localhost:7001/eureka/instance:instance-id: springcloud-provider-dept-8001 #修改Eureka上的默認(rèn)描述信息結(jié)果如圖:
如果此時(shí)停掉springcloud-provider-dept-8001 等30s后 監(jiān)控會(huì)開啟保護(hù)機(jī)制:
配置關(guān)于服務(wù)加載的監(jiān)控信息
熱部署配置
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-yMWwnCPJ-1610725250921)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115003227472.png)]
完善監(jiān)控信息(actuator)
pom.xml中添加依賴
<!--actuator完善監(jiān)控信息--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>application.yml中添加配置
# info配置 info: # 項(xiàng)目的名稱app.name: haust-springcloud # 公司的名稱company.name: 河南科技大學(xué)西苑校區(qū)軟件學(xué)院此時(shí)刷新監(jiān)控頁,點(diǎn)擊進(jìn)入跳轉(zhuǎn)新頁面顯示如下內(nèi)容:
自我保護(hù)機(jī)制:好死不如賴活著
一句話總結(jié)就是:某時(shí)刻某一個(gè)微服務(wù)不可用,eureka不會(huì)立即清理,依舊會(huì)對(duì)該微服務(wù)的信息進(jìn)行保存!
- 默認(rèn)情況下,當(dāng)eureka server在一定時(shí)間內(nèi)沒有收到實(shí)例的心跳,便會(huì)把該實(shí)例從注冊(cè)表中刪除(默認(rèn)是90秒),但是,如果短時(shí)間內(nèi)丟失大量的實(shí)例心跳,便會(huì)觸發(fā)eureka server的自我保護(hù)機(jī)制,比如在開發(fā)測試時(shí),需要頻繁地重啟微服務(wù)實(shí)例,但是我們很少會(huì)把eureka server一起重啟(因?yàn)樵陂_發(fā)過程中不會(huì)修改eureka注冊(cè)中心),當(dāng)一分鐘內(nèi)收到的心跳數(shù)大量減少時(shí),會(huì)觸發(fā)該保護(hù)機(jī)制。可以在eureka管理界面看到Renews threshold和Renews(last min),當(dāng)后者(最后一分鐘收到的心跳數(shù))小于前者(心跳閾值)的時(shí)候,觸發(fā)保護(hù)機(jī)制,會(huì)出現(xiàn)紅色的警告:EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.從警告中可以看到,eureka認(rèn)為雖然收不到實(shí)例的心跳,但它認(rèn)為實(shí)例還是健康的,eureka會(huì)保護(hù)這些實(shí)例,不會(huì)把它們從注冊(cè)表中刪掉。
- 該保護(hù)機(jī)制的目的是避免網(wǎng)絡(luò)連接故障,在發(fā)生網(wǎng)絡(luò)故障時(shí),微服務(wù)和注冊(cè)中心之間無法正常通信,但服務(wù)本身是健康的,不應(yīng)該注銷該服務(wù),如果eureka因網(wǎng)絡(luò)故障而把微服務(wù)誤刪了,那即使網(wǎng)絡(luò)恢復(fù)了,該微服務(wù)也不會(huì)重新注冊(cè)到eureka server了,因?yàn)橹挥性谖⒎?wù)啟動(dòng)的時(shí)候才會(huì)發(fā)起注冊(cè)請(qǐng)求,后面只會(huì)發(fā)送心跳和服務(wù)列表請(qǐng)求,這樣的話,該實(shí)例雖然是運(yùn)行著,但永遠(yuǎn)不會(huì)被其它服務(wù)所感知。所以,eureka server在短時(shí)間內(nèi)丟失過多的客戶端心跳時(shí),會(huì)進(jìn)入自我保護(hù)模式,該模式下,eureka會(huì)保護(hù)注冊(cè)表中的信息,不在注銷任何微服務(wù),當(dāng)網(wǎng)絡(luò)故障恢復(fù)后,eureka會(huì)自動(dòng)退出保護(hù)模式。自我保護(hù)模式可以讓集群更加健壯。
- 但是我們?cè)陂_發(fā)測試階段,需要頻繁地重啟發(fā)布,如果觸發(fā)了保護(hù)機(jī)制,則舊的服務(wù)實(shí)例沒有被刪除,這時(shí)請(qǐng)求有可能跑到舊的實(shí)例中,而該實(shí)例已經(jīng)關(guān)閉了,這就導(dǎo)致請(qǐng)求錯(cuò)誤,影響開發(fā)測試。所以,在開發(fā)測試階段,我們可以把自我保護(hù)模式關(guān)閉,只需在eureka server配置文件中加上如下配置即可:eureka.server.enable-self-preservation=false【不推薦關(guān)閉自我保護(hù)機(jī)制】
詳細(xì)內(nèi)容可以參考下這篇博客內(nèi)容:https://blog.csdn.net/wudiyong22/article/details/80827594
注冊(cè)進(jìn)來的微服務(wù),獲取一些消息(團(tuán)隊(duì)開發(fā)會(huì)用到)
DeptController.java新增方法
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-wDpAUERt-1610725250926)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115004810922.png)]
/*** DiscoveryClient 可以用來獲取一些配置的信息,得到具體的微服務(wù)!*/ @Autowired private DiscoveryClient client;/*** 獲取一些注冊(cè)進(jìn)來的微服務(wù)的信息~,** @return*/ @GetMapping("/dept/discovery") public Object discovery() {// 獲取微服務(wù)列表的清單List<String> services = client.getServices();System.out.println("discovery=>services:" + services);// 得到一個(gè)具體的微服務(wù)信息,通過具體的微服務(wù)id,applicaioinName;List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");for (ServiceInstance instance : instances) {System.out.println(instance.getHost() + "\t" + // 主機(jī)名稱instance.getPort() + "\t" + // 端口號(hào)instance.getUri() + "\t" + // uriinstance.getServiceId() // 服務(wù)id);}return this.client; }主啟動(dòng)類中加入@EnableDiscoveryClient 注解
@SpringBootApplication // @EnableEurekaClient 開啟Eureka客戶端注解,在服務(wù)啟動(dòng)后自動(dòng)向注冊(cè)中心注冊(cè)服務(wù) @EnableEurekaClient // @EnableEurekaClient 開啟服務(wù)發(fā)現(xiàn)客戶端的注解,可以用來獲取一些配置的信息,得到具體的微服務(wù) @EnableDiscoveryClient public class DeptProvider_8001 {... }結(jié)果如圖:
集群環(huán)境配置
1.初始化
新建springcloud-eureka-7002、springcloud-eureka-7003 模塊
1.為pom.xml添加依賴 (與springcloud-eureka-7001相同)
<!--導(dǎo)包~--> <dependencies><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><!--導(dǎo)入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配置(與springcloud-eureka-7001相同)
server:port: 7003# Eureka配置 eureka:instance:hostname: localhost # Eureka服務(wù)端的實(shí)例名字client:register-with-eureka: false # 表示是否向 Eureka 注冊(cè)中心注冊(cè)自己(這個(gè)模塊本身是服務(wù)器,所以不需要)fetch-registry: false # fetch-registry如果為false,則表示自己為注冊(cè)中心service-url: # 監(jiān)控頁面~# 重寫Eureka的默認(rèn)端口以及訪問路徑 --->http://localhost:7001/eureka/defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/3.主啟動(dòng)類(與springcloud-eureka-7001相同)
/*** @Auther: csp1999* @Date: 2020/05/18/10:26* @Description: 啟動(dòng)之后,訪問 http://127.0.0.1:7003/*/ @SpringBootApplication // @EnableEurekaServer 服務(wù)端的啟動(dòng)類,可以接受別人注冊(cè)進(jìn)來~ public class EurekaServer_7003 {public static void main(String[] args) {SpringApplication.run(EurekaServer_7003.class,args);} }2.集群成員相互關(guān)聯(lián)
配置一些自定義本機(jī)名字,找到本機(jī)hosts文件并打開
在hosts文件最后加上,要訪問的本機(jī)名稱,默認(rèn)是localhost
修改application.yml的配置,如圖為springcloud-eureka-7001配置,springcloud-eureka-7002/springcloud-eureka-7003同樣分別修改為其對(duì)應(yīng)的名稱即可
在集群中使springcloud-eureka-7001關(guān)聯(lián)springcloud-eureka-7002、springcloud-eureka-7003
完整的springcloud-eureka-7001下的application.yml如下
server:port: 7001#Eureka配置 eureka:instance:hostname: eureka7001.com #Eureka服務(wù)端的實(shí)例名字client:register-with-eureka: false #表示是否向 Eureka 注冊(cè)中心注冊(cè)自己(這個(gè)模塊本身是服務(wù)器,所以不需要)fetch-registry: false #fetch-registry如果為false,則表示自己為注冊(cè)中心service-url: #監(jiān)控頁面~#重寫Eureka的默認(rèn)端口以及訪問路徑 --->http://localhost:7001/eureka/# 單機(jī): defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/# 集群(關(guān)聯(lián)):7001關(guān)聯(lián)7002、7003defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/同時(shí)在集群中使springcloud-eureka-7002關(guān)聯(lián)springcloud-eureka-7001、springcloud-eureka-7003
完整的springcloud-eureka-7002下的application.yml如下
server:port: 7002#Eureka配置 eureka:instance:hostname: eureka7002.com #Eureka服務(wù)端的實(shí)例名字client:register-with-eureka: false #表示是否向 Eureka 注冊(cè)中心注冊(cè)自己(這個(gè)模塊本身是服務(wù)器,所以不需要)fetch-registry: false #fetch-registry如果為false,則表示自己為注冊(cè)中心service-url: #監(jiān)控頁面~#重寫Eureka的默認(rèn)端口以及訪問路徑 --->http://localhost:7001/eureka/# 單機(jī): defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/# 集群(關(guān)聯(lián)):7002關(guān)聯(lián)7001、7003defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/springcloud-eureka-7003配置方式同理可得.
通過springcloud-provider-dept-8001下的yml配置文件,修改Eureka配置:配置服務(wù)注冊(cè)中心地址
# Eureka配置:配置服務(wù)注冊(cè)中心地址 eureka:client:service-url:# 注冊(cè)中心地址7001-7003defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/instance:instance-id: springcloud-provider-dept-8001 #修改Eureka上的默認(rèn)描述信息這樣模擬集群就搭建號(hào)了,就可以把一個(gè)項(xiàng)目掛載到三個(gè)服務(wù)器上了
對(duì)比和Zookeeper
1. 回顧C(jī)AP原則
RDBMS (MySQL\Oracle\sqlServer) ===> ACID
NoSQL (Redis\MongoDB) ===> CAP
ACID
- A (Atomicity) 原子性
- C (Consistency) 一致性
- I (Isolation) 隔離性
- D (Durability) 持久性
CAP
- C (Consistency) 強(qiáng)一致性
- A (Availability) 可用性
- P (Partition tolerance) 分區(qū)容錯(cuò)性
CAP的三進(jìn)二:CA、AP、CP
CAP理論的核心
- 一個(gè)分布式系統(tǒng)不可能同時(shí)很好的滿足一致性,可用性和分區(qū)容錯(cuò)性這三個(gè)需求
- 根據(jù)CAP原理,將NoSQL數(shù)據(jù)庫分成了滿足CA原則,滿足CP原則和滿足AP原則三大類
- CA:單點(diǎn)集群,滿足一致性,可用性的系統(tǒng),通常可擴(kuò)展性較差
- CP:滿足一致性,分區(qū)容錯(cuò)的系統(tǒng),通常性能不是特別高
- AP:滿足可用性,分區(qū)容錯(cuò)的系統(tǒng),通常可能對(duì)一致性要求低一些
Eureka VS Zookeeper
著名的CAP理論指出,一個(gè)分布式系統(tǒng)不可能同時(shí)滿足C (一致性) 、A (可用性) 、P (容錯(cuò)性),由于分區(qū)容錯(cuò)性P再分布式系統(tǒng)中是必須要保證的,因此我們只能再A和C之間進(jìn)行權(quán)衡。
- Zookeeper 保證的是 CP —> 滿足一致性,分區(qū)容錯(cuò)的系統(tǒng),通常性能不是特別高
- Eureka 保證的是 AP —> 滿足可用性,分區(qū)容錯(cuò)的系統(tǒng),通常可能對(duì)一致性要求低一些
Zookeeper保證的是CP
當(dāng)向注冊(cè)中心查詢服務(wù)列表時(shí),我們可以容忍注冊(cè)中心返回的是幾分鐘以前的注冊(cè)信息,但不能接收服務(wù)直接down掉不可用。也就是說,服務(wù)注冊(cè)功能對(duì)可用性的要求要高于一致性。但zookeeper會(huì)出現(xiàn)這樣一種情況,當(dāng)master節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與其他節(jié)點(diǎn)失去聯(lián)系時(shí),剩余節(jié)點(diǎn)會(huì)重新進(jìn)行l(wèi)eader選舉。問題在于,選舉leader的時(shí)間太長,30-120s,且選舉期間整個(gè)zookeeper集群是不可用的,這就導(dǎo)致在選舉期間注冊(cè)服務(wù)癱瘓。在云部署的環(huán)境下,因?yàn)榫W(wǎng)絡(luò)問題使得zookeeper集群失去master節(jié)點(diǎn)是較大概率發(fā)生的事件,雖然服務(wù)最終能夠恢復(fù),但是,漫長的選舉時(shí)間導(dǎo)致注冊(cè)長期不可用,是不可容忍的。
Eureka保證的是AP
Eureka看明白了這一點(diǎn),因此在設(shè)計(jì)時(shí)就優(yōu)先保證可用性。Eureka各個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉不會(huì)影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊(cè)和查詢服務(wù)。而Eureka的客戶端在向某個(gè)Eureka注冊(cè)時(shí),如果發(fā)現(xiàn)連接失敗,則會(huì)自動(dòng)切換至其他節(jié)點(diǎn),只要有一臺(tái)Eureka還在,就能保住注冊(cè)服務(wù)的可用性,只不過查到的信息可能不是最新的,除此之外,Eureka還有之中自我保護(hù)機(jī)制,如果在15分鐘內(nèi)超過85%的節(jié)點(diǎn)都沒有正常的心跳,那么Eureka就認(rèn)為客戶端與注冊(cè)中心出現(xiàn)了網(wǎng)絡(luò)故障,此時(shí)會(huì)出現(xiàn)以下幾種情況:
- Eureka不在從注冊(cè)列表中移除因?yàn)殚L時(shí)間沒收到心跳而應(yīng)該過期的服務(wù)
- Eureka仍然能夠接受新服務(wù)的注冊(cè)和查詢請(qǐng)求,但是不會(huì)被同步到其他節(jié)點(diǎn)上 (即保證當(dāng)前節(jié)點(diǎn)依然可用)
- 當(dāng)網(wǎng)絡(luò)穩(wěn)定時(shí),當(dāng)前實(shí)例新的注冊(cè)信息會(huì)被同步到其他節(jié)點(diǎn)中
因此,Eureka可以很好的應(yīng)對(duì)因網(wǎng)絡(luò)故障導(dǎo)致部分節(jié)點(diǎn)失去聯(lián)系的情況,而不會(huì)像zookeeper那樣使整個(gè)注冊(cè)服務(wù)癱瘓
負(fù)載均衡Ribbon和Feign
Ribbon負(fù)載均衡(基于客戶端)
6.1 負(fù)載均衡以及Ribbon
Ribbon是什么?
- Spring Cloud Ribbon 是基于Netflix Ribbon 實(shí)現(xiàn)的一套客戶端負(fù)載均衡的工具。
- 簡單的說,Ribbon 是 Netflix 發(fā)布的開源項(xiàng)目,主要功能是提供客戶端的軟件負(fù)載均衡算法,將 Netflix 的中間層服務(wù)連接在一起。Ribbon 的客戶端組件提供一系列完整的配置項(xiàng),如:連接超時(shí)、重試等。簡單的說,就是在配置文件中列出 LoadBalancer (簡稱LB:負(fù)載均衡) 后面所有的及其,Ribbon 會(huì)自動(dòng)的幫助你基于某種規(guī)則 (如簡單輪詢,隨機(jī)連接等等) 去連接這些機(jī)器。我們也容易使用 Ribbon 實(shí)現(xiàn)自定義的負(fù)載均衡算法!
Ribbon能干嘛?
- LB,即負(fù)載均衡 (LoadBalancer) ,在微服務(wù)或分布式集群中經(jīng)常用的一種應(yīng)用。
- 負(fù)載均衡簡單的說就是將用戶的請(qǐng)求平攤的分配到多個(gè)服務(wù)上,從而達(dá)到系統(tǒng)的HA (高用)。
- 常見的負(fù)載均衡軟件有 Nginx、Lvs 等等。
- Dubbo、SpringCloud 中均給我們提供了負(fù)載均衡,SpringCloud 的負(fù)載均衡算法可以自定義。
負(fù)載均衡簡單分類
- 集中式LB
- 即在服務(wù)的提供方和消費(fèi)方之間使用獨(dú)立的LB設(shè)施,如Nginx(反向代理服務(wù)器),由該設(shè)施負(fù)責(zé)把訪問請(qǐng)求通過某種策略轉(zhuǎn)發(fā)至服務(wù)的提供方!
- 進(jìn)程式 LB
- 將LB邏輯集成到消費(fèi)方,消費(fèi)方從服務(wù)注冊(cè)中心獲知有哪些地址可用,然后自己再從這些地址中選出一個(gè)合適的服務(wù)器。
- Ribbon 就屬于進(jìn)程內(nèi)LB,它只是一個(gè)類庫,集成于消費(fèi)方進(jìn)程,消費(fèi)方通過它來獲取到服務(wù)提供方的地址!
集成Ribbon
springcloud-consumer-dept-80向pom.xml中添加Ribbon和Eureka依賴
<!--Ribbon--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--Eureka: Ribbon需要從Eureka服務(wù)中心獲取要拿什么--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version> </dependency>在application.yml文件中配置Eureka
# Eureka配置 eureka:client:register-with-eureka: false # 不向 Eureka注冊(cè)自己service-url: # 從三個(gè)注冊(cè)中心中隨機(jī)取一個(gè)去訪問defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/主啟動(dòng)類加上@EnableEurekaClient注解,開啟Eureka
//Ribbon 和 Eureka 整合以后,客戶端可以直接調(diào)用,不用關(guān)心IP地址和端口號(hào) @SpringBootApplication @EnableEurekaClient //開啟Eureka 客戶端 public class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class, args);} }自定義Spring配置類:ConfigBean.java 配置負(fù)載均衡實(shí)現(xiàn)RestTemplate
@Configuration public class ConfigBean {//@Configuration -- spring applicationContext.xml@LoadBalanced //配置負(fù)載均衡實(shí)現(xiàn)RestTemplate@Beanpublic RestTemplate getRestTemplate() {return new RestTemplate();} }修改conroller:DeptConsumerController.java
//Ribbon:我們這里的地址,應(yīng)該是一個(gè)變量,通過服務(wù)名來訪問 //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";數(shù)據(jù)庫導(dǎo)出
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-OxOU2SJU-1610725250930)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115135531598.png)]
使用Ribbon實(shí)現(xiàn)負(fù)載均衡
流程圖:
1.新建兩個(gè)服務(wù)提供者M(jìn)oudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002
2.參照springcloud-provider-dept-8001 依次為另外兩個(gè)Moudle添加pom.xml依賴 、resourece下的mybatis和application.yml配置,Java代碼
3.啟動(dòng)所有服務(wù)測試(根據(jù)自身電腦配置決定啟動(dòng)服務(wù)的個(gè)數(shù)),訪問http://eureka7001.com:7002/查看結(jié)果
測試訪問http://localhost/consumer/dept/list 這時(shí)候隨機(jī)訪問的是服務(wù)提供者8003
再次訪問http://localhost/consumer/dept/list這時(shí)候隨機(jī)的是服務(wù)提供者8001
以上這種每次訪問http://localhost/consumer/dept/list隨機(jī)訪問集群中某個(gè)服務(wù)提供者,這種情況叫做輪詢,輪詢算法在SpringCloud中可以自定義。
自定義負(fù)載均衡
在springcloud-provider-dept-80模塊下的ConfigBean中進(jìn)行配置,切換使用不同的規(guī)則
@Configuration public class ConfigBean {//@Configuration -- spring applicationContext.xml/*** IRule:* RoundRobinRule 輪詢策略* RandomRule 隨機(jī)策略* AvailabilityFilteringRule : 會(huì)先過濾掉,跳閘,訪問故障的服務(wù)~,對(duì)剩下的進(jìn)行輪詢~* RetryRule : 會(huì)先按照輪詢獲取服務(wù)~,如果服務(wù)獲取失敗,則會(huì)在指定的時(shí)間內(nèi)進(jìn)行,重試*/@Beanpublic IRule myRule() {return new RandomRule();//使用隨機(jī)策略//return new RoundRobinRule();//使用輪詢策略//return new AvailabilityFilteringRule();//使用輪詢策略//return new RetryRule();//使用輪詢策略} }也可以自定義規(guī)則,在myRule包下自定義一個(gè)配置類MyRule.java,注意:該包不要和主啟動(dòng)類所在的包同級(jí),要跟啟動(dòng)類所在包同級(jí):
MyRule.java
/*** @Auther: csp1999* @Date: 2020/05/19/11:58* @Description: 自定義規(guī)則*/ @Configuration public class MyRule {@Beanpublic IRule myRule(){return new MyRandomRule();//默認(rèn)是輪詢RandomRule,現(xiàn)在自定義為自己的} }主啟動(dòng)類開啟負(fù)載均衡并指定自定義的MyRule配置類
//Ribbon 和 Eureka 整合以后,客戶端可以直接調(diào)用,不用關(guān)心IP地址和端口號(hào) @SpringBootApplication @EnableEurekaClient //在微服務(wù)啟動(dòng)的時(shí)候就能加載自定義的Ribbon類(自定義的規(guī)則會(huì)覆蓋原有默認(rèn)的規(guī)則) @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//開啟負(fù)載均衡,并指定自定義的規(guī)則 public class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class, args);} }自定義的規(guī)則(這里我們參考Ribbon中默認(rèn)的規(guī)則代碼自己稍微改動(dòng)):MyRandomRule.java
public class MyRandomRule extends AbstractLoadBalancerRule {/*** 每個(gè)服務(wù)訪問5次則換下一個(gè)服務(wù)(總共3個(gè)服務(wù))* <p>* total=0,默認(rèn)=0,如果=5,指向下一個(gè)服務(wù)節(jié)點(diǎn)* index=0,默認(rèn)=0,如果total=5,index+1*/private int total = 0;//被調(diào)用的次數(shù)private int currentIndex = 0;//當(dāng)前是誰在提供服務(wù)//@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")public Server choose(ILoadBalancer lb, Object key) {if (lb == null) {return null;}Server server = null;while (server == null) {if (Thread.interrupted()) {return null;}List<Server> upList = lb.getReachableServers();//獲得當(dāng)前活著的服務(wù)List<Server> allList = lb.getAllServers();//獲取所有的服務(wù)int serverCount = allList.size();if (serverCount == 0) {/** No servers. End regardless of pass, because subsequent passes* only get more restrictive.*/return null;}//int index = chooseRandomInt(serverCount);//生成區(qū)間隨機(jī)數(shù)//server = upList.get(index);//從或活著的服務(wù)中,隨機(jī)獲取一個(gè)//=====================自定義代碼=========================if (total < 5) {server = upList.get(currentIndex);total++;} else {total = 0;currentIndex++;if (currentIndex > =upList.size()) {currentIndex = 0;}server = upList.get(currentIndex);//從活著的服務(wù)中,獲取指定的服務(wù)來進(jìn)行操作}//======================================================if (server == null) {/** The only time this should happen is if the server list were* somehow trimmed. This is a transient condition. Retry after* yielding.*/Thread.yield();continue;}if (server.isAlive()) {return (server);}// Shouldn't actually happen.. but must be transient or a bug.server = null;Thread.yield();}return server;}protected int chooseRandomInt(int serverCount) {return ThreadLocalRandom.current().nextInt(serverCount);}@Overridepublic Server choose(Object key) {return choose(getLoadBalancer(), key);}@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {// TODO Auto-generated method stub} }Feign負(fù)載均衡(基于服務(wù)端)
7.1 Feign簡介
Feign是聲明式Web Service客戶端,它讓微服務(wù)之間的調(diào)用變得更簡單,類似controller調(diào)用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供負(fù)載均衡的http客戶端
只需要?jiǎng)?chuàng)建一個(gè)接口,然后添加注解即可~
Feign,主要是社區(qū)版,大家都習(xí)慣面向接口編程。這個(gè)是很多開發(fā)人員的規(guī)范。調(diào)用微服務(wù)訪問兩種方法
Feign能干什么?
- Feign旨在使編寫Java Http客戶端變得更容易
- 前面在使用Ribbon + RestTemplate時(shí),利用RestTemplate對(duì)Http請(qǐng)求的封裝處理,形成了一套模板化的調(diào)用方法。但是在實(shí)際開發(fā)中,由于對(duì)服務(wù)依賴的調(diào)用可能不止一處,往往一個(gè)接口會(huì)被多處調(diào)用,所以通常都會(huì)針對(duì)每個(gè)微服務(wù)自行封裝一個(gè)客戶端類來包裝這些依賴服務(wù)的調(diào)用。所以,Feign在此基礎(chǔ)上做了進(jìn)一步的封裝,由他來幫助我們定義和實(shí)現(xiàn)依賴服務(wù)接口的定義,在Feign的實(shí)現(xiàn)下,我們只需要?jiǎng)?chuàng)建一個(gè)接口并使用注解的方式來配置它 (類似以前Dao接口上標(biāo)注Mapper注解,現(xiàn)在是一個(gè)微服務(wù)接口上面標(biāo)注一個(gè)Feign注解),即可完成對(duì)服務(wù)提供方的接口綁定,簡化了使用Spring Cloud Ribbon 時(shí),自動(dòng)封裝服務(wù)調(diào)用客戶端的開發(fā)量。
Feign默認(rèn)集成了Ribbon
- 利用Ribbon維護(hù)了MicroServiceCloud-Dept的服務(wù)列表信息,并且通過輪詢實(shí)現(xiàn)了客戶端的負(fù)載均衡,而與Ribbon不同的是,通過Feign只需要定義服務(wù)綁定接口且以聲明式的方法,優(yōu)雅而簡單的實(shí)現(xiàn)了服務(wù)調(diào)用。
Feign的使用
創(chuàng)建springcloud-consumer-fdept-feign模塊
拷貝springcloud-consumer-dept-80模塊下的pom.xml,resource,以及java代碼到springcloud-consumer-feign模塊,并添加feign依賴。
<!--Feign的依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><version>1.4.6.RELEASE</version> </dependency>通過Ribbon實(shí)現(xiàn):—原來的controller:DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {/*** 理解:消費(fèi)者,不應(yīng)該有service層~* RestTemplate .... 供我們直接調(diào)用就可以了! 注冊(cè)到Spring中* (地址:url, 實(shí)體:Map ,Class<T> responseType)* <p>* 提供多種便捷訪問遠(yuǎn)程http服務(wù)的方法,簡單的Restful服務(wù)模板~*/@Autowiredprivate RestTemplate restTemplate;/*** 服務(wù)提供方地址前綴* <p>* Ribbon:我們這里的地址,應(yīng)該是一個(gè)變量,通過服務(wù)名來訪問*/ // private static final String REST_URL_PREFIX = "http://localhost:8001";private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";/*** 消費(fèi)方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {// postForObject(服務(wù)提供方地址(接口),參數(shù)實(shí)體,返回類型.class)return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);}/*** 消費(fèi)方根據(jù)id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {// getForObject(服務(wù)提供方地址(接口),返回類型.class)return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);}/*** 消費(fèi)方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);} }通過Feign實(shí)現(xiàn):—改造后controller:DeptConsumerController.java
/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/ @RestController public class DeptConsumerController {@Autowiredprivate DeptClientService deptClientService;/*** 消費(fèi)方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {return deptClientService.addDept(dept);}/*** 消費(fèi)方根據(jù)id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {return deptClientService.queryById(id);}/*** 消費(fèi)方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return deptClientService.queryAll();} }Feign和Ribbon二者對(duì)比,前者顯現(xiàn)出面向接口編程特點(diǎn),代碼看起來更清爽,而且Feign調(diào)用方式更符合我們之前在做SSM或者SprngBoot項(xiàng)目時(shí),Controller層調(diào)用Service層的編程習(xí)慣!
主配置類:
/*** @Auther: csp1999* @Date: 2020/05/17/22:47* @Description:*/ @SpringBootApplication @EnableEurekaClient // feign客戶端注解,并指定要掃描的包以及配置接口DeptClientService @EnableFeignClients(basePackages = {"com.haust.springcloud"}) // 切記不要加這個(gè)注解,不然會(huì)出現(xiàn)404訪問不到 //@ComponentScan("com.haust.springcloud") public class FeignDeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(FeignDeptConsumer_80.class, args);} }改造springcloud-api模塊
pom.xml添加feign依賴
<!--Feign的依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><version>1.4.6.RELEASE</version> </dependency>新建service包,并新建DeptClientService.java接口,
package com.kuang.springcloud.controller;import com.kuang.springcloud.pojo.Dept;import com.kuang.springcloud.service.DeptClientService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @Auther: csp1999* @Date: 2020/05/17/22:44* @Description:*/@RestControllerpublic class DeptConsumerController {@Autowiredprivate DeptClientService deptClientService=null;/*** 消費(fèi)方添加部門信息* @param dept* @return*/@RequestMapping("/consumer/dept/add")public boolean add(Dept dept) {return deptClientService.addDept(dept);}/*** 消費(fèi)方根據(jù)id查詢部門信息* @param id* @return*/@RequestMapping("/consumer/dept/get/{id}")public Dept get(@PathVariable("id") Long id) {return deptClientService.queryById(id);}/*** 消費(fèi)方查詢部門信息列表* @return*/@RequestMapping("/consumer/dept/list")public List<Dept> list() {return deptClientService.queryAll();}}Feign VS Ribbon
根據(jù)個(gè)人習(xí)慣而定,如果喜歡REST風(fēng)格使用Ribbon;如果喜歡社區(qū)版的面向接口風(fēng)格使用Feign.
Feign 本質(zhì)上也是實(shí)現(xiàn)了 Ribbon,只不過后者是在調(diào)用方式上,為了滿足一些開發(fā)者習(xí)慣的接口調(diào)用習(xí)慣!
下面我們關(guān)閉springcloud-consumer-dept-80 這個(gè)服務(wù)消費(fèi)方,換用springcloud-consumer-dept-feign(端口還是80) 來代替:(依然可以正常訪問,就是調(diào)用方式相比于Ribbon變化了)
Hystrix
服務(wù)熔斷
分布式系統(tǒng)面臨的問題
復(fù)雜分布式體系結(jié)構(gòu)中的應(yīng)用程序有數(shù)十個(gè)依賴關(guān)系,每個(gè)依賴關(guān)系在某些時(shí)候?qū)⒉豢杀苊馐?#xff01;
服務(wù)雪崩
多個(gè)微服務(wù)之間調(diào)用的時(shí)候,假設(shè)微服務(wù)A調(diào)用微服務(wù)B和微服務(wù)C,微服務(wù)B和微服務(wù)C又調(diào)用其他的微服務(wù),這就是所謂的“扇出”,如果扇出的鏈路上某個(gè)微服務(wù)的調(diào)用響應(yīng)時(shí)間過長,或者不可用,對(duì)微服務(wù)A的調(diào)用就會(huì)占用越來越多的系統(tǒng)資源,進(jìn)而引起系統(tǒng)崩潰,所謂的“雪崩效應(yīng)”。
對(duì)于高流量的應(yīng)用來說,單一的后端依賴可能會(huì)導(dǎo)致所有服務(wù)器上的所有資源都在幾十秒內(nèi)飽和。比失敗更糟糕的是,這些應(yīng)用程序還可能導(dǎo)致服務(wù)之間的延遲增加,備份隊(duì)列,線程和其他系統(tǒng)資源緊張,導(dǎo)致整個(gè)系統(tǒng)發(fā)生更多的級(jí)聯(lián)故障,這些都表示需要對(duì)故障和延遲進(jìn)行隔離和管理,以達(dá)到單個(gè)依賴關(guān)系的失敗而不影響整個(gè)應(yīng)用程序或系統(tǒng)運(yùn)行。
我們需要,棄車保帥!
Hystrix作用
Hystrix是一個(gè)應(yīng)用于處理分布式系統(tǒng)的延遲和容錯(cuò)的開源庫,在分布式系統(tǒng)里,許多依賴不可避免的會(huì)調(diào)用失敗,比如超時(shí),異常等,Hystrix 能夠保證在一個(gè)依賴出問題的情況下,不會(huì)導(dǎo)致整個(gè)體系服務(wù)失敗,避免級(jí)聯(lián)故障,以提高分布式系統(tǒng)的彈性。
“斷路器”本身是一種開關(guān)裝置,當(dāng)某個(gè)服務(wù)單元發(fā)生故障之后,通過斷路器的故障監(jiān)控 (類似熔斷保險(xiǎn)絲) ,向調(diào)用方返回一個(gè)服務(wù)預(yù)期的,可處理的備選響應(yīng) (FallBack) ,而不是長時(shí)間的等待或者拋出調(diào)用方法無法處理的異常,這樣就可以保證了服務(wù)調(diào)用方的線程不會(huì)被長時(shí)間,不必要的占用,從而避免了故障在分布式系統(tǒng)中的蔓延,乃至雪崩。
Hystrix能干嘛?
- 服務(wù)降級(jí)
- 服務(wù)熔斷
- 服務(wù)限流
- 接近實(shí)時(shí)的監(jiān)控
- …
當(dāng)一切正常時(shí),請(qǐng)求流可以如下所示:
當(dāng)許多后端系統(tǒng)中有一個(gè)潛在阻塞服務(wù)時(shí),它可以阻止整個(gè)用戶請(qǐng)求:
隨著大容量通信量的增加,單個(gè)后端依賴項(xiàng)的潛在性會(huì)導(dǎo)致所有服務(wù)器上的所有資源在幾秒鐘內(nèi)飽和。
應(yīng)用程序中通過網(wǎng)絡(luò)或客戶端庫可能導(dǎo)致網(wǎng)絡(luò)請(qǐng)求的每個(gè)點(diǎn)都是潛在故障的來源。比失敗更糟糕的是,這些應(yīng)用程序還可能導(dǎo)致服務(wù)之間的延遲增加,從而備份隊(duì)列、線程和其他系統(tǒng)資源,從而導(dǎo)致更多跨系統(tǒng)的級(jí)聯(lián)故障。
當(dāng)使用Hystrix包裝每個(gè)基礎(chǔ)依賴項(xiàng)時(shí),上面的圖表中所示的體系結(jié)構(gòu)會(huì)發(fā)生類似于以下關(guān)系圖的變化。每個(gè)依賴項(xiàng)是相互隔離的,限制在延遲發(fā)生時(shí)它可以填充的資源中,并包含在回退邏輯中,該邏輯決定在依賴項(xiàng)中發(fā)生任何類型的故障時(shí)要做出什么樣的響應(yīng):
官網(wǎng)資料:https://github.com/Netflix/Hystrix/wiki
服務(wù)熔斷(服務(wù)端)
什么是服務(wù)熔斷?
熔斷機(jī)制是賭贏雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制。
當(dāng)扇出鏈路的某個(gè)微服務(wù)不可用或者響應(yīng)時(shí)間太長時(shí),會(huì)進(jìn)行服務(wù)的降級(jí),進(jìn)而熔斷該節(jié)點(diǎn)微服務(wù)的調(diào)用,快速返回錯(cuò)誤的響應(yīng)信息。檢測到該節(jié)點(diǎn)微服務(wù)調(diào)用響應(yīng)正常后恢復(fù)調(diào)用鏈路。在SpringCloud框架里熔斷機(jī)制通過Hystrix實(shí)現(xiàn)。Hystrix會(huì)監(jiān)控微服務(wù)間調(diào)用的狀況,當(dāng)失敗的調(diào)用到一定閥值缺省是5秒內(nèi)20次調(diào)用失敗,就會(huì)啟動(dòng)熔斷機(jī)制。熔斷機(jī)制的注解是:@HystrixCommand。
服務(wù)熔斷解決如下問題:
- 當(dāng)所依賴的對(duì)象不穩(wěn)定時(shí),能夠起到快速失敗的目的;
- 快速失敗后,能夠根據(jù)一定的算法動(dòng)態(tài)試探所依賴對(duì)象是否恢復(fù)。
案例
新建springcloud-provider-dept-hystrix-8001模塊并拷貝springcloud-provider-dept–8001內(nèi)的pom.xml、resource和Java代碼進(jìn)行初始化并調(diào)整。
導(dǎo)入hystrix依賴
<!--導(dǎo)入Hystrix依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version> </dependency>調(diào)整yml配置文件
server:port: 8001# mybatis配置 mybatis:# springcloud-api 模塊下的pojo包type-aliases-package: com.haust.springcloud.pojo# 本模塊下的mybatis-config.xml核心配置文件類路徑config-location: classpath:mybatis/mybatis-config.xml# 本模塊下的mapper配置文件類路徑mapper-locations: classpath:mybatis/mapper/*.xml# spring配置 spring:application:#項(xiàng)目名name: springcloud-provider-deptdatasource:# 德魯伊數(shù)據(jù)源type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8username: rootpassword: root# Eureka配置:配置服務(wù)注冊(cè)中心地址 eureka:client:service-url:# 注冊(cè)中心地址7001-7003defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/instance:instance-id: springcloud-provider-dept-hystrix-8001 #修改Eureka上的默認(rèn)描述信息prefer-ip-address: true #改為true后默認(rèn)顯示的是ip地址而不再是localhost#info配置 info:app.name: haust-springcloud #項(xiàng)目的名稱company.name: com.haust #公司的名稱prefer-ip-address: false:
prefer-ip-address: true:
修改controller
/*** @Auther: csp1999* @Date: 2020/05/17/22:06* @Description: 提供Restful服務(wù)*/ @RestController public class DeptController {@Autowiredprivate DeptService deptService;/*** 根據(jù)id查詢部門信息* 如果根據(jù)id查詢出現(xiàn)異常,則走h(yuǎn)ystrixGet這段備選代碼* @param id* @return*/@HystrixCommand(fallbackMethod = "hystrixGet")@RequestMapping("/dept/get/{id}")//根據(jù)id查詢public Dept get(@PathVariable("id") Long id){Dept dept = deptService.queryById(id);if (dept==null){throw new RuntimeException("這個(gè)id=>"+id+",不存在該用戶,或信息無法找到~");}return dept;}/*** 根據(jù)id查詢備選方案(熔斷)* @param id* @return*/public Dept hystrixGet(@PathVariable("id") Long id){return new Dept().setDeptno(id).setDname("這個(gè)id=>"+id+",沒有對(duì)應(yīng)的信息,null---@Hystrix~").setDb_source("在MySQL中沒有這個(gè)數(shù)據(jù)庫");} }為主啟動(dòng)類添加對(duì)熔斷的支持注解@EnableCircuitBreaker
/*** @Auther: csp1999* @Date: 2020/05/17/22:09* @Description: 啟動(dòng)類*/ @SpringBootApplication @EnableEurekaClient // EnableEurekaClient 客戶端的啟動(dòng)類,在服務(wù)啟動(dòng)后自動(dòng)向注冊(cè)中心注冊(cè)服務(wù) @EnableDiscoveryClient // 服務(wù)發(fā)現(xiàn)~ @EnableCircuitBreaker // 添加對(duì)熔斷的支持注解 public class HystrixDeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(HystrixDeptProvider_8001.class,args);} }測試:
使用熔斷后,當(dāng)訪問一個(gè)不存在的id時(shí),前臺(tái)頁展示數(shù)據(jù)如下:
而不適用熔斷的springcloud-provider-dept–8001模塊訪問相同地址會(huì)出現(xiàn)下面狀況:
因此,為了避免因某個(gè)微服務(wù)后臺(tái)出現(xiàn)異常或錯(cuò)誤而導(dǎo)致整個(gè)應(yīng)用或網(wǎng)頁報(bào)錯(cuò),使用熔斷是必要的
顯示服務(wù)的ip
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-POuM4oTq-1610725250931)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115162939925.png)]
服務(wù)降級(jí)(客戶端)
什么是服務(wù)降級(jí)?
服務(wù)降級(jí)是指 當(dāng)服務(wù)器壓力劇增的情況下,根據(jù)實(shí)際業(yè)務(wù)情況及流量,對(duì)一些服務(wù)和頁面有策略的不處理,或換種簡單的方式處理,從而釋放服務(wù)器資源以保證核心業(yè)務(wù)正常運(yùn)作或高效運(yùn)作。說白了,就是盡可能的把系統(tǒng)資源讓給優(yōu)先級(jí)高的服務(wù)。
資源有限,而請(qǐng)求是無限的。如果在并發(fā)高峰期,不做服務(wù)降級(jí)處理,一方面肯定會(huì)影響整體服務(wù)的性能,嚴(yán)重的話可能會(huì)導(dǎo)致宕機(jī)某些重要的服務(wù)不可用。所以,一般在高峰期,為了保證核心功能服務(wù)的可用性,都要對(duì)某些服務(wù)降級(jí)處理。比如當(dāng)雙11活動(dòng)時(shí),把交易無關(guān)的服務(wù)統(tǒng)統(tǒng)降級(jí),如查看螞蟻深林,查看歷史訂單等等。
服務(wù)降級(jí)主要用于什么場景呢?當(dāng)整個(gè)微服務(wù)架構(gòu)整體的負(fù)載超出了預(yù)設(shè)的上限閾值或即將到來的流量預(yù)計(jì)將會(huì)超過預(yù)設(shè)的閾值時(shí),為了保證重要或基本的服務(wù)能正常運(yùn)行,可以將一些 不重要 或 不緊急 的服務(wù)或任務(wù)進(jìn)行服務(wù)的 延遲使用 或 暫停使用。
降級(jí)的方式可以根據(jù)業(yè)務(wù)來,可以延遲服務(wù),比如延遲給用戶增加積分,只是放到一個(gè)緩存中,等服務(wù)平穩(wěn)之后再執(zhí)行 ;或者在粒度范圍內(nèi)關(guān)閉服務(wù),比如關(guān)閉相關(guān)文章的推薦。
由上圖可得,當(dāng)某一時(shí)間內(nèi)服務(wù)A的訪問量暴增,而B和C的訪問量較少,為了緩解A服務(wù)的壓力,這時(shí)候需要B和C暫時(shí)關(guān)閉一些服務(wù)功能,去承擔(dān)A的部分服務(wù),從而為A分擔(dān)壓力,叫做服務(wù)降級(jí)。
服務(wù)降級(jí)需要考慮的問題
- 1)那些服務(wù)是核心服務(wù),哪些服務(wù)是非核心服務(wù)
- 2)那些服務(wù)可以支持降級(jí),那些服務(wù)不能支持降級(jí),降級(jí)策略是什么
- 3)除服務(wù)降級(jí)之外是否存在更復(fù)雜的業(yè)務(wù)放通場景,策略是什么?
自動(dòng)降級(jí)分類
1)超時(shí)降級(jí):主要配置好超時(shí)時(shí)間和超時(shí)重試次數(shù)和機(jī)制,并使用異步機(jī)制探測回復(fù)情況
2)失敗次數(shù)降級(jí):主要是一些不穩(wěn)定的api,當(dāng)失敗調(diào)用次數(shù)達(dá)到一定閥值自動(dòng)降級(jí),同樣要使用異步機(jī)制探測回復(fù)情況
3)故障降級(jí):比如要調(diào)用的遠(yuǎn)程服務(wù)掛掉了(網(wǎng)絡(luò)故障、DNS故障、http服務(wù)返回錯(cuò)誤的狀態(tài)碼、rpc服務(wù)拋出異常),則可以直接降級(jí)。降級(jí)后的處理方案有:默認(rèn)值(比如庫存服務(wù)掛了,返回默認(rèn)現(xiàn)貨)、兜底數(shù)據(jù)(比如廣告掛了,返回提前準(zhǔn)備好的一些靜態(tài)頁面)、緩存(之前暫存的一些緩存數(shù)據(jù))
4)限流降級(jí):秒殺或者搶購一些限購商品時(shí),此時(shí)可能會(huì)因?yàn)樵L問量太大而導(dǎo)致系統(tǒng)崩潰,此時(shí)會(huì)使用限流來進(jìn)行限制訪問量,當(dāng)達(dá)到限流閥值,后續(xù)請(qǐng)求會(huì)被降級(jí);降級(jí)后的處理方案可以是:排隊(duì)頁面(將用戶導(dǎo)流到排隊(duì)頁面等一會(huì)重試)、無貨(直接告知用戶沒貨了)、錯(cuò)誤頁(如活動(dòng)太火爆了,稍后重試)。
入門案例
在springcloud-api模塊下的service包中新建降級(jí)配置類DeptClientServiceFallBackFactory.java
/*** @Auther: csp1999* @Date: 2020/05/20/9:18* @Description: Hystrix服務(wù)降級(jí) ~*/ @Component public class DeptClientServiceFallBackFactory implements FallbackFactory {@Overridepublic DeptClientService create(Throwable cause) {return new DeptClientService() {@Overridepublic Dept queryById(Long id) {return new Dept().setDeptno(id).setDname("id=>" + id + "沒有對(duì)應(yīng)的信息,客戶端提供了降級(jí)的信息,這個(gè)服務(wù)現(xiàn)在已經(jīng)被關(guān)閉").setDb_source("沒有數(shù)據(jù)~");}@Overridepublic List<Dept> queryAll() {return null;}@Overridepublic Boolean addDept(Dept dept) {return false;}};} }在DeptClientService中指定降級(jí)配置類DeptClientServiceFallBackFactory
@Component //注冊(cè)到spring容器中 //@FeignClient:微服務(wù)客戶端注解,value:指定微服務(wù)的名字,這樣就可以使Feign客戶端直接找到對(duì)應(yīng)的微服務(wù) @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//fallbackFactory指定降級(jí)配置類 public interface DeptClientService {@GetMapping("/dept/get/{id}")public Dept queryById(@PathVariable("id") Long id);@GetMapping("/dept/list")public List<Dept> queryAll();@GetMapping("/dept/add")public Boolean addDept(Dept dept); }在springcloud-consumer-dept-feign模塊中開啟降級(jí):
server:port: 80# Eureka配置 eureka:client:register-with-eureka: false # 不向 Eureka注冊(cè)自己service-url: # 從三個(gè)注冊(cè)中心中隨機(jī)取一個(gè)去訪問defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/# 開啟降級(jí)feign.hystrix feign:hystrix:enabled: true服務(wù)熔斷VS降級(jí)VS限流
- 服務(wù)熔斷—>服務(wù)端:某個(gè)服務(wù)超時(shí)或異常,引起熔斷~,類似于保險(xiǎn)絲(自我熔斷)
- 服務(wù)降級(jí)—>客戶端:從整體網(wǎng)站請(qǐng)求負(fù)載考慮,當(dāng)某個(gè)服務(wù)熔斷或者關(guān)閉之后,服務(wù)將不再被調(diào)用,此時(shí)在客戶端,我們可以準(zhǔn)備一個(gè) FallBackFactory ,返回一個(gè)默認(rèn)的值(缺省值)。會(huì)導(dǎo)致整體的服務(wù)下降,但是好歹能用,比直接掛掉強(qiáng)。
- 觸發(fā)原因不太一樣,服務(wù)熔斷一般是某個(gè)服務(wù)(下游服務(wù))故障引起,而服務(wù)降級(jí)一般是從整體負(fù)荷考慮;管理目標(biāo)的層次不太一樣,熔斷其實(shí)是一個(gè)框架級(jí)的處理,每個(gè)微服務(wù)都需要(無層級(jí)之分),而降級(jí)一般需要對(duì)業(yè)務(wù)有層級(jí)之分(比如降級(jí)一般是從最外圍服務(wù)開始)
- 實(shí)現(xiàn)方式不太一樣,服務(wù)降級(jí)具有代碼侵入性(由控制器完成/或自動(dòng)降級(jí)),熔斷一般稱為自我熔斷。
熔斷,降級(jí),限流:
限流:限制并發(fā)的請(qǐng)求訪問量,超過閾值則拒絕;
降級(jí):服務(wù)分優(yōu)先級(jí),犧牲非核心服務(wù)(不可用),保證核心服務(wù)穩(wěn)定;從整體負(fù)荷考慮;
熔斷:依賴的下游服務(wù)故障觸發(fā)熔斷,避免引發(fā)本系統(tǒng)崩潰;系統(tǒng)自動(dòng)執(zhí)行和恢復(fù)
Dashboard 流監(jiān)控
新建springcloud-consumer-hystrix-dashboard模塊
添加依賴
<!--Hystrix依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--dashboard依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix-dashboard</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--Ribbon--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--Eureka--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version> </dependency> <!--實(shí)體類+web--> <dependency><groupId>com.haust</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>主啟動(dòng)類
@SpringBootApplication // 開啟Dashboard @EnableHystrixDashboard public class DeptConsumerDashboard_9001 {public static void main(String[] args) {SpringApplication.run(DeptConsumerDashboard_9001.class,args);} }給springcloud-provider-dept-hystrix-8001模塊下的主啟動(dòng)類添加如下代碼,添加監(jiān)控
@SpringBootApplication @EnableEurekaClient //EnableEurekaClient 客戶端的啟動(dòng)類,在服務(wù)啟動(dòng)后自動(dòng)向注冊(cè)中心注冊(cè)服務(wù) public class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);}//增加一個(gè) Servlet@Beanpublic ServletRegistrationBean hystrixMetricsStreamServlet(){ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());//訪問該頁面就是監(jiān)控頁面registrationBean.addUrlMappings("/actuator/hystrix.stream");return registrationBean;} }訪問:http://localhost:9001/hystrix
進(jìn)入監(jiān)控頁面:
效果如下圖:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-6Lrufp0x-1610725250932)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190406423.png)]
一些問題解決辦法
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-fz0nuLpz-1610725250934)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190154045.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-ifS1YBTP-1610725250939)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190205062.png)]
Zull路由網(wǎng)關(guān)
概述
什么是zuul?
Zull包含了對(duì)請(qǐng)求的路由(用來跳轉(zhuǎn)的)和過濾兩個(gè)最主要功能:
其中路由功能負(fù)責(zé)將外部請(qǐng)求轉(zhuǎn)發(fā)到具體的微服務(wù)實(shí)例上,是實(shí)現(xiàn)外部訪問統(tǒng)一入口的基礎(chǔ),而過濾器功能則負(fù)責(zé)對(duì)請(qǐng)求的處理過程進(jìn)行干預(yù),是實(shí)現(xiàn)請(qǐng)求校驗(yàn),服務(wù)聚合等功能的基礎(chǔ)。Zuul和Eureka進(jìn)行整合,將Zuul自身注冊(cè)為Eureka服務(wù)治理下的應(yīng)用,同時(shí)從Eureka中獲得其他服務(wù)的消息,也即以后的訪問微服務(wù)都是通過Zuul跳轉(zhuǎn)后獲得。
注意:Zuul 服務(wù)最終還是會(huì)注冊(cè)進(jìn) Eureka
提供:代理 + 路由 + 過濾 三大功能!
Zuul 能干嘛?
- 路由
- 過濾
官方文檔:https://github.com/Netflix/zuul/
入門案例
新建springcloud-zuul模塊,并導(dǎo)入依賴
<dependencies><!--導(dǎo)入zuul依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zuul</artifactId><version>1.4.6.RELEASE</version></dependency><!--Hystrix依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version></dependency><!--dashboard依賴--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix-dashboar</artifactId><version>1.4.6.RELEASE</version></dependency><!--Ribbon--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId><version>1.4.6.RELEASE</version></dependency><!--Eureka--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version></dependency><!--實(shí)體類+web--><dependency><groupId>com.haust</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>application.yml
server:port: 9527spring:application:name: springcloud-zuul #微服務(wù)名稱# eureka 注冊(cè)中心配置 eureka:client:service-url:defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/instance: #實(shí)例的idinstance-id: zuul9527.comprefer-ip-address: true # 顯示ipinfo:app.name: haust.springcloud # 項(xiàng)目名稱company.name: 河南科技大學(xué)西苑校區(qū) # 公司名稱# zull 路由網(wǎng)關(guān)配置 zuul:# 路由相關(guān)配置# 原來訪問路由 eg:http://www.cspStudy.com:9527/springcloud-provider-dept/dept/get/1# zull路由配置后訪問路由 eg:http://www.cspstudy.com:9527/haust/mydept/dept/get/1routes:mydept.serviceId: springcloud-provider-dept # eureka注冊(cè)中心的服務(wù)提供方路由名稱mydept.path: /mydept/** # 將eureka注冊(cè)中心的服務(wù)提供方路由名稱 改為自定義路由名稱# 不能再使用這個(gè)路徑訪問了,*: 忽略,隱藏全部的服務(wù)名稱~ignored-services: "*"# 設(shè)置公共的前綴prefix: /haust主啟動(dòng)類
/*** @Auther: csp1999* @Date: 2020/05/20/20:53* @Description: Zull路由網(wǎng)關(guān)主啟動(dòng)類*/ @SpringBootApplication @EnableZuulProxy // 開啟Zuul public class ZuulApplication_9527 {public static void main(String[] args) {SpringApplication.run(ZuulApplication_9527.class,args);} }測試:
可以看出Zull路由網(wǎng)關(guān)被注冊(cè)到Eureka注冊(cè)中心中了!
上圖是沒有經(jīng)過Zull路由網(wǎng)關(guān)配置時(shí),服務(wù)接口訪問的路由,可以看出直接用微服務(wù)(服務(wù)提供方)名稱去訪問,這樣不安全,不能將微服務(wù)名稱暴露!
所以經(jīng)過Zull路由網(wǎng)關(guān)配置后,訪問的路由為:
我們看到,微服務(wù)名稱被替換并隱藏,換成了我們自定義的微服務(wù)名稱mydept,同時(shí)加上了前綴haust,這樣就做到了對(duì)路由fan訪問的加密處理!
詳情參考springcloud中文社區(qū)zuul組件 :https://www.springcloud.cc/spring-cloud-greenwich.html#_router_and_filter_zuul
SpringCloud Config 分布式配置
Dalston.RELEASE
Spring Cloud Config為分布式系統(tǒng)中的外部配置提供服務(wù)器和客戶端支持。使用Config Server,您可以在所有環(huán)境中管理應(yīng)用程序的外部屬性。客戶端和服務(wù)器上的概念映射與Spring Environment和PropertySource抽象相同,因此它們與Spring應(yīng)用程序非常契合,但可以與任何以任何語言運(yùn)行的應(yīng)用程序一起使用。隨著應(yīng)用程序通過從開發(fā)人員到測試和生產(chǎn)的部署流程,您可以管理這些環(huán)境之間的配置,并確定應(yīng)用程序具有遷移時(shí)需要運(yùn)行的一切。服務(wù)器存儲(chǔ)后端的默認(rèn)實(shí)現(xiàn)使用git,因此它輕松支持標(biāo)簽版本的配置環(huán)境,以及可以訪問用于管理內(nèi)容的各種工具。很容易添加替代實(shí)現(xiàn),并使用Spring配置將其插入。
概述
分布式系統(tǒng)面臨的–配置文件問題
微服務(wù)意味著要將單體應(yīng)用中的業(yè)務(wù)拆分成一個(gè)個(gè)子服務(wù),每個(gè)服務(wù)的粒度相對(duì)較小,因此系統(tǒng)中會(huì)出現(xiàn)大量的服務(wù),由于每個(gè)服務(wù)都需要必要的配置信息才能運(yùn)行,所以一套集中式的,動(dòng)態(tài)的配置管理設(shè)施是必不可少的。spring cloud提供了configServer來解決這個(gè)問題,我們每一個(gè)微服務(wù)自己帶著一個(gè)application.yml,那上百個(gè)的配置文件修改起來,令人頭疼!
什么是SpringCloud config分布式配置中心?
spring cloud config 為微服務(wù)架構(gòu)中的微服務(wù)提供集中化的外部支持,配置服務(wù)器為各個(gè)不同微服務(wù)應(yīng)用的所有環(huán)節(jié)提供了一個(gè)中心化的外部配置。
spring cloud config 分為服務(wù)端和客戶端兩部分。
服務(wù)端也稱為 分布式配置中心,它是一個(gè)獨(dú)立的微服務(wù)應(yīng)用,用來連接配置服務(wù)器并為客戶端提供獲取配置信息,加密,解密信息等訪問接口。
客戶端則是通過指定的配置中心來管理應(yīng)用資源,以及與業(yè)務(wù)相關(guān)的配置內(nèi)容,并在啟動(dòng)的時(shí)候從配置中心獲取和加載配置信息。配置服務(wù)器默認(rèn)采用git來存儲(chǔ)配置信息,這樣就有助于對(duì)環(huán)境配置進(jìn)行版本管理。并且可用通過git客戶端工具來方便的管理和訪問配置內(nèi)容。
spring cloud config 分布式配置中心能干嘛?
- 集中式管理配置文件
- 不同環(huán)境,不同配置,動(dòng)態(tài)化的配置更新,分環(huán)境部署,比如 /dev /test /prod /beta /release
- 運(yùn)行期間動(dòng)態(tài)調(diào)整配置,不再需要在每個(gè)服務(wù)部署的機(jī)器上編寫配置文件,服務(wù)會(huì)向配置中心統(tǒng)一拉取配置自己的信息
- 當(dāng)配置發(fā)生變動(dòng)時(shí),服務(wù)不需要重啟,即可感知到配置的變化,并應(yīng)用新的配置
- 將配置信息以REST接口的形式暴露
與GitHub整合
新建倉庫
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-Bhz1F83t-1610725250942)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115201322508.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-LE7yvLGo-1610725250943)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115201720254.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-BDYARVKc-1610725250944)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115201835756.png)]
下載遠(yuǎn)程代碼
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-CFHdAOxD-1610725250945)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115203431941.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-TsRQNrCr-1610725250946)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115203520367.png)]
對(duì)git進(jìn)行配置
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-pRrLqu6I-1610725250946)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115203746644.png)]
生成公鑰
此文件夾下
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-Z1QfZuVv-1610725250947)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115205541149.png)]
ssh-keygen -t rsa -C “2764954910@qq.com”
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-fY2YDC6L-1610725250949)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115205752053.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-mJltkGjK-1610725250950)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115205742128.png)]
上傳代碼、
先下載再提交,對(duì)應(yīng)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-XrlSWZgt-1610725250951)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115211052522.png)]
由于spring cloud config 默認(rèn)使用git來存儲(chǔ)配置文件 (也有其他方式,比如自持SVN 和本地文件),但是最推薦的還是git ,而且使用的是 http / https 訪問的形式。
服務(wù)端
前提yml寫對(duì)否則會(huì)報(bào)錯(cuò)
新建springcloud-config-server-3344模塊導(dǎo)入pom.xml依賴
<dependencies><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--config--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId><version>2.1.1.RELEASE</version></dependency><!--eureka--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version></dependency> </dependencies>resource下創(chuàng)建application.yml配置文件,Spring Cloud Config服務(wù)器從git存儲(chǔ)庫(必須提供)為遠(yuǎn)程客戶端提供配置:
server:port: 3344spring:application:name: springcloud-config-server# 連接碼云遠(yuǎn)程倉庫cloud:config:server:git:# 注意是https的而不是sshuri: https://gitee.com/wdlyb/springcloud-config.git# 通過 config-server可以連接到git,訪問其中的資源以及配置~# 不加這個(gè)配置會(huì)報(bào)Cannot execute request on any known server 這個(gè)錯(cuò):連接Eureka服務(wù)端地址不對(duì) # 或者直接注釋掉eureka依賴 這里暫時(shí)用不到eureka eureka:client:register-with-eureka: falsefetch-registry: false主啟動(dòng)類
@EnableConfigServer // 開啟spring cloud config server服務(wù) @SpringBootApplication public class Config_server_3344 {public static void main(String[] args) {SpringApplication.run(Config_server_3344.class,args);} }將本地git倉庫springcloud-config文件夾下新建的application.yml提交到碼云倉庫:
定位資源的默認(rèn)策略是克隆一個(gè)git倉庫(在spring.cloud.config.server.git.uri),并使用它來初始化一個(gè)迷你SpringApplication。小應(yīng)用程序的Environment用于枚舉屬性源并通過JSON端點(diǎn)發(fā)布。
HTTP服務(wù)具有以下格式的資源:
/{application}/{profile}[/{label}] /{application}-{profile}.yml /{label}/{application}-{profile}.yml /{application}-{profile}.properties /{label}/{application}-{profile}.properties其中“應(yīng)用程序”作為SpringApplication中的spring.config.name注入(即常規(guī)的Spring Boot應(yīng)用程序中通常是“應(yīng)用程序”),“配置文件”是活動(dòng)配置文件(或逗號(hào)分隔列表的屬性),“l(fā)abel”是可選的git標(biāo)簽(默認(rèn)為“master”)。
測試訪問http://localhost:3344/application-dev.yml
測試訪問 http://localhost:3344/application/test/master
測試訪問 http://localhost:3344/master/application-dev.yml
如果測試訪問不存在的配置則不顯示 如:http://localhost:3344/master/application-aaa.yml
客戶端
將本地git倉庫springcloud-config文件夾下新建的config-client.yml提交到碼云倉庫:
新建一個(gè)springcloud-config-client-3355模塊,并導(dǎo)入依賴
<!--config--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-start --> <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>resources下創(chuàng)建application.yml和bootstrap.yml配置文件
bootstrap.yml 是系統(tǒng)級(jí)別的配置
# 系統(tǒng)級(jí)別的配置 spring:cloud:config:name: config-client # 需要從git上讀取的資源名稱,不要后綴profile: devlabel: masteruri: http://localhost:3344application.yml 是用戶級(jí)別的配置
# 用戶級(jí)別的配置 spring:application:name: springcloud-config-client創(chuàng)建controller包下的ConfigClientController.java 用于測試
@RestController public class ConfigClientController {@Value("${spring.application.name}")private String applicationName; //獲取微服務(wù)名稱@Value("${eureka.client.service-url.defaultZone}")private String eurekaServer; //獲取Eureka服務(wù)@Value("${server.port}")private String port; //獲取服務(wù)端的端口號(hào)@RequestMapping("/config")public String getConfig(){return "applicationName:"+applicationName +"eurekaServer:"+eurekaServer +"port:"+port;} }主啟動(dòng)類
@SpringBootApplication public class ConfigClient {public static void main(String[] args) {SpringApplication.run(ConfigClient.class,args);} }測試:
啟動(dòng)服務(wù)端Config_server_3344 再啟動(dòng)客戶端ConfigClient
訪問:http://localhost:8201/config/
小案例
本地新建config-dept.yml和config-eureka.yml并提交到碼云倉庫
這里配置文件內(nèi)容不再列舉直接到代碼中看把。
新建springcloud-config-eureka-7001模塊,并將原來的springcloud-eureka-7001模塊下的內(nèi)容拷貝的該模塊。
1.清空該模塊的application.yml配置,并新建bootstrap.yml連接遠(yuǎn)程配置
spring:cloud:config:name: config-eureka # 倉庫中的配置文件名稱label: masterprofile: devuri: http://localhost:33442.在pom.xml中添加spring cloud config依賴
<!--config--> <!-- 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>3.主啟動(dòng)類
@SpringBootApplication @EnableEurekaServer //EnableEurekaServer 服務(wù)端的啟動(dòng)類,可以接受別人注冊(cè)進(jìn)來~ public class ConfigEurekaServer_7001 {public static void main(String[] args) {SpringApplication.run(ConfigEurekaServer_7001.class,args);} }4.測試
第一步:啟動(dòng) Config_Server_3344,并訪問 http://localhost:3344/master/config-eureka-dev.yml 測試
第二部:啟動(dòng)ConfigEurekaServer_7001,訪問 http://localhost:7001/ 測試
顯示上圖則成功
新建springcloud-config-dept-8001模塊并拷貝springcloud-provider-dept-8001的內(nèi)容
同理導(dǎo)入spring cloud config依賴、清空application.yml 、新建bootstrap.yml配置文件并配置
spring:cloud:config:name: config-deptlabel: masterprofile: devuri: http://localhost:3344主啟動(dòng)類
@SpringBootApplication @EnableEurekaClient //在服務(wù)啟動(dòng)后自動(dòng)注冊(cè)到Eureka中! @EnableDiscoveryClient //服務(wù)發(fā)現(xiàn)~ @EnableCircuitBreaker // public class ConfigDeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(ConfigDeptProvider_8001.class,args);}//增加一個(gè) Servlet@Beanpublic ServletRegistrationBean hystrixMetricsStreamServlet(){ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());registrationBean.addUrlMappings("/actuator/hystrix.stream");return registrationBean;} }[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-EFNYsTnO-1610725250953)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115233434134.png)]
總結(jié)
以上是生活随笔為你收集整理的SpringCloud(笔记)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 温州绕城高速出口设置(温州绕城高速公路)
- 下一篇: gradle idea java ssm