天天看點

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

目錄

⼀、單體應⽤存在的問題

1.1 商城項⽬架構

1.2 單體項⽬存在的問題

⼆、微服務架構

2.1 微服務架構概念

2.2 微服務架構優點

2.3 微服務架構缺點

三、微服務架構開發需要解決的問題

3.1 服務之間如何互相發現?

3.2 服務之間如何進⾏通信?

3.2.1 同步調⽤

3.2.2 異步調⽤

3.3 服務挂了該如何解決?

3.3.1 服務故障雪崩

3.3.2 如何解決服務故障雪崩

3.4 用戶端如何統⼀通路多個接⼝服務?

四、微服務架構架構

4.1 主流的微服務架構架構

4.2 SpringCloud簡介

4.3 Spring Cloud核⼼元件

4.4 SpringCloud版本介紹

五、搭建服務注冊與發現中⼼

5.1 建立SpringBoot應⽤,添加依賴

5.2 配置服務注冊與發現中⼼

5.3 在啟動類添加@EnableEurekaServer注解

5.4 運⾏及通路

 六、服務注冊

6.1 建立SpringBoot應⽤

6.2 注冊服務

6.2.1 添加依賴

6.2.2 配置application.yml

6.2.3 在目前服務應⽤的啟動類添加 @EnableEurekaClient 注解

七、服務發現-Ribbon

7.1 基礎配置

7.1.1 建立SpringBoot應⽤,添加依賴

7.1.2 配置application.yml

7.1.3 在啟動類添加 @EnableDiscoveryClient 注解

7.2 服務調⽤

7.2.1 配置RestTemplate

7.2.2 在Service中注⼊RestTemplate對象調⽤服務

7.3 案例流程圖

7.4 Ribbon服務調⽤說明

⼋、基于Ribbon進⾏服務調⽤的參數傳遞

8.1 RestTemplate發送調⽤請求的⽅法

8.2 put/post請求傳參

8.3 get請求傳參

九、服務發現-Feign

9.1 基礎配置

9.1.1 建立SpringBoot應⽤,添加依賴

9.1.2 配置application.yml

9.1.3 在啟動類添加注解

9.2 服務調⽤

9.2.1 建立Feign用戶端

9.2.2 使⽤Feign用戶端調⽤服務

9.3 Feign傳參

9.3.1 POST請求

9.3.2 Get請求

⼗、服務注冊與發現中⼼的可靠性和安全性

10.1 可靠性

10.2 安全性

10.2.1 添加SpringSecurity的依賴

10.2.3 配置Spring Security

10.2.4 服務提供者和服務消費者連接配接到注冊中⼼都要帳号和密碼

⼗⼀、熔斷器-Hystrix

11.1 熔斷器介紹

11.2 熔斷器的原理

11.3 基于Ribbon服務調⽤的熔斷器使⽤

11.3.1 服務消費者的 服務降級

11.3.2 服務提供者的 服務降級

11.3.3 服務熔斷配置

11.4 基于Feign服務調⽤的熔斷器使⽤

11.4.1 Feign中的熔斷器使⽤

11.4.2 Ribbon 參數配置

11.5 熔斷器儀表盤監控

11.5.1 搭建熔斷器儀表盤

11.5.2 配置使⽤了熔斷器的服務可被監控

⼗⼆、微服務拆分

⼗三、服務鍊路追蹤

13.1 服務追蹤說明

13.2 Zipkin

13.3 搭建zipkin伺服器

13.4 服務中Sleuth配置

13.5 zipkin服務資料存儲

⼀、單體應⽤存在的問題

1.1 商城項⽬架構

為了解決⾼并發問題,我們的 Tomcat 采⽤了叢集部署,但是每個 Tomcat 節點上不是的 依然是單體項⽬(雖然是前後端分離,但是後端采⽤的是單體開發 —— 所有的接⼝都在 同⼀個項⽬中)

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

1.2 單體項⽬存在的問題

⼀個成功的應⽤必然有⼀個趨勢:⽤戶量會不斷增加、項⽬的業務也會不斷的擴充 ⽤戶量的增加會帶來⾼并發的問題,⾼并發問題解決⽅案:

  • 應⽤伺服器 --> 單體優化 --> 叢集(負載均衡、分布式并發)
  • 資料庫伺服器 --> 資料庫優化 --> 緩存redis --> 分布式資料庫

項⽬業務的擴充,也會帶來⼀些問題:

  • 項⽬結構越來越臃腫(項⽬結構和代碼複雜、項⽬體積逐漸變得龐⼤)
  • 項⽬結構和代碼複雜導緻項⽬不易維護和⼆次開發、擴充和更新就會變得困難
  • 項⽬體積逐漸變得龐⼤導緻啟動時間越來越⻓、⽣産⼒⼤受限制
  • 單體應⽤中任何⼀個子產品的任何⼀個bug都會導緻整個系統不可⽤(單點故障)
  • 複雜的單體項⽬也會帶來持續部署的障礙
  • 單體項⽬使得采⽤新的技術和架構會變得困難

