1、簡介

springcloud 是微服務(wù)開發(fā)組件集合。

微服務(wù):mirco-service
小服務(wù),一般情況把整個項目劃分多個小模塊,針對每個小模塊建立獨立的工程,有獨立的數(shù)據(jù)庫,能夠提供獨立的服務(wù)
微服務(wù)開發(fā)過程遇到最基本的問題:
1、服務(wù)發(fā)現(xiàn)與注冊問題 【Eureka、 Consul、 Nacos】
2、服務(wù)調(diào)用問題 【Ribbon 、 Feign】
3、服務(wù)集中配置問題 【SpringCloud config 結(jié)合 git】
4、服務(wù)保護(hù)問題 【Hystrix】
5、服務(wù)的網(wǎng)關(guān)問題 【Zuul SpringCloud gateway】
初識springcloud
1、springcloud : 整合市場所有知名企業(yè)微服務(wù)框架,匯聚在一起!定位集合。
2、版本問題:SpringCloud底層需要依賴springboot構(gòu)建因此,注意本次:Greenwich ---> 要求springboot版本 2.1.X
3、注意:一般微服務(wù)開發(fā):
1、基于apache dubbo
2、基于springcloud
3、基于k8s (技術(shù)難度大,運維復(fù)雜,綁定,國內(nèi)目前不太流行)
4、dubbo和springcloud 區(qū)別:
性能:dubbo優(yōu)于springcloud
底層通信協(xié)議:(dubbo RPC 、 springcloud HTTP)
dubbo是基于更為底層通信協(xié)議,封包和拆包的效率高
springcloud基于應(yīng)用層通信協(xié)議,封包和拆包效率低
功能:springcloud功能更加完善

2、服務(wù)注冊中心組件
組件: 能夠單獨完成某一項功能的一個軟件或者框架。

兩項最基本功能:
服務(wù)注冊
服務(wù)發(fā)現(xiàn)
1.1、eureka組件
基本架構(gòu): C/S 架構(gòu) (client 和 server) Java中很多c/s 依賴方式。

