轉載https://blog.csdn.net/weixin_44448094/article/details/88535475
一、 網站的架構演變
網絡架構由最開始的三層mvc漸漸演變。傳統的三層架構后來在互聯網公司讓幾百人幾千人同時開發一個項目已經變得不可行,並且會產生代碼沖突的問題。基於SOA面向服務開發的架構,漸漸產生了微服務架構。微服務的架構的特點就是項目拆分成各個子項目,進行解耦操作,提供外部訪問接口,屬於敏捷開發,其實也可以視為面向接口開發。
一旦有了多個子項目,比如把淘寶網的訂單系統和會員系統分開來看,就回產生如何管理接口、負載均衡、高並發情況下怎么限流斷路等問題。那么這就有SpringCloud出現了。
那么springCloud的組件大概有哪些呢,我先簡單介紹下:
- Eureka 服務注冊中心
- 服務消費者 Rest 和 Fegin --消費實現負載均衡ribbon
- 接口網關Zuul
- Hystrix 關於服務雪崩的解決方案--服務熔斷、服務降級、隔離資源。
二、 Eureka
eureka是個什么東西呢?它是一個服務注冊中心。就拿上面的例子來說,如果要查看會員的訂單詳情,那么就要在會員系統的tomcat里面調用訂單系統的tomcat里的方法。那么直接通過接口訪問嗎?顯然這是不安全的。因此我們需要一個統一管理遠程RPC調用的注冊中心
如圖所示,會員系統和訂單都是獨立能夠運行的SpringBoot項目,把SpringBoot注冊進eureka中,這樣我們就可以通過eureka讓會員系統遠程調用訂單系統。具體配置要怎么做呢?
首先我們要創建eureka注冊中心,這里建議用idea的工具創建SpringBoot項目。
選擇如圖的包,如果沒有則直接復制pom文件
-
<?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>
-
<parent>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-parent
</artifactId>
-
<version>2.1.3.RELEASE
</version>
-
<relativePath/>
<!-- lookup parent from repository -->
-
</parent>
-
<groupId>my
</groupId>
-
<artifactId>learning
</artifactId>
-
<version>0.0.1-SNAPSHOT
</version>
-
<name>learning
</name>
-
<description>Demo project for Spring Boot
</description>
-
-
<properties>
-
<java.version>1.8
</java.version>
-
<spring-cloud.version>Greenwich.SR1
</spring-cloud.version>
-
</properties>
-
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-web
</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-netflix-eureka-server
</artifactId>
-
</dependency>
-
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-test
</artifactId>
-
<scope>test
</scope>
-
</dependency>
-
</dependencies>
-
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-dependencies
</artifactId>
-
<version>${spring-cloud.version}
</version>
-
<type>pom
</type>
-
<scope>import
</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-maven-plugin
</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
-
<repositories>
-
<repository>
-
<id>spring-milestones
</id>
-
<name>Spring Milestones
</name>
-
<url>https://repo.spring.io/milestone
</url>
-
</repository>
-
</repositories>
-
-
</project>
然后我們去yml文件中做如下配置
-
#eureka的端口號
-
server:
-
port: 8888
-
eureka:
-
instance:
-
hostname: localhost
-
client:
-
registerWithEureka:
false
-
fetchRegistry:
false
-
serviceUrl:
-
defaultZone: http://
${eureka.instance.hostname}:
${server.port}/eureka/
然后在啟動類里添加表示為eureka注冊中心
-
@EnableEurekaServer
-
@SpringBootApplication
-
public
class LearningApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(LearningApplication.class, args);
-
}
-
-
}
通過localhost:8888可以進到如下頁面就表示eureka注冊中心啟動成功
OK,那么我們要怎么把訂單系統和會員系統注冊進去呢?同樣創建兩個SpringBoot項目,創建方式和導包方式和注冊中心一樣。我們關注的只有yml文件是如何把這個springBoot項目注冊進去的,那么我們來看看yml文件如何配置
-
eureka:
-
client:
-
serviceUrl:
-
# eureka的注冊中心地址
-
defaultZone: http:
//localhost:8888/eureka/
-
server:
-
# 此項目端口號
-
port:
8889
-
spring:
-
application:
-
# 注冊進eureka的名字
-
name: order-server
創建controller包並且啟動
-
@RestController
-
public
class ordercontroller {
-
@RequestMapping(
"orderTest")
-
public String orderTest(){
-
return
"this is order";
-
}
-
}
-
-
// 啟動類
-
@EnableEurekaClient
-
@SpringBootApplication
-
public
class DemoApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(DemoApplication.class, args);
-
}
-
-
}
再次打開注冊中心網頁,就發現已經注冊進去
重復以上步驟把會員系統也注冊進去
三、 PRC遠程調用的方法
遠程調用的方法有兩種,我們一一來細說。
1. 第一種,通過rest的方式來調用,首先我們要導入rest的pom依賴,我們要使用用戶調用訂單,就在用戶里添加調用依賴。先解釋一下什么是ribbon-----ribbon是一個負載均衡客戶端 類似nginx反向代理,可以很好的控制htt和tcp的一些行為。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
-
// 在啟動類里把ribbon類注入spring
-
@EnableEurekaClient
-
@SpringBootApplication
-
public
class DemoApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(DemoApplication.class, args);
-
}
-
@Bean
-
@LoadBalanced
// 開啟負載均衡
-
public RestTemplate restTemplate(){
-
return
new RestTemplate();
-
}
-
}
-
-
public
class memService{
-
@Autowired
-
private RestTemplate restTemplate;
-
@RequestMapping(
"/memTest")
-
public String memTest(){
-
String str = restTemplate.getForObject(
"http://order-server/orderTest",String.class);
-
return str;
-
}
-
}
然后我們調用會員系統的接口訪問,看他會不會走到訂單系統里
這就是Rest遠程調用的結果。
2. Feigin
Feign是一個聲明式的偽Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只需要創建一個接口並注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的編碼器和解碼器。Feign默認集成了Ribbon,並和Eureka結合,默認實現了負載均衡的效果。
簡而言之:
·Feign 采用的是基於接口的注解
·Feign 整合了ribbon
第一步依然是導入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
-
@Service
-
@FeignClient(
"order-server")
-
public
interface orderFeign {
-
@RequestMapping(
"/orderTest")
-
public String orderTest();
-
}
-
@RestController
-
public
class memController {
-
@Autowired
-
private OrderFeign orderFeign;
-
@RequestMapping(
"/memTest")
-
public String memTest(){
-
String str = orderFeign.orderTest();
-
return str;
-
}
-
}
-
-
// 啟動類
-
@EnableEurekaClient
-
@EnableFeignClients
-
@SpringBootApplication
-
public
class DemoApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(DemoApplication.class, args);
-
}
-
-
}
因此成功。這兩個方式使用ribbon均衡負載,一個需要手動啟動,fegin是自動啟動。
四、 路由網關(ZUUL)
路由網關有什么作用呢?上面訂單和會員系統已經注冊進服務中心,兩者之間是通過網址直接訪問。但是如果在瀏覽器里由訂單訪問會員,會因為域名不同而導致跨域問題。跨域問題的解決方案可以使用http client設置、設置請求頭、nginx轉發解決,那么在SpringCloud里面當然提供了一套解決方案,那就是網關ZUUL。
如圖所示,當一個客戶端如果直接訪問時,會因為域名不同導致跨域問題。而我們所需要做的就是在前面設置一個網關變成my.com/vip my.com/order,這樣就不會產生跨域的問題。接下來我們來設置zuul。
第一步首先也要注冊進eureka,導入依賴。
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-zuul
</artifactId>
-
</dependency>
第二步配置yml文件..
-
#注冊進eureka
-
eureka:
-
client:
-
serviceUrl:
-
defaultZone: http:
//localhost:8888/eureka/
-
#配置網關端口號
-
server:
-
port:
8080
-
spring:
-
application:
-
name: zuul-server
-
#配置網關轉發詳情
-
zuul:
-
routes:
-
api-a:
-
path: /member
/**
-
service-id: member-server
-
api-b:
-
path: /order/**
-
service-id: order-server
-
// 開啟網關
-
@EnableZuulProxy
-
@SpringBootApplication
-
public
class DemoApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(DemoApplication.class, args);
-
}
-
-
}
訪問配置的網關地址8080,調用member-server里的方法,成功!還可以使用網關過濾信息。具體怎樣過濾不做贅述。
五、 斷路器(Hystrix)
為什么需要 Hystrix?
在微服務架構中,我們將業務拆分成一個個的服務,服務與服務之間可以相互調用(RPC)。為了保證其高可用,單個服務又必須集群部署。由於網絡原因或者自身的原因,服務並不能保證服務的100%可用,如果單個服務出現問題,調用這個服務就會出現網絡延遲,此時若有大量的網絡涌入,會形成任務累計,導致服務癱瘓,甚至導致服務“雪崩”。為了解決這個問題,就出現斷路器模型。
什么是服務雪崩
分布式系統中經常會出現某個基礎服務不可用造成整個系統不可用的情況, 這種現象被稱為服務雪崩效應. 為了應對服務雪崩, 一種常見的做法是手動服務降級. 而Hystrix的出現,給我們提供了另一種選擇.
通俗來說: 就是對一個方法的PRC調用並發數量太大
服務雪崩應對策略
針對造成服務雪崩的不同原因, 可以使用不同的應對策略:
1. 流量控制
2. 改進緩存模式
3. 服務自動擴容
服務調用者降級服務
流量控制 的具體措施包括:
·網關限流
·用戶交互限流
·關閉重試
什么是服務降級
所有的RPC技術里面服務降級是一個最為重要的話題,所謂的降級指的是當服務的提供方不可使用的時候,程序不會出現異常,而會出現本地的操作調用。
通俗解釋來說:就是上面例子里的會員系統訪問訂單系統,執行遠程RPC調用方法,但是當達到一定並發量的時候,比如200個人同時訪問 orderTest()方法時,tomcat的容量設置的只有150個,剩余的50個人就在外面等待一直等待。服務降級就是不讓他們一直等待,調用本地的方法來fallback消息。而不再去PRC方法。
Hystrix的作用
1.斷路器機制
斷路器很好理解, 當Hystrix Command請求后端服務失敗數量超過一定比例(默認50%), 斷路器會切換到開路狀態(Open). 這時所有請求會直接失敗而不會發送到后端服務. 斷路器保持在開路狀態一段時間后(默認5秒), 自動切換到半開路狀態(HALF-OPEN). 這時會判斷下一次請求的返回情況, 如果請求成功, 斷路器切回閉路狀態(CLOSED), 否則重新切換到開路狀態(OPEN). Hystrix的斷路器就像我們家庭電路中的保險絲, 一旦后端服務不可用, 斷路器會直接切斷請求鏈, 避免發送大量無效請求影響系統吞吐量, 並且斷路器有自我檢測並恢復的能力.
2.Fallback
Fallback相當於是降級操作. 對於查詢操作, 我們可以實現一個fallback方法, 當請求后端服務出現異常的時候, 可以使用fallback方法返回的值. fallback方法的返回值一般是設置的默認值或者來自緩存.
3.資源隔離
在Hystrix中, 主要通過線程池來實現資源隔離. 通常在使用的時候我們會根據調用的遠程服務划分出多個線程池. 例如調用產品服務的Command放入A線程池, 調用賬戶服務的Command放入B線程池. 這樣做的主要優點是運行環境被隔離開了. 這樣就算調用服務的代碼存在bug或者由於其他原因導致自己所在線程池被耗盡時, 不會對系統的其他服務造成影響. 但是帶來的代價就是維護多個線程池會對系統帶來額外的性能開銷. 如果是對性能有嚴格要求而且確信自己調用服務的客戶端代碼不會出問題的話, 可以使用Hystrix的信號模式(Semaphores)來隔離資源.
第一步首先是導入依賴
-
<dependency>
-
<groupId>org.springframework.cloud
</groupId>
-
<artifactId>spring-cloud-starter-hystrix
</artifactId>
-
</dependency>
Rest方式調用
-
@HystrixCommand(fallbackMethod =
"testError")
-
@RequestMapping(
"/memTest")
-
public String memTest(){
-
String str = restTemplate.getForObject(
"http://order-server/orderTest",String.class);
-
return str;
-
}
-
public String testError(){
-
//遠程調用失敗,調用此方法
-
}
-
-
-
//啟動方式
-
@EnableEurekaClient
-
@EnableHystrix
-
@SpringBootApplication
-
public
class MemApp {
-
-
public static void main(String[] args) {
-
SpringApplication.run(OrderApp.class, args);
-
}
Fegin方式調用
yml文件新增配置
feign:
hystrix:
enabled: true
注冊一個繼承了Fegin接口的類到Spring容器中
-
@Component
-
public
class MemberFeignService implements orderFeign {
-
-
public String errorMsg {
-
return
"出錯啦";
-
}
-
}
-
-
@Service
-
@FeignClient(
"order-server",fallback=MemberFeignService.class)
-
public
interface orderFeign {
-
@RequestMapping(
"/orderTest")
-
public String orderTest();
-
}
所以整個流程就是並發訪問量太大導致服務雪崩。然后出發PRC的熔斷機制。最后會根據情況來進行隔離資源。
另外安利一個學習教程:Spring Cloud快速入門教程
分享一個it資源平台:點擊進入