⼆、微服務架構

2.1 微服務架構概念

微服務架構是⼀種架構概念,就是将⼀個單體應⽤中的每個功能分解到各個離散的服務 中以實作對單體應⽤的解耦,并提供更加靈活的服務⽀持 從單體到微服務

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

2.2 微服務架構優點

  • 解決了單體項⽬的複雜性問題
  • 每個服務都可以由單獨的團隊進⾏開發
  • 每個服務都可以使⽤單獨的技術棧進⾏開發
  • 每個服務都是獨⽴的進⾏部署和維護
  • 每個服務都可以獨⽴進⾏擴充

2.3 微服務架構缺點

  • 微服務架構本身就是⼀個缺點:如何把握“微”的粒度;
  • 微服務架構是⼀個分布式系統,雖然單個服務變得簡單了,但是服務之間存在互相的調 ⽤,整個服務架構的系統變得複雜了;
  • 微服務架構需要依賴分布式資料庫架構;
  • 微服務的單元測試及調⽤變得⽐單體更為複雜;
  • 部署基于微服務架構的應⽤程式變得⾮常複雜;
  • 進⾏微服務架構的應⽤程式開發的技術成本變得更⾼。

三、微服務架構開發需要解決的問題

在微服務架構開發的系統中必然存在很多個服務,服務之間需要互相感覺對⽅的存在, 需要進⾏服務間的調⽤,該如何實作呢? —— 進⾏微服務架構開發需要解決的問題: 1. 如此多的服務,服務間如何互相發現? 2. 服務與服務之間該如何通信? 3. 如果某個服務挂了,該如何處理? 4. 前端通路多個不同的服務時該如何統⼀通路路徑呢?

3.1 服務之間如何互相發現?

微服務架構 —— 每個服務隻處理⼀件事情 / ⼀個步驟,在⼀個複雜的業務中必然會存在服 務間的互相調⽤,服務想要互相調⽤就需要先發現對⽅。 通過服務注冊與發現中⼼實作服務間的互相發現

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

服務注冊與發現中⼼也是⼀台獨⽴伺服器 1. 服務提供者在服務注冊與發現中⼼進⾏注冊 2. 服務注冊與發現中⼼進⾏服務記錄,并與服務提供者保持⼼跳 3. 服務消費者通過服務注冊與發現中⼼進⾏服務查詢(服務發現) 4. 服務注冊與發現中⼼傳回可⽤的服務的伺服器位址清單 5. 服務消費者通過負載均衡通路服務提供者

3.2 服務之間如何進⾏通信?

服務消費者在調⽤服務提供者時,⾸先需要通過 服務注冊與發現中⼼ 進⾏服務服務查詢, 傳回服務清單給服務消費者, 服務消費者 通過 LoadBalance 調⽤ 服務提供者 , 那麼他們之 間是如何通信呢? —— 資料傳輸規則 服務與服務間的通信⽅式有 2 種:同步調⽤ 和 異步調⽤

3.2.1 同步調⽤

  • REST(SpringCloud Netflix,SpringCloud Alibaba)
    • 基于HTTP協定的請求和響應
    • 更容易實作、技術更靈活
    • ⽀持多語⾔、同時可以實作跨用戶端
    • 适⽤⾯很⼴
  • RPC(Dubbo)
    • 基于⽹絡層協定通信
    • 傳輸效率⾼
    • 安全性更⾼
    • 如果有統⼀的開發規劃或者架構,開發效率是⽐較⾼的

3.2.2 異步調⽤

服務間的異步通信通常是通過消息隊列實作的

3.3 服務挂了該如何解決?

3.3.1 服務故障雪崩

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

3.3.2 如何解決服務故障雪崩

  • 服務叢集——盡量保證每個服務可⽤
  • 服務降級與熔斷——避免請求阻塞造成正常的服務出現故障

3.4 用戶端如何統⼀通路多個接⼝服務?

通過路由⽹關實作接⼝的統⼀通路

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

四、微服務架構架構

4.1 主流的微服務架構架構

  • Dubbo(阿⾥、開源apache):2012年推出、2014年停更、2015年⼜繼續更新
  • Dubbox(當當⽹基于Dubbo的更新)
  • jd-hydra(京東基于Dubbo的更新)
  • SpringCloud Netflix (2016年)/ SpringCloud Alibaba
  • ServiceComb(CSE)華為 2017年

4.2 SpringCloud簡介

Spring Cloud 是⼀個基于 SpringBoot 實作的微服務架構應⽤開發架構,它為我們進⾏微 服務架構應⽤開發提供了服務注冊與發現、熔斷器、⽹關路由、配置管理、負載均衡、 消息總線、資料監控等⼀系列⼯具。 Spring Cloud ⽐較成熟的兩個體系:

  • Spring Cloud Netflix
  • Spring Cloud Alibaba