1.1.1 創(chuàng)建一個服務(wù)提供方工程 (一個微服務(wù))
提供根據(jù)商品id查詢商品功能 --- 接口:
①接口Java程序員的眼中interface關(guān)鍵字,
②前端或者測試眼中接口 http://localhost:8080/goods/1
第一步:引入依賴
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring cloud client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
第二步: 編寫配置文件 application.yml
server:
port: 8000
eureka:
instance:
hostname: localhost #主機(jī)名
prefer-ip-address: true #使用IP注冊到eureka
ip-address: 127.0.0.1 #設(shè)置當(dāng)前的實例IP
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} #eureka控制臺中顯示的實例ID
lease-renewal-interval-in-seconds: 3 # 每隔3秒發(fā)一次心跳包,默認(rèn)30秒
lease-expiration-duration-in-seconds: 9 # 如果9秒內(nèi)沒有發(fā)心跳包,就會被服務(wù)器干掉,默認(rèn)90秒
client:
service-url:
defaultZone: http://localhost:8761/eureka #eureka服務(wù)端地址,將來客戶端使用該地址和eureka進(jìn)行通信
spring:
application:
name: eureka-provider #設(shè)置當(dāng)前應(yīng)用的名稱:
# 1.將來會在eureka管理平臺的Application中顯示
# 2.將來需要使用該名稱來獲取路徑
第三步: 編寫相關(guān)邏輯代碼
//引導(dǎo)類
package com.itheima.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //開啟eureka客戶端
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
//實體類
public class Goods {
private int id;
private String title;//商品標(biāo)題
private double price;//商品價格
private int count;//商品庫存
public Goods() {
}
public Goods(int id, String title, double price, int count) {
this.id = id;
this.title = title;
this.price = price;
this.count = count;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
//dao層
package com.itheima.provider.dao;
import com.itheima.provider.domain.Goods;
import org.springframework.stereotype.Repository;
@Repository
public class GoodsDao {
public Goods fingById(int id){
return new Goods(1,"華為手機(jī)",399,10000);
}
}
//service層
package com.itheima.provider.service;
import com.itheima.provider.dao.GoodsDao;
import com.itheima.provider.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GoodsService {
@Autowired
private GoodsDao goodsDao;
public Goods findOne(int id){
return goodsDao.fingById(id);
}
}
//controller層
package com.itheima.provider.contrller;
import com.itheima.provider.domain.Goods;
import com.itheima.provider.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/findOne/{id}")
public Goods findOne(@PathVariable("id") int id){
Goods goods = goodsService.findOne(id);
return goods;
}
}
1.1.2 創(chuàng)建一個消費者工程(一個微服務(wù)),只需要調(diào)用 生產(chǎn)者工程 提供好的這個接口!
第一步:導(dǎo)入依賴同生產(chǎn)者
第二步:編寫配置文件
server:
port: 9000
eureka:
instance:
hostname: localhost #主機(jī)名
client:
service-url:
defaultZone: http://localhost:8761/eureka #eureka服務(wù)端地址,將來客戶端使用該地址和eureka進(jìn)行通信
spring:
application:
name: eureka-consume
//引導(dǎo)類
package com.itheima.consumer;
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
@EnableDiscoveryClient # 開啟
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
第三步:實體類與生產(chǎn)者一致
第四步: 編寫 RestTemplate 配置類
服務(wù)調(diào)用 : RestTemplate 底部封裝HTTP
package com.itheima.consumer.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
第五步: 編寫控制層
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
//根據(jù)服務(wù)名稱獲取服務(wù)路徑集合
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//對路徑做作健壯性判斷
if (instances == null || instances.size() ==0){
return null;
}
//因為當(dāng)下只有一個,所以索引為0 直接獲取路徑
ServiceInstance instance = instances.get(0);
URI uri = instance.getUri();
//遠(yuǎn)程調(diào)用Goods服務(wù)中的 findOne() 接口
/**
* 1. 定義Bean restTemplate
* 2. 注入Bean
* 3. 使用方法
*/
String url = uri+"/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
1.1.3 創(chuàng)建eureka服務(wù)端:
第一步: 導(dǎo)入依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
第二步: 配置文件 application.yam
server:
port: 8761
eureka:
instance:
hostname: localhost #主機(jī)名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #eureka服務(wù)端地址,將來客戶端使用該地址和eureka進(jìn)行通信
register-with-eureka: false #默認(rèn)為true,是否將自己的地址注冊到eureka上 集群時需要 provider client也需要
fetch-registry: false #是否需要從eureka中抓取路徑, consumer client 需要
server:
enable-self-preservation: false # 關(guān)閉自我保護(hù)機(jī)制
eviction-interval-timer-in-ms: 3000 # 檢查服務(wù)的時間間隔位3秒,默認(rèn)60秒
第三步: 引導(dǎo)類
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
eureka配置分為4個部分:
1. dashboard : eureka的web控制臺配置
2. server: eureka 的服務(wù)端配置
3. client: eureka的客戶端配置
4. instance: eureka的實例配置
server中自我保護(hù)機(jī)制,默認(rèn)就是開啟的 (了解)
eureka:
instance:
lease-renewal-interval-in-seconds: 3 # 每隔3秒發(fā)一次心跳包,默認(rèn)30秒
lease-expiration-duration-in-seconds: 9 # 如果9秒內(nèi)沒有發(fā)心跳包,就會被服務(wù)器干掉,默認(rèn)90秒
server:
enable-self-preservation: false # 關(guān)閉自我保護(hù)機(jī)制
eviction-interval-timer-in-ms: 3000 # 檢查服務(wù)的時間間隔位3秒,默認(rèn)60秒
1.1.4搭建server服務(wù)集群:
①在 C:\Windows\System32\drivers\etc 中有一個hosts文件,
需要分別綁定集群中成員的主機(jī)名與IP: 127.0.0.1 eureka-server1
②下面以其中一個配置文件為例: application.yam
server:
port: 8761
eureka:
instance:
hostname: eureka-server1 #主機(jī)名
client:
service-url:
defaultZone: http://eureka-server2:8762/eureka #集群這里是相互搭建
register-with-eureka: true #默認(rèn)為true,是否將自己的地址注冊到eureka上
fetch-registry: true #是否需要從eureka中抓取路徑
spring:
application:
name: eureka-server-ha #這里同一集群內(nèi)的每個name最好一致
高可用

1.準(zhǔn)備兩個Eureka Server
2.分別進(jìn)行配置,相互注冊
3.Eureka Client分別注冊到這兩個Eureka Server中
1.2、consul組件
- Consul是由HashiCorp基于Go語言開發(fā)的, 支持多數(shù)據(jù)中心, 分布式高可用的服務(wù)發(fā)布和注冊服務(wù)軟件。
- 用于實現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置。
- 使用起來也較為簡單。具有天然可移植性(支持Linux、windows和MacOSX) ; 安裝包僅包含一個可執(zhí)行文件,方便部署。
官網(wǎng)地址: https://www.consul.io
開啟方式:
1. 直接解壓到E盤的software文件夾,按住shift+右鍵,選擇 在此處打開Powersholl窗口
2. 輸入開發(fā)模式命令: .\consul agent -dev (.\consul可以不加尾綴.exe,也可以加上。-dev開發(fā)者模式不會持久化任何數(shù)據(jù))
3. 管理控制臺地址: http://localhost:8500/ui/dc1/services

1.搭建Provider和Consumer服務(wù)。
2.使用RestTemplate完成遠(yuǎn)程調(diào)用。
3.將Provider服務(wù)注冊到Consul中。
4.Consumer服務(wù)通過從Consul中抓取Provider地址完成遠(yuǎn)程調(diào)用
1.2.1 服務(wù)提供方
需要依賴 pom.xml
<dependencies>
<!--consul 客戶端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--服務(wù)監(jiān)控用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
配置文件 application.yml
server:
port: 8000
spring:
cloud:
consul:
host: localhost # consul 服務(wù)端的 ip
port: 8500 # consul 服務(wù)端的端口 默認(rèn)8500
discovery:
service-name: ${spring.application.name} # 當(dāng)前應(yīng)用注冊到consul的名稱
prefer-ip-address: true # 注冊ip
application:
name: consul-provider # 應(yīng)用名稱
1.2.2 服務(wù)消費方
這里注意下開啟 @EnableDiscoveryClient : 可以獲取服務(wù)信息
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsulConsumerApp.class,args);
}
}
1.3、nacos組件
- Nacos(Dynamic Naming and Configuration Service) 是阿里巴巴2018年7月開源的項目。
- 它專注于服務(wù)發(fā)現(xiàn)和配置管理領(lǐng)域致力于幫助您發(fā)現(xiàn)、配置和管理微服務(wù)。Na cos支持幾乎所有主流類型的“服務(wù)”的發(fā)現(xiàn)、配置和管理。
- 一句話概括就是Nacos=SpringCloud注冊中心+SpringCloud配置中心。
官網(wǎng):https://nacos.io/
下載地址:https://github.com/alibaba/nacos/releases
本地起來后訪問網(wǎng)址: http://localhost:8848/nacos
用戶名: nacos 密碼: nacos
開啟nacos服務(wù): E:\software\nacos\bin startup.cmd
1.3.1 需要依賴
<dependencies>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies><dependencies>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
配置文件
server:
port: 8000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服務(wù)端地址
application:
name: nacos-provider # 服務(wù)名稱
3、Ribbon客戶端負(fù)載均衡
Ribbon是Netflix提供的一個基于HTTP和TCP的 客戶端 負(fù)載均衡工具。
Ribbon主要有兩個功能:1.簡化遠(yuǎn)程調(diào)用 2.負(fù)載均衡
服務(wù)端負(fù)載均衡
- 負(fù)載均衡算法在服務(wù)端
- 由負(fù)載均衡器維護(hù)服務(wù)地址列表

