SpringCloud學習筆記(一) 搭建一個SpringCloud
簡介
摘自百度百科:
SpringCloud是一系列框架的有序集合。它利用SpringBoot的開發便利性巧妙地簡化了分散式系統基礎設施的開發,如服務發現註冊、配置中心、訊息匯流排、負載均衡、斷路器、資料監控等,都可以用SpringBoot的開發風格做到一鍵啟動和部署。SpringCloud並沒有重複製造輪子,它只是將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過SpringBoot風格進行再封裝遮蔽掉了複雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分散式系統開發工具包。
反正SpringCloud是一個用來做微服務的框架,主要是基於SpringBoot來完成的,相關的微服務框架還有比較出名的Dubbo和DubboX。關於微服務是用來做什麼的,有什麼好處自行百度。
SpringCloud是Spring全家桶中的一員,所以SpringCloud對於Spring的其他元件都有著很好的支援。
SpringCloud主要採用的Eureka,Dubbo主要採用的是zookeeper。
上程式碼
provider 服務提供者
直接新建一個SpringBoot專案,由於是為了示例,本次示例中不使用資料庫,只引入了spring-boot-starter-web
專案及其簡單,只暴露了一個介面,用於測試,yml檔案只配置了埠號為7900
consumer 服務消費者
同樣新建一個SpringBoot專案,使其呼叫consumer的介面,同樣只引入了spring-boot-starter-web
,yml檔案只是修改了埠號為7910。
這裡解釋一下RestTemplates
這個類,關於這個類,這個老哥https://blog.csdn.net/u012702547/article/details/77917939的解釋我覺得非常完整了,RestTemplates
在SpringCloud中,消費者通過這個類訪問生產者,@bean
註解是為了例項化這個類,例項化之後通過@AutoWired
註解引入,將其交給Spring進行管理。
分別啟動兩個類,分別訪問localhost:7900/provider/demo
和http://localhost:7910/consumer/demo
應該都能得到ProviderDemo這個結果,說明consumer成功呼叫了provider中的方法。
問題:
這樣的編碼方式是將介面(http://localhost:7900/provider/demo
)硬編碼在程式碼中,但是專案釋出之後,ip地址必然是變動的。而且,硬編碼的方式肯定是無法實現負載均衡的,就是說如果同時啟動多個provider服務,這種硬編碼方式是無法根據負載均衡策略去呼叫服務的。
解決方法:
在Dubbo中使用的ZooKeeper作為服務註冊與發現的容器,在Springcloud中使用的是Eureka作為服務註冊與發現的容器。
Eureka
同樣建立一個SPringBoot專案,下面是pom.xml
檔案,我是在idea中直接新增spring-cloud-starter-netflix-eureka-server
這個依賴的。
<?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>cn.edu.nuaa</groupId>
<artifactId>eureka-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-demo</name>
<description>eureka-demo</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</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>
</project>
然後在Springboot的啟動類上新增@EnableEurekaServer
或者@EnableDiscoveryClient
,這兩個註解的註解的區別主要是:
@EnableEurekaServer
是基於 spring-cloud-netflix依賴,只能為eureka作用,是專門給Eureka用的
@EnableDiscoveryClient
是基於 spring-cloud-commons依賴,並且在classpath中實現,是給比如zookeeper、consul使用的,
舊版本的@EnableEurekaServer
的原始碼上面也是也是有@EnableDiscoveryClient
註解的。
本示例是使用Eureka的,故推薦使用@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaDemoApplication.class, args);
}
}
然後在yml檔案中配置如下資訊:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
這個埠號官網設定成8761,這裡也設定成8761;
`register-with-eureka: false
這個的預設值為true,設定為true不會對使用不會有很大的影響,但是在啟動的時候會保下面的錯誤:
was unable to refresh its cache! status = Cannot execute request on any known server
是因為啟動的時候自己註冊了自己而引起的衝突
defaultZone配置eureka的地址,這個如果有多個註冊中心,則用逗號隔開。
為了服務註冊中心的安全考慮,很多時候我們都會為服務註冊中心加入安全認證。通常與SpringSecurity整合,主要是SpringSecurity的內容,這裡不做討論(主要是我自己嘗試的時候失敗了,啊哈哈哈)。
配置資訊完成之後,啟動eureka專案,訪問localhost:8761
便可以得到下面的介面,目前上面兩個寫的provider和consumer還沒有註冊到該註冊中心:
關於Eureka配置的含義及其預設值主要參考下表:
服務註冊類配置
省略了eureka.client字首
引數名 | 說明 | 預設值 |
---|---|---|
enabled | 啟用Eureka客戶端 | true |
registryFetchIntervalSeconds | 從Eureka服務端獲取註冊資訊的間隔時間,單位為秒 | 30 |
instanceInfoReplicationIntervalSeconds | 更新例項資訊的變化到Eureka服務端的間隔時間,單位為秒 | 30 |
initialInstanceInfoReplicationIntervalSeconds | 初始化例項資訊到Eureka服務端的間隔時間,單位為秒 | 40 |
eurekaServiceUrlPollIntervalSeconds | 輪詢Eureka服務端地址更改的間隔時間,單位為秒。當我們與Spring CLoud Config整合,動態重新整理Eureka的serviceURL地址時需要關注該引數 | 300 |
eurekaServerReadTimeoutSeconds | 讀取Eureka Server資訊的超時時間,單位為秒 | 8 |
eurekaServerConnectTimeoutSeconds | 連結Eureka Server的超時時間,單位為秒 | 5 |
eurekaServerTotalConnections | 從Eureka客戶端到所有Eureka服務端的連線總數 | 200 |
eurekaServerTotalConnectionsPerHost | 從Eureka客戶端到每個Eureka服務端主機的連線總數 | 50 |
eurekaConnectionIdleTimeoutSeconds | Eureka服務端連線的空閒關閉時間,單位為秒 | 30 |
heartbeatExecutorThreadPoolSize | 心跳連線池的初始化執行緒數 | 2 |
heartbeatExecutorExponentialBackOffBound | 心跳超時重試延遲時間的最大乘數值 | 10 |
cacheRefreshExecutorThreadPoolSize | 快取重新整理執行緒池的初始化執行緒數 | 2 |
cacheRefreshExecutorExponentialBackOffBound | 快取重新整理重試延遲時間的最大乘數值 | 10 |
useDnsForFetchingServiceUrls | 使用DNS來獲取Eureka服務端的serviceUrl | false |
registerWithEureka | 是否要將自身的例項資訊註冊到Eureka服務端 | true |
preferSameZoneEureka | 是否偏好使用處於相同Zone的Eureka服務端 | true |
filterOnlyUpInstances | 獲取例項時是否過濾,僅保留UP狀態的例項 | true |
fetchRegistry | 是否從Eureka服務端獲取註冊資訊 | true |
服務例項類配置
eureka.instance.instanceId
為例項的id,可以自定義,預設值為
${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}
省略了eureka.instance為字首
引數名 | 說明 | 預設值 |
---|---|---|
preferIpAddress | 是否優先使用IP地址作為主機名的標識 | false |
leaseRenewalIntervalInSeconds | Eureka客戶端向服務端傳送心跳的時間間隔,單位為秒 | 30 |
leaseExpirationDurationInSeconds | Eureka服務端在收到最後一次心跳之後等待的時間上限,單位為秒。超過該時間之後服務端會將該服務例項從服務清單中剔除,從而禁止服務呼叫請求被髮送到該例項上 | 90 |
nonSecurePort | 非安全的通訊埠號 | 80 |
securePort | 安全的通訊埠號 | 443 |
nonSecurePortEnabled | 是否啟用非安全的通訊埠號 | true |
securePortEnabled | 是否啟用安全的通訊埠號 | |
appname | 服務名,預設取spring.application.name的配置值,如果沒有則為unknown | |
hostname | 主機名,不配置的時候講根據作業系統的主機名來獲取 |
註冊服務到Eureka
回到之前寫的provider-demo專案中,在專案中新增下面這個依賴,注意version:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>RELEASE</version>
</dependency>
- /ul>
在之前的SpringCloud版本中,還有出現過下面的依賴,但是目前最新的版本是上面這個,親測,在本示例中兩個都是可以的。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>RELEASE</version>
</dependency>
然後在專案的啟動類上新增@EnableEurekaClient
註解
@SpringBootApplication
@EnableEurekaClient
public class ProviderDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderDemoApplication.class, args);
}
}
從依賴的名字spring-cloud-starter-netflix-eureka-client
的名字就知道這個依賴是用來做eureka的客戶端,然後註冊服務到eureka上的。然後在專案的啟動類上的新增的註解為@EnableEurekaClient
回到上文中會發現搭建eureka註冊中心的時候會發現引入的包是spring-cloud-starter-netflix-eureka-server
,在專案的啟動類上的新增的註解為@EnableEurekaServer
還是很好記憶和理解的。
最後在yml檔案中新增上eureka註冊中心的地址並可以了:
server:
port: 7900
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
分別啟動一下eureka和provider專案,然後訪問一下localhost:8761
便會得到下面的頁面:
可以看到provider的服務已經註冊上eureka上了。
發現application的名稱為UNKNOWN,可以在yml檔案中新增下面內容修改名字:
spring:
application:
name: provider-demo
重啟一下服務便可以看到名字,這裡就不貼圖片了。
有可能會遇到下面的紅色字型:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
這個主要是eureka的自我保護的心跳機制導致的,即如果真實的服務已經Down掉,但在註冊中心介面服務卻一直存在,且顯示為UP狀態。解決方法可以新增下面內容,上面有eureka的配置資訊中解釋含義:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
lease-renewal-interval-in-seconds: 1
lease-expiration-duration-in-seconds: 2
服務監控
對於服務的眾多資訊可能都需要監控和監聽,SpringCloud主要採用的是下面這個依賴對其實現監聽的:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
新增這個依賴之後重啟服務會發現console中多了下圖這幾個端點:
/actuator/health和/actuator/info以及/actuator這三個就是actuator提供的端點,注意以前的版本是沒有/actuator字首的,2.0以後的版本都加了/actuator字首。可以訪問localhost:7900/actuator
嘗試看監聽的都是一些什麼內容
如果要開啟全部的監聽端點,可以在yml檔案中加入下面的配置資訊:
management:
endpoints:
web:
exposure:
include: "*"
重啟服務便可以看到所有的端點都開啟用了。
主要的端點的含義可以參考下面的表格:
端點 | 描述 |
---|---|
actuator | 為其他端點提供“發現頁面”。要求Spring HATEOAS在classpath路徑上。 |
auditevents | 陳列當前應用程式的審計事件資訊。 |
autoconfig | 展示自動配置資訊並且顯示所有自動配置候選人以及他們“被不被”應用的原因。 |
beans | 顯示應用程式中所有Spring bean的完整列表。 |
configprops | 顯示所有配置資訊。 |
dump | dump所有執行緒。 |
env | 陳列所有的環境變數。 |
flyway | Shows any Flyway database migrations that have been applied. |
health | 顯示應用程式執行狀況資訊 |
info | 顯示應用資訊。 |
loggers | 顯示和修改應用程式中的loggers配置。 |
liquibase | 顯示已經應用的任何Liquibase資料庫遷移。 |
metrics | 顯示當前應用程式的“指標”資訊。 |
mappings | 顯示所有@RequestMapping的url整理列表。 |
shutdown | 關閉應用(預設情況下不啟用)。 |
trace | 顯示跟蹤資訊(預設最後100個HTTP請求)。 |
使用同樣的方法把consumer-demo一起註冊到Eureka上。
ribbon
上文只是將服務註冊到eureka上,但是consumer還是硬編碼呼叫,前文也有提到這種硬編碼方式肯定是不合理的,一來服務上線之後,IP地址肯定是變動的, 再則,採用硬編碼的方式是無法實現負載均衡的。
ribbon便是一個用來做負載均衡的元件。
點進spring-cloud-starter-netflix-eureka-client
依賴,會發現,這個依賴中已經新增了spring-cloud-starter-netflix-ribbon
,故在專案中可以直接使用ribbon,不用重新新增依賴。
在載入restTemplates的方法上新增@LoadBalanced
註解,使其具有負載均衡的能力,然後將硬編碼的ip地址換成服務提供者的應用名字(application.name
屬性的值),修改之後controller便變成了下面的樣子,其他地方不做修改。
@RestController
public class ConsumerController {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/consumer/demo")
public String ConsumerDemo(){
return this.restTemplate.getForObject("http://provider-demo:7900/provider/demo", String.class);
}
}
重啟一下Eureka,provider-demo,consumer-demo,分別訪問localhost:7900/provider/demo
和http://localhost:7910/consumer/demo
應該都能得到ProviderDemo 這個結果,說明consumer成功呼叫了provider中的方法。便解決了不採用硬編碼的方式,使得consumer-demo呼叫provider-demo介面。
ribbon預設的負載均衡策略是輪詢的。測試一下:
首先啟動多個provider-demo專案,我這裡分別用的介面是7900和7901兩個介面,可以在Eureka中看一下provider的資訊:
然後在consumer-demo專案的controller中新增下面的內容,程式碼應該很容易看懂就是模擬loadBalancerClient
客戶端來訪問名字為provider-demo
的服務介面,然後輸出訪問的介面埠號。
@Autowired
private LoadBalancerClient loadBalancerClient;
@RequestMapping("/consumer/getInterfaceInfo")
public void getInterfaceInfo(){
ServiceInstance choose = loadBalancerClient.choose("provider-demo");
System.out.println(choose.getPort());
}
然後分別訪問一下多次訪問localhost:7910//consumer/getInterfaceInfo
這個URL,可以看到控制檯輸出的資訊在下面,很容易看出是輪詢。
ribbon有多種修改負載均衡的策略,可以通過程式碼,也可以通過配置檔案,個人覺得配置檔案的方法比較方便,其他的方法可以自行百度:
在consumer-demo的application.yml
檔案中新增下面的內容,這裡使用的是隨機的策略,該測試就不貼圖了,反正最後結果是隨機的:
#服務提供者的名字
provider-demo:
ribbon:
# 所要採用的策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ribbon所有的策略可以參照下表:
策略名 | 策略描述 | 實現說明 |
---|---|---|
BestAvailableRule | 選擇一個最小的併發請求的server | 逐個考察Server,如果Server被tripped了,則忽略,在選擇其中ActiveRequestsCount最小的server |
AvailabilityFilteringRule | 過濾掉那些因為一直連線失敗的被標記為circuit tripped的後端server,並過濾掉那些高併發的的後端server(active connections 超過配置的閾值) | 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status裡記錄的各個server的執行狀態 |
WeightedResponseTimeRule | 根據響應時間分配一個weight,響應時間越長,weight越小,被選中的可能性越低。 | 一個後臺執行緒定期的從status裡面讀取評價響應時間,為每個server計算一個weight。Weight的計算也比較簡單responsetime 減去每個server自己平均的responsetime是server的權重。當剛開始執行,沒有形成status時,使用roubine策略選擇server。 |
RetryRule | 對選定的負載均衡策略機上重試機制。 | 在一個配置時間段內當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server |
RoundRobinRule | roundRobin方式輪詢選擇server | 輪詢index,選擇index對應位置的server |
RandomRule | 隨機選擇一個server | 在index上隨機,選擇index對應位置的server |
ZoneAvoidanceRule | 複合判斷server所在區域的效能和server的可用性選擇server | 使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的執行效能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用於過濾掉連線數過多的Server。 |
相關文章
- springcloud學習筆記(一)Spring Cloud EurekaSpringGCCloud筆記
- SpringCloud學習筆記:SpringCloud簡介(1)SpringGCCloud筆記
- SpringCloud學習之路(一)- 走進SpringCloudSpringGCCloud
- 【SpringCloud】黑馬學習筆記-NacosSpringGCCloud筆記
- SpringCloud學習系列之一 ----- 搭建一個高可用的註冊中心(Eureka)SpringGCCloud
- springcloud學習(一)之EurekaSpringGCCloud
- springcloud學習筆記(二)Spring Cloud FeignSpringGCCloud筆記
- springcloud學習筆記(三)Spring Cloud RibbonSpringGCCloud筆記
- springcloud學習筆記(四)Spring Cloud HystrixSpringGCCloud筆記
- springcloud學習筆記(五)Spring Cloud ActuatorSpringGCCloud筆記
- springcloud學習筆記(六)Spring Cloud ZuulSpringGCCloud筆記Zuul
- SpringCloud學習筆記:宣告式呼叫Feign(4)SpringGCCloud筆記
- SpringCloud學習筆記:熔斷器Hystrix(5)SpringGCCloud筆記
- springCloud學習筆記2(服務發現)SpringGCCloud筆記
- SpringCloud學習筆記:負載均衡Ribbon(3)SpringGCCloud筆記負載
- springcloud使用筆記SpringGCCloud筆記
- springcloud學習SpringGCCloud
- Springcloud學習筆記64---Oss Amazon s3SpringGCCloud筆記S3
- SpringCloud基礎概念學習筆記(Eureka、Ribbon、Feign、Zuul)SpringGCCloud筆記Zuul
- 從零搭建一個SpringCloud專案之Config(五)SpringGCCloud
- 每天學點SpringCloud(一):使用SpringBoot2.0.3整合SpringCloudGCCloudSpring Boot
- Springcloud學習筆記68--springboot 整合Caffeine 本地快取GCCloud筆記Spring Boot快取
- Springcloud原始碼學習筆記1—— Zuul閘道器原理SpringGCCloud原始碼筆記Zuul
- ZooKeeper學習筆記一:叢集搭建筆記
- SpringCloud系列(一)SpringGCCloud
- SpringCloud (一) EurekaSpringGCCloud
- Springcloud學習筆記62---log.error()列印內容區別SpringGCCloud筆記Error
- SpringCloud學習筆記:服務註冊與發現Eureka(2)SpringGCCloud筆記
- SpringCloud 學習總結SpringGCCloud
- SpringCloud Alibaba開篇:SpringCloud這麼火,為何還要學習SpringCloud Alibaba?SpringGCCloud
- SpringCloud Alibaba (一):序言SpringGCCloud
- 如何簡潔高效的搭建一個SpringCloud2023的maven工程SpringGCCloudMaven
- Dockerfile 與 Compose 環境搭建學習筆記(一)Docker筆記
- 學習筆記(一)筆記
- SpringCloud第而部分以及SpringCloudAlibaba筆記SpringGCCloud筆記
- Flutter 學習筆記(一):第一個 Flutter 應用Flutter筆記
- 分享一個 SpringCloud Feign 中所埋藏的坑SpringGCCloud
- Web 開發學習筆記(1) — 搭建你的第一個 Web ServerWeb筆記Server