4.3 Spring Cloud核⼼元件

  • Spring Cloud Netflix
    • Eureka 服務注冊與發現中⼼,⽤于服務治理
    • Ribbon 服務通路元件、進⾏服務調⽤,實作了負載均衡
    • Hystrix 熔斷器,服務容錯管理
    • Feign 服務通路元件(對Ribbon和HyStrix的封裝)
    • zuul ⽹關元件
  • Spring Cloud Config 配置管理的元件—分布式配置中⼼
  • Spring Cloud Bus 消息總線
  • Spring Cloud Consul 服務注冊與發現中⼼(功能類似eureka)

4.4 SpringCloud版本介紹

  • SpringCloud版本 : A-H,2020.0.2
  • SpringCloud的版本對SpringBoot版本時有依賴的
    • A ---- 1.2
    • B ---- 1.3
    • C ---- 1.4
    • D-E ---- 1.5
    • F-G-H ---- 2.x

五、搭建服務注冊與發現中⼼

使⽤ Spring Cloud Netflix 中的 Eureka 搭建服務注冊與發現中⼼

5.1 建立SpringBoot應⽤,添加依賴

  • spring web
  • eureka server

5.2 配置服務注冊與發現中⼼

## 設定服務注冊與發現中⼼的端⼝ server : port : 8761 ## 在微服務架構中,服務注冊中⼼是通過服務應⽤的名稱來區分每個服務的 ## 我們在建立每個服務之後,指定目前服務的 應⽤名 / 項⽬名 spring : application : name : service-eureka eureka : client : ## ip 就是服務注冊中⼼伺服器的 ip ## port 就是服務注冊與發現中⼼設定的 port service-url : defaultZone : http : //192.168.54.59 : 8761/eureka ## 設定服務注冊與發現中⼼是否為為叢集搭建(如果為叢集模式,多個 eureka 節點之間 需要互相注冊) register-with-eureka : false ## 設定服務注冊與發現中是否作為服務進⾏注冊 fetch-registry : false

5.3 在啟動類添加@EnableEurekaServer注解

5.4 運⾏及通路

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

 六、服務注冊

建立儲存訂單的服務( order-add )注冊到服務注冊與發現中⼼

6.1 建立SpringBoot應⽤

建立 spring boot 應⽤,完成功能開發

6.2 注冊服務

将能夠完成特定業務的 SpringBoot 應⽤作為服務提供者,注冊到服務注冊與發現中⼼

6.2.1 添加依賴

eureka-server [ 注意版本! ]

<dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-starter-netflix-eureka-server </artifactId> </dependency>

6.2.2 配置application.yml

## 目前服務的 port server : port : 9001 ## 目前應⽤名會作為服務唯⼀辨別注冊到 eureka spring : application : name : order-add datasource : driver-class-name : com.mysql.jdbc.Driver url : jdbc : mysql : //localhost : 3306/db_2010_sc?characterEncoding=utf-8 username : root password : admin123 mybatis : mapper-locations : classpath : mappers/* type-aliases-package : com.qfedu.order.beans ## 配置 Eureka 服務注冊與發現中⼼的位址 eureka : client : service-url : defaultZone : http : //localhost : 8761/eureka

6.2.3 在目前服務應⽤的啟動類添加 @EnableEurekaClient 注解

@SpringBootApplication
@MapperScan("com.qfedu.order.dao")
@EnableEurekaClient
public class OrderAddApplication {
 public static void main(String[] args) {
 SpringApplication.run(OrderAddApplication.class, args);
 }
}
           

七、服務發現-Ribbon

服務消費者( api-order-add )通過 eureka 查找服務提供者( order-add ) , 通過服務調⽤ 元件調⽤提供者

  • eureka server
  • ribbon

7.1 基礎配置

Ribbon 用戶端已經停更進維啦

7.1.1 建立SpringBoot應⽤,添加依賴

  • eureka server
  • ribbon

7.1.2 配置application.yml

server : port : 8001 spring : application : name : api-order-add eureka : client : service-url : defaultZone : http : //localhost : 8761/eureka

7.1.3 在啟動類添加 @EnableDiscoveryClient 注解

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

7.2 服務調⽤

7.2.1 配置RestTemplate

@Configuration
public class AppConfig {
 @LoadBalanced //啟⽤Ribbon(負載均衡)
 @Bean
 public RestTemplate getRestTemplate(){
 return new RestTemplate();
 }
}
           

7.2.2 在Service中注⼊RestTemplate對象調⽤服務

@Service
public class OrderAddServiceImpl implements OrderAddService {
 @Autowired
 private RestTemplate restTemplate;
 @Override
 public ResultVO saveOrder(Order order) {
 //1. 調⽤ order-add服務進⾏儲存
 ResultVO vo = restTemplate.postForObject("http://orderadd/order/add", order, ResultVO.class);
 //2. 調⽤ orderitem-add 儲存訂單快照
 //3. 調⽤ stock-update 修改商品庫存
 //4. 調⽤ shopcart-del 删除購物⻋記錄
 return null;
 }
}
           