客戶端負(fù)載均衡
負(fù)載均衡算法在客戶端
客戶端維護(hù)服務(wù)地址列表


@Configuration
public class RestTemplateConfig{
@LoadBalance
@Bean
public RestTemplate restTemplate() { return new RestTemplate() ;}
}
/**
*使用Ribbon簡化rest Template調(diào)用
*1.在聲明rest TempLate的Bean時候, 添加一個注解:@LoadBalanced
*2.在使用rest TempLate發(fā)起請求時, 需要定義url時,host:port可以替換為, 服務(wù)提供方的應(yīng)用名稱
*@param id
*@return
*/
@Get Mapping(“/goods 2/{id} “)
public Goods findGoodsById2(@PathVariable(“id") int id) {
String url=“http://EUREKA-PROVIDER/goods/findOne/“+id;
//3.調(diào)用方法
Goods goods = restTemplate.getForObject(url, Goods.class) ;
return goods;
}
服務(wù)調(diào)用:
① RestTemplate 發(fā)送請求
② DiscoveryClient 從eureka中獲取服務(wù)ip和端口
③ Ribbon 負(fù)載均衡 按照規(guī)則選取一個來調(diào)用
Ribbon負(fù)責(zé)均衡策略:
隨機(jī):RandomRule
輪詢:RoundRobinRule
最小并發(fā):BestAvailableRule
過濾:AvailabilityFilteringRule
響應(yīng)時間:WeightedResponseTimeRule
輪詢重試:RetryRule
性能可用性:ZoneAvoidanceRule
配置方式:①客戶端代碼添加規(guī)則 ②配置增加規(guī)則
代碼方式:
package com.i theima.consumer.config;
import com.netflix.loadbalancer.I Rule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRule{
@Bean
public IRule rule() {
return new RandomRule();
}
}
@EnableDiscoveryclient //激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
/*
配置Ribbon的負(fù)載均衡策略 name
*name:設(shè)置服務(wù)提供方的 應(yīng)用名稱
*configuration:設(shè)置負(fù)載均衡 Bean
*/
@RibbonClient(name=“EUREKA-PROVIDER", configuration=My Rule.class)
public class ConsumerApp {
public static void main(String[]args) {
Spring Application.run(ConsumerApp.class, args);
}
}
配置方式(在客戶端配置)
#配置的方式設(shè)置Ribbon的負(fù)載均衡策略
EUREKA-PROVIDER: #設(shè)置的服務(wù)提供方的應(yīng)用名稱
ribbon:
NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #策略類
4、Feign (糞) 簡化 服務(wù)調(diào)用 【項目中會使用】
Feign是一個聲明式的REST客戶端, 它用了基于接口的注解方式, 很方便實現(xiàn)客戶端配置。
Feign最初由Netflix公司提供, 但不支持SpringMVC注解, 后由SpringCloud對其封裝, 支持了SpringMVC注解,讓使用者更易于接受。
1.依賴 --- 消費端添加
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.定義一個接口
接口上添加注解 @FeignClient,設(shè)置value屬性為 服務(wù)提供者的 應(yīng)用名稱
里面的方法返回值and參數(shù),需要與生產(chǎn)者的方法保持一致
映射路徑需要在原方法的基礎(chǔ)上添加 /goods
@FeignClient(value = "feign-provider")
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id")int id);
}
3.添加注解
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients //開啟Feign的功能
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
4.超時間設(shè)置:
在消費者配置文件中配置(feign底層使用的ribbon 我們一般設(shè)置ribbon超時時間即可)
# 設(shè)置Ribbon的超時時間
ribbon:
ConnectTimeout: 1000 # 連接超時時間 默認(rèn)1s
ReadTimeout: 1000 # 邏輯處理的超時時間 默認(rèn)1s
5.feign 的日志問題:

在消費者配置文件中配置
# 設(shè)置當(dāng)前的日志級別 debug,feign只支持記錄debug級別的日志
logging:
level:
com.itheima: debug
5、Hystrix 服務(wù)熔斷器(保險絲)
豪豬(身上帶刺的豬,刺保護(hù)自己)
A--->B--->C 服務(wù)級聯(lián)調(diào)用,過程中很容產(chǎn)生服務(wù)雪崩效應(yīng),我們Hystrix組件解決問這個問題。
Hystrix是Netflix開源的一個延遲和容錯庫, 用于隔離訪問遠(yuǎn)程服務(wù)、第三方庫,防止出現(xiàn)級聯(lián)失敗(雪崩)
雪崩:一個服務(wù)失敗,導(dǎo)致整條鏈路的服務(wù)都失敗的情形
Hystrix主要功能
隔離
降級
熔斷
限流
1.隔離(默認(rèn)配置)

1.線程池隔離

2.信號量隔離

2.降級
當(dāng)服務(wù)發(fā)生異?;蛘{(diào)用超時,返回默認(rèn)數(shù)據(jù)
觸發(fā)降級的場景: ①異常 ②超時

2.1 服務(wù)提供方降級
1.在服務(wù)提供方, 引入hystrix依賴
2.定義降級方法
3.使用@HystrixCommand注解配置降級方法
4.在啟動類上開啟Hystrix功能:@EnableCircuitBreaker
① 引入hystrix依賴
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
②注解: 引導(dǎo)類 @EnableCircuitBreaker , controller 方法上要加入@HystrixCommand(fallbackmethod=“降級方法名稱”)
@EnableEurekaClient //該注解 在新版本中可以省略
@SpringBootApplication
@EnableCircuitBreaker //開啟熔斷器hystrix
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
③編寫降級方法 --- 這里的方法是生產(chǎn)者controller層提供服務(wù)的方法上
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback", commandProperties = {//指代觸發(fā)降級后運行的方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="3000")//超時
})
public Goods findOne(@PathVariable("id") int id){
Goods goods = goodsService.findOne(id);
//當(dāng)前線程睡2秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
goods.setTitle(goods.getTitle() + ":" + port);//將端口號,設(shè)置到了 商品標(biāo)題上
return goods;
}
/**
* 定義降級方法
* 1. 方法的參數(shù)和返回值需與原方法保持一致
*/
public Goods findOne_fallback(@PathVariable("id") int id){
Goods goods = new Goods();
goods.setTitle("降級了...");
return goods;
}
2.2 服務(wù)消費方降級
1.feign組件已經(jīng)集成了hystrix組件。
2.定義feign調(diào)用接口實現(xiàn)類, 復(fù)寫方法, 即降級方法
3.在@FeignClient注解中使用fallback屬性設(shè)置降級處理類。
4.配置開啟feign.hystrix.enabled=true
①配置文件中開熔斷
#開啟feign對hystrix的支持
feign:
hystrix:
enabled: true
#開啟feign對hystrix的支持
feign:
httpclient:
enabled: true
② 寫一個降級的類 a.實現(xiàn)feign客戶端接口(自己定義遠(yuǎn)程調(diào)用的接口) b.加入springIOc容器
package com.itheima.consumer.feign;
import com.itheima.consumer.domain.Goods;
import org.springframework.stereotype.Component;
/**
* Feign客戶端降級處理
* 1. 定義類 實現(xiàn)Feign接口
* 2. 使用@Component注解,將改類加入springmvc
* 3.
*/
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public Goods findGoodsById(int id) {
Goods goods = new Goods();
goods.setTitle("又降級了...");
return goods;
}
}
2.3 服務(wù)提供方 和消費方同時都提供 降級處理的時候,誰生效?
服務(wù)提供方的生效
3.熔斷
Hystrix熔斷機(jī)制, 用于監(jiān)控微服務(wù)調(diào)用情況, 當(dāng)失敗的情況達(dá)到預(yù)定的閾值(5秒失敗20次),會打開斷路器,拒絕所有請求,直到服務(wù)恢復(fù)正常為止。