7.3 案例流程圖

服務注冊與發現-案例流程圖

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

7.4 Ribbon服務調⽤說明

@LoadBalanced 注解是 Ribbon 的⼊⼝,在 RestTemplate 對象上添加此注解之後,再使 ⽤ RestTemplate 發送 REST 請求的時候,就可以通過 Ribbon 根據服務名稱從 Eureka 中查 找服務對應的通路位址清單,再根據負載均衡政策(預設輪詢)選擇其中的⼀個,然後 完成服務的調⽤

  • 擷取服務清單
  • 根據負載均衡政策選擇服務
  • 完成服務調⽤

⼋、基于Ribbon進⾏服務調⽤的參數傳遞

8.1 RestTemplate發送調⽤請求的⽅法

SpringCloud 的服務調⽤是基于 REST 的,是以當服務提供者規定了請求的⽅式,服務消 費者必須發送對應⽅式的請求才能完成服務的調⽤, RestTemplate 提供了多個⽅法⽤于 發送不同形式的請求

//post⽅式請求
restTemplate.postForObject();
//get⽅式請求
restTemplate.getForObject();
//delete⽅式請求
restTemplate.delete();
//put⽅式請求
restTemplate.put();
           

8.2 put/post請求傳參

  • 服務消費者請求傳參
//參數1:通路服務的url
//參數2:傳遞的對象參數
//參數3:指定服務提供者傳回的資料類型
ResultVO vo = restTemplate.postForObject("http://order-add/order/add",
order, ResultVO.class);
           
  • 服務提供者接收參數
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
 return orderService.saveOrder(order);
}
           

8.3 get請求傳參

  • 服務消費者請求傳參
String userId = order.getUserId();
ResultVO vo = restTemplate.getForObject("http://order-add/order/add?
userId="+userId, ResultVO.class);
           
  • 服務提供者接收參數
@GetMapping("/add")
public ResultVO addOrder(Order order){
 return orderService.saveOrder(order);
}
@GetMapping("/add")
public ResultVO addOrder(String userId){
 //return orderService.saveOrder(order);
}
           

九、服務發現-Feign

9.1 基礎配置

9.1.1 建立SpringBoot應⽤,添加依賴

  • spring web
  • eureka server
  • OpenFeign

9.1.2 配置application.yml

server : port : 8002 spring : application : name : api-order-add-feign eureka : client : service-url : defaultZone : http : //localhost : 8761/eureka

9.1.3 在啟動類添加注解

@SpringBootApplication
@EnableDiscoveryClient //聲明為服務消費者
@EnableFeignClients //聲明啟⽤feign用戶端
public class ApiOrderAddFeignApplication {
 public static void main(String[] args) {
 SpringApplication.run(ApiOrderAddFeignApplication.class, args);
 }
}
           

9.2 服務調⽤

使⽤ Feign 進⾏服務調⽤的時候,需要⼿動建立⼀個服務通路用戶端(接⼝)

9.2.1 建立Feign用戶端

@FeignClient("order-add")
public interface OrderAddClient {
 @PostMapping("order/add")
 public ResultVO addOrder(Order order);
}
           

9.2.2 使⽤Feign用戶端調⽤服務

@Service
public class OrderAddServiceImpl implements OrderAddService {
 @Autowired
 private OrderAddClient orderAddClient;
 @Override
 public ResultVO saveOrder(Order order) {
 //1. 調⽤ order-add服務進⾏儲存
 ResultVO vo = orderAddClient.addOrder(order);
 //2. 調⽤ orderitem-add 儲存訂單快照
 //3. 調⽤ stock-update 修改商品庫存
 //4. 調⽤ shopcart-del 删除購物⻋記錄
 return vo;
 }
}
           

9.3 Feign傳參

9.3.1 POST請求

  • 通過請求體傳遞對象
    • 服務提供者
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order){
 System.out.println("-------------------order-add");
 System.out.println(order);
 return orderService.saveOrder(order);
}
           
    • 服務消費者(Feign用戶端)
@FeignClient("order-add")
public interface OrderAddClient {
 @PostMapping("order/add")
 public ResultVO addOrder(Order order);
} 1234567
           
  • 通過請求⾏傳參
    • 服務提供者
@PostMapping("/add")
public ResultVO addOrder(@RequestBody Order order,String str){
 System.out.println("-------------------order-add");
 System.out.println(order);
 System.out.println(str);
 return orderService.saveOrder(order);
}
           
    • 服務消費者(Feign用戶端)
//1.對⽤POST請求調⽤服務,Feign用戶端的⽅法參數預設為body傳值(body隻能有⼀個
值)
//2.如果有多個參數,則需要通過@RequestParam聲明參數為請求⾏傳值
@PostMapping("order/add")
public ResultVO addOrder(Order order,@RequestParam("str") String
str);
           

9.3.2 Get請求

Get 請求調⽤服務,隻能通過 url 傳參 在 Feign 用戶端的⽅法中,如果不指定參數的傳值⽅式,則預設為 body 傳參, Get 請求也 不例外;是以對于 get 請求傳遞參數,必須通過 @RequestParam 注解聲明

  • 服務提供者
@GetMapping("/get")
public Order addOrder(String orderId){
 return new Order();
}
           
  • 服務消費者(Feign用戶端)
@GetMapping("order/get")
public Order getOrder(@RequestParam("orderId") String orderId);
           

⼗、服務注冊與發現中⼼的可靠性和安全性

10.1 可靠性

在微服務架構系統中,服務消費者是通過服務注冊與發現中⼼發現服務、調⽤服務的, 服務注冊與發現中⼼伺服器⼀旦挂掉,将會導緻整個微服務架構系統的崩潰,如何保證 Eureka 的可靠性呢?

  • 使⽤eureka叢集

Eureka 叢集搭建 互相注冊、互相發現

## 設定服務注冊與發現中⼼的端⼝ server : port : 8761 ## 在微服務架構中,服務注冊中⼼是通過服務應⽤的名稱來區分每個服務的 ## 我們在建立每個服務之後,指定目前服務的 應⽤名 / 項⽬名 spring : application : name : service-eureka eureka : client : ## 設定服務注冊與發現中⼼是否為叢集搭建 register-with-eureka : true ## 設定服務注冊與發現中是否作為服務進⾏注冊 fetch-registry : true ## ip 就是服務注冊中⼼伺服器的 ip ## port 就是服務注冊與發現中⼼設定的 port service-url : defaultZone : http : //192.168.54.10 : 8761/eureka

10.2 安全性

當完成 Eureka 的搭建之後,隻要知道 ip 和 port 就可以随意的注冊服務、調⽤服務,這是 不安全的,我們可以通過設定帳号和密碼來限制服務的注冊及發現。 在 eureka 中整合 Spring Security 安全架構實作帳号和密碼驗證

10.2.1 添加SpringSecurity的依賴

<dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-security </artifactId> </dependency>

10.2.2 設定通路 eureka 的帳号和密碼

spring : security : user : name : zhangsan password : 123456

10.2.3 配置Spring Security

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http.csrf().disable();
 //設定目前伺服器的所有請求都要使⽤spring security的認證
 
http.authorizeRequests().anyRequest().authenticated().and().httpBasic(
);
 }
} 
           

10.2.4 服務提供者和服務消費者連接配接到注冊中⼼都要帳号和密碼

eureka : client : service-url : defaultZone : http : //zhangsan : [email protected] : 8761/eureka

⼗⼀、熔斷器-Hystrix

服務故障的雪崩效應:當 A 服務調⽤ B 服務時,由于 B 服務的故障導緻 A 服務處于阻塞狀 态,當量的請求可能會導緻 A 服務因資源耗盡⽽出現故障。 為了解決服務故障的雪崩效應,出現了熔斷器模型。

11.1 熔斷器介紹

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

熔斷器作⽤ :

  • 服務降級 :⽤戶請求A服務,A服務調⽤B服務,當B服務出現故障或者在特定的時間段内 不能給A服務響應,為了避免A服務因等待B服務⽽産⽣阻塞,A服務就不等B服務的結果 了,直接給⽤戶⼀個降級響應
  • 服務熔斷 :⽤戶請求A服務,A服務調⽤B服務,當B服務出現故障的頻率過⾼達到特定阈 值(5s 20次)時,當⽤戶再請求A服務時,A服務将不再調⽤B服務,直接給⽤戶⼀個降級響應

11.2 熔斷器的原理

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

11.3 基于Ribbon服務調⽤的熔斷器使⽤

11.3.1 服務消費者的 服務降級

  • 添加熔斷器依賴 hystrix
<dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-starter-netflix-hystrix </artifactId> </dependency>
  • 在啟動類添加 @EnableHystrix 注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class ApiOrderAddApplication {
 public static void main(String[] args) {
 SpringApplication.run(ApiOrderAddApplication.class, args);
 }
}
           
  • 在調⽤服務提供者的業務處理⽅法中,進⾏降級配置
@Service
public class OrderAddServiceImpl implements OrderAddService {
 @Autowired
 private RestTemplate restTemplate;
 @HystrixCommand(fallbackMethod =
"fallbackSaveOrder",commandProperties = {
 
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds
",value="3000")
 })
 public ResultVO saveOrder(Order order) {
 //1. 調⽤ order-add服務進⾏儲存
 //參數1:通路服務的url
 //參數2:傳遞的對象參數
 //參數3:指定服務提供者傳回的資料類型
 ResultVO vo =
 restTemplate.postForObject("http://order-add/order/add",
order, ResultVO.class);
 System.out.println(vo);
 //2. 調⽤ orderitem-add 儲存訂單快照
 //3. 調⽤ stock-update 修改商品庫存
 //4. 調⽤ shopcart-del 删除購物⻋記錄
 return vo;
 }
 /**
 * 降級⽅法:與業務⽅法擁有相同的參數和傳回值
 * @return
 */
 public ResultVO fallbackSaveOrder(Order order){
 return ResultVO.fail("⽹絡異常,請重試!",null);
 }
}
           