circuitBreaker.sleepWindowInMiliseconds:監(jiān)控時間默認(rèn)5000毫秒
circuitBreaker.requestVolumeThreshold:失敗次數(shù)默認(rèn)20次
circuitBreaker.errorThresholdPercentage:失敗率默認(rèn)50%
只要我們引入依賴默認(rèn)的配置不需要你去處理!
feign 底層 對 hystrix 進(jìn)行了封裝
<!-- hystrix 如果有了feign就不需要了 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
#開啟feign對hystrix的支持
feign:
httpclient:
enabled: true
熔斷器的狀態(tài):
關(guān)閉: 正常提供服務(wù)
打開: 不能正常提供服務(wù)
半開: 有部分服務(wù)請求能夠使用 (水龍頭半開狀態(tài))
面試問題:
熔斷器 :狀態(tài):3種狀態(tài) 關(guān)閉狀態(tài) 、半開狀態(tài)、打開狀態(tài) 默認(rèn)是關(guān)閉狀態(tài),關(guān)閉----》打開狀態(tài) (條件:當(dāng)我們的服務(wù)降級次數(shù)在5秒內(nèi)超過20次時候)打開---》半開狀態(tài) (條件:五秒之以后我會放一部分請求過來)----》關(guān)閉狀態(tài) (半開狀態(tài)放過來的請求成功)
熔斷器監(jiān)控
Hystrix提供了Hystrix-dashboard功能, 用于時監(jiān)控微服務(wù)運行狀態(tài)。
但是Hystrix-dashboard只能監(jiān)控一個微服務(wù)。
Netfix還提供了Turbine, 進(jìn)行聚合監(jiān)控。