11.3.2 服務提供者的 服務降級

  • 配置步驟⼀緻
  • 服務提供者接⼝降級
@RestController
@RequestMapping("/order")
public class OrderController {
 @Autowired
 private OrderService orderService;
 @HystrixCommand(fallbackMethod =
"fallbackAddOrder",commandProperties = {
 
@HystrixProperty(name="execution.isolation.thread.timeoutInMillisecond
s",value="3000")
 })
 @PostMapping("/add")
 public ResultVO addOrder(@RequestBody Order order){
 System.out.println("-------------------order-add");
 System.out.println(order);
 try {
 Thread.sleep(5000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 return orderService.saveOrder(order);
 }
 public ResultVO fallbackAddOrder(@RequestBody Order order){
 System.out.println("-------------------order-add--fallback");
 return ResultVO.fail("訂單儲存失敗!",null);
 }
}
           

11.3.3 服務熔斷配置

  • 熔斷器狀态:閉合、打開、半開
  • 服務熔斷配置
@HystrixCommand(fallbackMethod =
"fallbackSaveOrder",commandProperties = {
 
@HystrixProperty(name="execution.isolation.thread.timeoutInMillise
conds",value="3000"),
 @HystrixProperty(name="circuitBreaker.enabled",value="true"),
//啟⽤服務熔斷
 
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",v
alue="10000"),//時間
 
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",valu
e="10"),//請求次數
 
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",va
lue="50"),//服務錯誤率
})
public ResultVO saveOrder(Order order) {
 //1. 調⽤ order-add服務進⾏儲存
 ResultVO vo = restTemplate.postForObject("http://orderadd/order/add", order, ResultVO.class);
 System.out.println(vo);
 //2. 調⽤ orderitem-add 儲存訂單快照
 //3. 調⽤ stock-update 修改商品庫存
 //4. 調⽤ shopcart-del 删除購物⻋記錄
 return vo; }
/**
* 降級⽅法:與業務⽅法擁有相同的參數和傳回值
* @return
*/
public ResultVO fallbackSaveOrder(Order order){
 return ResultVO.fail("⽹絡異常,請重試!",null);
}
           

服務熔斷:當⽤戶請求服務 A ,服務 A 調⽤服務 B 時,如果服務 B 的故障率達到特定的 門檻值時,熔斷器就會被打開⼀個時間周期(預設 5s ,可⾃定義),在這個時間周期 内如果⽤戶請求服務 A ,服務 A 将不再調⽤服務 B ,⽽是直接響應降級服務。

11.4 基于Feign服務調⽤的熔斷器使⽤

Feign 是基于 Ribbon 和 Hystrix 的封裝

11.4.1 Feign中的熔斷器使⽤

  • 添加依賴

        SpringBoot 2.3.11 Spring Cloud H

<parent> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-parent </artifactId> <version> 2.3.11.RELEASE </version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <java.version> 1.8 </java.version> <spring-cloud.version> Hoxton.SR11 </spring-cloud.version> </properties>
<dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-starter-netflix-hystrix </artifactId> </dependency>
  • 在application.yml啟⽤熔斷器機制
feign : hystrix : enabled : true
  • 在啟動類添加 @EnableHystrix
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class ApiOrderAddFeignApplication {
 public static void main(String[] args) {
 SpringApplication.run(ApiOrderAddFeignApplication.class,
args);
 }
}
           
  • 建立服務降級處理類

        FeignClient的服務降級類: 1. 必須實作 Feign 用戶端接⼝, 2. 必須交給 Spring 容器管理

@Component
public class OrderAddClientFallback implements OrderAddClient {
 public ResultVO addOrder(Order order, String str) {
 System.out.println("-------addOrder的降級服務");
 return ResultVO.fail("fail",null);
 }
 public Order getOrder(String orderId) {
 System.out.println("-------getOrder的降級服務");
 return new Order();
 }
}
           
  • 在Feign用戶端指定降級處理類
@FeignClient(value = "order-add", fallback =
OrderAddClientFallback.class)
public interface OrderAddClient {
 //1.對⽤POST請求調⽤服務,Feign用戶端的⽅法參數預設為body傳值(body隻能
有⼀個值)
 //2.如果有多個參數,則需要通過@RequestParam聲明參數為請求⾏傳值
 @PostMapping("order/add")
 public ResultVO addOrder(Order order,@RequestParam("str")
String str);
 @GetMapping("order/get")
 public Order getOrder(@RequestParam("orderId") String orderId);
}
           
  • Service類通過Feign用戶端調⽤服務