<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
spring:
application.name: hystrix-monitor
server:
port: 8769
turbine:
combine-host-port: true
# 配置需要被監(jiān)控的服務(wù)名稱列表
app-config: hystrix-provider, hystrix-consumer
cluster-name-expression: "'default'"
aggregator:
cluster-config: default
# instanceUrlSuffix: /actuator/hystrix.stream
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
創(chuàng)建啟動類
@SpringBootApplication
@EnableEurekaclient
@EnableTurbine //開啟Turbine很聚合監(jiān)控功能
@EnableHystrixDashboard //開啟Hystrix儀表盤監(jiān)控功能
public class HystrixMonitorApp{
public static void main(String[] args) {
SpringApplication.run(HystrixMonitorApp.class, args) ;
}
}
修改被監(jiān)控模塊,需要分別修改hystrix-provider和hystrix-consumer模塊:
1、導(dǎo)入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addurlMappings("/actuator/hystrix.stream/);
registrationBean.setName(“HystrixMetricsStreamServlet");
return registrationBean;
}
啟動服務(wù)后查看監(jiān)控儀表盤
http://localhost:8769/hystrix/ 瀏覽器訪問
http://localhost:8769/turbine.stream 儀表盤首頁填入


4.限流
4.1 rabbitMQ
4.2 nginx
4.3 gateway
6、SpringCloudGateway 網(wǎng)關(guān) (城門)【項目中會使用】

網(wǎng)關(guān) : 提供統(tǒng)一API路由訪問的入口
網(wǎng)關(guān)就是系統(tǒng)的入口,封裝了應(yīng)用程序的內(nèi)部結(jié)構(gòu),為客戶端提供統(tǒng)一服務(wù),一些與業(yè)務(wù)本身功能無關(guān)的公共邏輯可以在這里實現(xiàn),諸如認(rèn)證、鑒權(quán)、監(jiān)控、緩存、負(fù)載均衡、流量管控、路由轉(zhuǎn)發(fā)等
在目前的網(wǎng)關(guān)解決方案里, 有Nginx+Lua、Netflix Zuul、SpringCloud Gateway等等
操作步驟:
1.搭建網(wǎng)關(guān)模塊
2.引入依賴: starter-gateway
<!--引入gateway 網(wǎng)關(guān)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
3.編寫啟動類
@SpringBootApplication
// 啟用EurekaClient
@EnableEurekaClient
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
4.編寫配置文件
server:
port: 80
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: api-gateway-server
cloud:
# 網(wǎng)關(guān)配置
gateway:
# 路由配置:轉(zhuǎn)發(fā)規(guī)則
routes: #集合。
# id: 唯一標(biāo)識。默認(rèn)是一個UUID
# uri: 轉(zhuǎn)發(fā)路徑
# predicates: 條件,用于請求網(wǎng)關(guān)路徑的匹配規(guī)則
# filters:配置局部過濾器的
- id: gateway-provider
# 靜態(tài)路由
# uri: http://localhost:8001/
# 動態(tài)路由 lb : load baldance 負(fù)載均衡
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters: #局部過濾器
- AddRequestParameter=username,zhangsan
- id: gateway-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
# 微服務(wù)名稱配置----這里是將請求路徑前加項目名稱,一般不用
discovery:
locator:
enabled: true # 設(shè)置為true 請求路徑前可以添加微服務(wù)名稱
lower-case-service-id: true # 允許為小寫
7、Gateway 網(wǎng)關(guān)中的過濾器

內(nèi)置過濾器工廠: http://www.itdecent.cn/p/58267466251e
局部過濾器
以添加請求參數(shù)為列:
1.在網(wǎng)關(guān)模塊的yam配置文件上添加配置
cloud:
# 網(wǎng)關(guān)配置
gateway:
# 路由配置:轉(zhuǎn)發(fā)規(guī)則
routes: #集合。
# filters:配置局部過濾器的
- id: gateway-provider
# 動態(tài)路由
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters: #局部過濾器,這里只僅僅給goods路徑下的請求添加參數(shù)
- AddRequestParameter=username,zhangsan
- id: gateway-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
# 微服務(wù)名稱配置
2.給服務(wù)提供者的方法上添加 username 參數(shù)
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//設(shè)置Hystrix的超時時間,默認(rèn)1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//監(jiān)控時間 默認(rèn)5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失敗次數(shù)。默認(rèn)20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失敗率 默認(rèn)50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
public Goods findOne(@PathVariable("id") int id,String username){
System.out.println(username);
//如果id == 1 ,則出現(xiàn)異常,id != 1 則正常訪問
if(id == 1){
//1.造個異常
int i = 3/0;
}
/*try {
//2. 休眠2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port);//將端口號,設(shè)置到了 商品標(biāo)題上
return goods;
}
/**
* 定義降級方法:
* 1. 方法的返回值需要和原方法一樣
* 2. 方法的參數(shù)需要和原方法一樣
*/
public Goods findOne_fallback(int id,String username){
Goods goods = new Goods();
goods.setTitle("降級了~~~");
return goods;
}
全局過濾器
自定義全局過濾器步驟:
1.定義類實現(xiàn) GlobalFilter 和 Ordered 接口
2.復(fù)寫方法
3.完成邏輯處理
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定義全局過濾器執(zhí)行了......");
return chain.filter(exchange);//放行當(dāng)前過濾器,執(zhí)行下個過濾器
}
/**
* 過濾器排序
* 數(shù)值越小越先執(zhí)行
* @return
*/
public int getOrder() {
return 0;
}
}
8、微服務(wù)配置中心---Config