@Service
public class OrderAddServiceImpl implements OrderAddService {
 @Autowired
 private OrderAddClient orderAddClient;
 //當我們建立Feign用戶端的降級類并交給Spring管理後 在Spring容器中就會出現
兩個OrderAddClient對象
 @Override
 public ResultVO saveOrder(Order order) {
 //1. 調⽤ order-add服務進⾏儲存
 ResultVO vo = orderAddClient.addOrder(order,"測試字元串");
 Order order1 = orderAddClient.getOrder("訂單編号");
 System.out.println(order1);
 //2. 調⽤ orderitem-add 儲存訂單快照
 //3. 調⽤ stock-update 修改商品庫存
 //4. 調⽤ shopcart-del 删除購物⻋記錄
 return vo;
 }
}
           

11.4.2 Ribbon 參數配置

SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤
ribbon : ## Ribbon 建⽴連接配接最⼤等待時間 ConnectTimeout : 1000 ## 在目前服務提供者嘗試連接配接次數 MaxAutoRetries : 2 ## 與服務提供者通信時間 ReadTimeout : 5000 ## 設定熔斷器服務降級時間 (預設 1000 ) hystrix : command : default : execution : isolation : thread : timeoutInMilliseconds : 8000

11.5 熔斷器儀表盤監控

如果伺服器的并發壓⼒過⼤、伺服器⽆法正常響應,則熔斷器狀态變為 open 屬于正常的 情況;但是如果⼀個熔斷器⼀直處于 open 狀态、或者說伺服器提供者沒有通路壓⼒的情 況下熔斷器依然為 open 狀态,說明熔斷器的狀态就不屬于正常情況了。如何了解熔斷器 的⼯作狀态呢 ?

  • 熔斷器儀表盤

11.5.1 搭建熔斷器儀表盤

  • 建立SpringBoot項⽬,添加依賴
<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> <dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-starter-netflix-hystrix dashboard </artifactId> </dependency>
  • 配置儀表盤的port和appName
server : port : 9999 spring : application : name : hystrix-dashboard hystrix : dashboard : proxy-stream-allow-list : "localhost"
  • 啟動類添加 @EanbleHystrixDashboard 注解
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
 public static void main(String[] args) {
 SpringApplication.run(HystrixDashboardApplication.class,
args);
 }
}
           
  • 通路 http://localhost:9999/hystrix
SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

11.5.2 配置使⽤了熔斷器的服務可被監控

  • 添加依賴
<dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-actuator </artifactId> </dependency>
  • 配置
@Configuration
public class DashBoardConfig {
 @Bean
 public ServletRegistrationBean getServletRegistrationBean(){
 HystrixMetricsStreamServlet streamServlet = new
HystrixMetricsStreamServlet();
 ServletRegistrationBean registrationBean =
 new ServletRegistrationBean(streamServlet);
 registrationBean.setName("HystrixMetricsStreamServlet");
 registrationBean.setLoadOnStartup(1);
 registrationBean.addUrlMappings("/hystrix.stream");
 return registrationBean;
 }
}
           
  • 檢視指定服務的熔斷器⼯作參數
SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤
SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤

⼗⼆、微服務拆分

⼗三、服務鍊路追蹤

13.1 服務追蹤說明

  • 微服務架構是通過業務來劃分服務的,使⽤REST調⽤。對外暴露的⼀個接⼝,可能需要 很多個服務協同才能完成這個接⼝功能,如果鍊路上任何⼀個服務出現問題或者⽹絡超 時,都會形成導緻接⼝調⽤失敗。
SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤
  • 随着業務的不斷擴張,服務之間互相調⽤會越來越複雜,它們之間的調⽤關系也許如下:
SpringCloud 基本使用⼀、單體應⽤存在的問題 ⼆、微服務架構 三、微服務架構開發需要解決的問題 四、微服務架構架構 五、搭建服務注冊與發現中⼼  六、服務注冊 七、服務發現-Ribbon ⼋、基于Ribbon進⾏服務調⽤的參數傳遞 九、服務發現-Feign ⼗、服務注冊與發現中⼼的可靠性和安全性 ⼗⼀、熔斷器-Hystrix ⼗⼆、微服務拆分 ⼗三、服務鍊路追蹤
  • 随着服務的越來越多,對調⽤鍊的分析會越來越複雜。

13.2 Zipkin

  • ZipKin是⼀個開放源代碼的分布式跟蹤系統,由Twitter公司開源,它緻⼒于收集服務的 定時資料,以解決微服務架構中的延遲問題,包括資料的收集、存儲、查找和展現。它 的理論模型來⾃于 Google Dapper 論⽂。
  • 每個服務向 ZipKin 報告計時資料,ZipKin 會根據調⽤關系通過 ZipKin UI ⽣成依賴關系 圖,顯示了多少跟蹤請求通過每個服務,該系統讓開發者可通過⼀個 Web 前端輕松的收 集和分析資料,例如⽤戶每次請求服務的處理時間等,可⽅便的監測系統中存在的瓶 頸。