優(yōu)點:
- 集中管理配置文件
- 不同環(huán)境不同配置,動態(tài)化配置更新
- 配置信息改變時,不需要重啟即可更新配置信息到服務(wù)
config-server模塊:
1.使用gitee創(chuàng)建遠(yuǎn)程倉庫,上傳配置文件
2.搭建config server 模塊
@SpringBootApplication
@EnableConfigServer // 啟用config server功能
public class ConfigServerApp {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApp.class,args);
}
}
3.導(dǎo)入config-server依賴
<!-- config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
4.編寫配置,設(shè)置gitee遠(yuǎn)程倉庫地址
server:
port: 9527
spring:
application:
name: config-server
# spring cloud config
cloud:
config:
server:
# git 的 遠(yuǎn)程倉庫地址
git:
uri: https://gitee.com/itheima_cch/itheima-configs.git
label: master # 分支配置
5.測試訪問遠(yuǎn)程配置文件
config-client模塊:
1.導(dǎo)入 starter-config 依賴
<!--config client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2.配置 config server 地址,讀取配置文件名稱等信息
bootstrap.yml --- 優(yōu)先級更高,一般用來系統(tǒng)化的配置
# 配置config-server地址
# 配置獲得配置文件的名稱等信息
spring:
cloud:
config:
# 配置config-server地址
uri: http://localhost:9527
# 配置獲得配置文件的名稱等信息
name: config # 文件名
profile: dev # profile指定, config-dev.yml
label: master # 分支
3.獲取配置值
Config客戶端刷新
1.在config客戶端引入actuator 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.獲取配置信息類上,添加 @RefreshScope 注解
@RestController
@RequestMapping("/goods")
@RefreshScope //開啟刷新功能
public class GoodsController {
@Autowired
private GoodsService goodsService;
@Value("${server.port}")
private int port;
@Value("${itheima}")
private String itheima;
/**
* 降級:
* 1. 出現(xiàn)異常
* 2. 服務(wù)調(diào)用超時
* * 默認(rèn)1s超時
*
* @HystrixCommand(fallbackMethod = "findOne_fallback")
* fallbackMethod:指定降級后調(diào)用的方法名稱
*/
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//設(shè)置Hystrix的超時時間,默認(rèn)1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//監(jiān)控時間 默認(rèn)5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失敗次數(shù)。默認(rèn)20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失敗率 默認(rèn)50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
public Goods findOne(@PathVariable("id") int id){
//如果id == 1 ,則出現(xiàn)異常,id != 1 則正常訪問
if(id == 1){
//1.造個異常
int i = 3/0;
}
/*try {
//2. 休眠2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port+":"+itheima);//將端口號,設(shè)置到了 商品標(biāo)題上
return goods;
}
/**
* 定義降級方法:
* 1. 方法的返回值需要和原方法一樣
* 2. 方法的參數(shù)需要和原方法一樣
*/
public Goods findOne_fallback(int id){
Goods goods = new Goods();
goods.setTitle("降級了~~~");
return goods;
}
}
3.添加配置
management:
endpoints:
web:
exposure:
include: '*'
4.使用curl工具在小黑窗口發(fā)送post請求
curl -X POST http://localhost:8001/actuator/refresh
config---集成eureka

在config-server模塊配置eureka客戶端依賴
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
添加配置信息
# 將自己注冊到eureka中
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
9、Bus 消息總線

1.分別在config-server和config-client中引入 bus依賴: bus-amqp
2.分別在config-server和config-client中配置RabbitMQ
3.在config-server中設(shè)置暴露監(jiān)控斷點: bus-refresh
4.啟動測試
不需要編寫代碼,只需要做配置:
https://cloud.spring.io/spring-cloud-bus/2.2.x/reference/html/appendix.html

1.分別再 config-server 和 config-client 中引入bus依賴: bus-amqp
<!--導(dǎo)入bus依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- 暴露斷點 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.分別在 config-server 和 config-client 中配置 RabbitMQ
3.在config-server 中設(shè)置暴露監(jiān)控斷點: bus-refresh
# 配置Rabbitmq,將配置模塊注冊到eureka中
rabbitmq:
host: localhost
post: 5672
username: guest
password: guest
virtual-host: /
# 暴露bus的刷新斷點
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
4.測試
還是要通知1次config_server,config_server通過bus消息總線通知各個微服務(wù)配置更新
在小黑窗口中輸入: curl -X POST http://localhost:9527/actuator/bus-refresh
10、Stream消息驅(qū)動
- Spring Cloud Stream是一個構(gòu)建消息驅(qū)動微服務(wù)應(yīng)用的框架。
- Stream解決了開發(fā)人員無感知的使用消息中間件的問題, 因為Stream對消息中間件的進(jìn)一步封裝, 可以做到代碼層面對中間件的無感知,甚至于動態(tài)的切換中間件,使得微服務(wù)開發(fā)的高度解耦,服務(wù)可以關(guān)注更多自己的業(yè)務(wù)流程。
- Spring Cloud Stream目前支持兩種消息中間件Rabbit MQ和Kafka

- Spring Cloud Stream構(gòu)建的應(yīng)用程序與消息中間件之間是通過綁定器Binder相關(guān)聯(lián)的。綁定器對于應(yīng)用程序而言起到了隔離作用,它使得不同消息中間件的實現(xiàn)細(xì)節(jié)對應(yīng)用程序來說是透明的。
- binding是我們通過配置把應(yīng)用和spring cloud stream的binder綁定在一起
- output:發(fā)送消息Channel, 內(nèi)置Source接口
- input:接收消息Channel, 內(nèi)置Sink接口
1.創(chuàng)建消息生產(chǎn)者模塊
1.1引入依賴 starter-stream-rabbit
<!-- stream -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
1.2編寫配置,定義binder和bingings
server:
port: 8000
spring:
cloud:
stream:
# 定義綁定器,綁定到哪個消息中間件上
binders:
itheima_binder: # 自定義的綁定器名稱
type: rabbit # 綁定器類型
environment: # 指定mq的環(huán)境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
output: # channel名稱
binder: itheima_binder #指定使用哪一個binder
destination: itheima_exchange # 消息目的地
1.3.定義消息發(fā)送業(yè)務(wù)類.添加 @EnableBindings(Source.class),注入MessageChannel output , 完成消息發(fā)送
@Component
@EnableBinding(Source.class)
public class MessageProducer {
@Autowired
private MessageChannel output;
public void send(){
String msessage = "hello stream~~~";
//發(fā)送消息
output.send(MessageBuilder.withPayload(msessage).build());
System.out.println("消息發(fā)送成功~~~");
}
}
@RestController
public class ProducerController {
@Autowired
private MessageProducer producer;
@RequestMapping("/send")
public String sendMsg(){
producer.send();
return "success";
}
}
4.編寫啟動類,測試
2.創(chuàng)建消息消費者模塊
2.1創(chuàng)建消息消費者模塊,引入依賴 starter-stream-rabbit
同生產(chǎn)者
2.2編寫配置,定義binder和bingings
server:
port: 9000
spring:
cloud:
stream:
# 定義綁定器,綁定到哪個消息中間件上
binders:
itheima_binder: # 自定義的綁定器名稱
type: rabbit # 綁定器類型
environment: # 指定mq的環(huán)境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
input: # channel名稱 <-----------------------------------這里特別注意channel名稱
binder: itheima_binder #指定使用哪一個binder
destination: itheima_exchange # 消息目的地
2.3定義消息接收業(yè)務(wù)類,添加 @EnableBinding(Sink.class) ,使用 @StreamListener(Sink.INPUT) ,完成消息接收
/**
* 消息接收類
*/
@EnableBinding({Sink.class})
@Component
public class MessageListener {
@StreamListener(Sink.INPUT)
public void receive(Message message){
System.out.println(message);
System.out.println(message.getPayload());
}
}
2.4編寫啟動類測試
11、Sleuth+Zipkin鏈路追蹤
Spring Cloud Sleuth 其實是一個工具,它在整個分布式系統(tǒng)中能跟蹤一個用戶請求的過程,捕獲這些跟蹤數(shù)
據(jù),就能構(gòu)建微服務(wù)的整個調(diào)用鏈的視圖,這是調(diào)試和監(jiān)控微服務(wù)的關(guān)鍵工具。
? 耗時分析
? 可視化錯誤
? 鏈路優(yōu)化
Zipkin 是 Twitter 的一個開源項目,它致力于收集服務(wù)的定時數(shù)據(jù),以解決微服務(wù)架構(gòu)中的延遲問題,包括數(shù)據(jù)的收集、存儲、查找和展現(xiàn)。
使用步驟:
安裝啟動zipkin。 java –jar zipkin.jar
訪問zipkin web界面。 http://localhost:9411/
-
在服務(wù)提供方和消費方分別引入 sleuth 和 zipkin 依賴
<!-- sleuth-zipkin --> <!--<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> -
分別配置服務(wù)提供方和消費方。
server: port: 8001 eureka: client: service-url: defaultZone: http://localhost:8761/eureka spring: application: name: feign-provider zipkin: base-url: http://localhost:9411/ # 設(shè)置zipkin的服務(wù)端路徑 sleuth: sampler: probability: 1 # 采集率 默認(rèn) 0.1 百分之十。 啟動,測試