13.3 搭建zipkin伺服器

  • 建立SpringBoot項⽬(版本2.1.x)
  • 添加依賴
<dependency> <groupId> io.zipkin.java </groupId> <artifactId> zipkin-server </artifactId> <version> 2.11.10 </version> </dependency> <!--zipkin 界⾯ --> <dependency> <groupId> io.zipkin.java </groupId> <artifactId> zipkin-autoconfigure-ui </artifactId> <version> 2.11.10 </version> </dependency>
  • 在啟動類添加 @EnableZipkinServer 注解
@SpringBootApplication
@EnableZipkinServer
public class ZipkinApplication {
 public static void main(String[] args) {
 SpringApplication.run(ZipkinApplication.class, args);
 }
}
           
  • 配置yml
spring : application : name : zipkin server : port : 9411 management : endpoints.web.exposure.include : '*' metrics.web.server.auto-time-requests : false

13.4 服務中Sleuth配置

  • 在服務應⽤中添加Sleuth依賴
<!-- spring-cloud-sleuth-zipkin --> <dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-sleuth-zipkin </artifactId> <version> 2.0.2.RELEASE </version> </dependency>
  • 在服務應⽤中配置yml
spring : application : name : goods-provider zipkin : enabled : true base-url : http : //localhost : 9411 sleuth : sampler : probability : 0.1

13.5 zipkin服務資料存儲

  • 建立資料庫資料表
CREATE TABLE IF NOT EXISTS zipkin_spans (
 `trace_id` BIGINT NOT NULL,
 `id` BIGINT NOT NULL,
 `name` VARCHAR(255) NOT NULL,
 `parent_id` BIGINT,
 `debug` BIT(1),
 `start_ts` BIGINT COMMENT "Span.timestamp(): epoch micros used
for endTs query and to implement TTL",
 `duration` BIGINT COMMENT "Span.duration(): micros used for
minDuration and maxDuration query"
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id`, `id`) COMMENT
"ignore insert on duplicate";
ALTER TABLE zipkin_spans ADD INDEX(`trace_id`, `id`) COMMENT "for
joining with zipkin_annotations";
ALTER TABLE zipkin_spans ADD INDEX(`trace_id`) COMMENT "for
getTracesByIds";

ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT "for getTraces
and getSpanNames";
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT "for
getTraces ordering and range";
CREATE TABLE IF NOT EXISTS zipkin_annotations (
 `trace_id` BIGINT NOT NULL COMMENT "coincides with
zipkin_spans.trace_id",
 `span_id` BIGINT NOT NULL COMMENT "coincides with
zipkin_spans.id",
 `a_key` VARCHAR(255) NOT NULL COMMENT "BinaryAnnotation.key or
Annotation.value if type == -1",
 `a_value` BLOB COMMENT "BinaryAnnotation.value(), which must be
smaller than 64KB",
 `a_type` INT NOT NULL COMMENT "BinaryAnnotation.type() or -1 if
Annotation",
 `a_timestamp` BIGINT COMMENT "Used to implement TTL;
Annotation.timestamp or zipkin_spans.timestamp",
 `endpoint_ipv4` INT COMMENT "Null when
Binary/Annotation.endpoint is null",
 `endpoint_ipv6` BINARY(16) COMMENT "Null when
Binary/Annotation.endpoint is null, or no IPv6 address",
 `endpoint_port` SMALLINT COMMENT "Null when
Binary/Annotation.endpoint is null",
 `endpoint_service_name` VARCHAR(255) COMMENT "Null when
Binary/Annotation.endpoint is null"
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id`,
`span_id`, `a_key`, `a_timestamp`) COMMENT "Ignore insert on
duplicate";
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`)
COMMENT "for joining with zipkin_spans";
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`) COMMENT "for
getTraces/ByIds";
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`)
COMMENT "for getTraces and getServiceNames";
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT "for
getTraces";
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT "for
getTraces";

CREATE TABLE IF NOT EXISTS zipkin_dependencies (
 `day` DATE NOT NULL,
 `parent` VARCHAR(255) NOT NULL,
 `child` VARCHAR(255) NOT NULL,
 `call_count` BIGINT
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`,
`child`);
           
  • pom依賴
<!-- zipkin-storage-mysql-v1 --> <dependency> <groupId> io.zipkin.zipkin2 </groupId> <artifactId> zipkin-storage-mysql-v1 </artifactId> <version> 2.11.12 </version> </dependency> <!--mysql 驅動 --> <dependency> <groupId> mysql </groupId> <artifactId> mysql-connector-java </artifactId> <version> 5.1.47 </version> </dependency>
  • 配置yml
spring : application : name : zipkin datasource : username : root password : admin123 driver-class-name : com.mysql.jdbc.Driver url : jdbc : mysql : //localhost : 3306/zipkin zipkin : storage : type : mysql