一.簡介
1.SpringCloud
SpringCloud是一套微服務開發(fā)一站式解決方案挣磨,它提供了微服務開發(fā)所需要的很多功能組件金蜀,
比如服務統(tǒng)一管理、配置統(tǒng)一管理吃靠、路由網關硫眨、斷路器、事件總線巢块、集群狀態(tài)配置等等礁阁。而且
SpringCloud與SpringBoot無縫銜接,配合SpringBoot能夠更輕松的搭建出一套微服務架構平
臺族奢。
2.微服務
微服務其實是一種架構的設計風格姥闭,并沒有明確的技術綁定和架構概念。簡單來說越走,微服務架構
風格其實就是將原來的單一架構開發(fā)為一組小型服務(微服務)的方法棚品,每個服務都運行在自己
獨立的進程中(服務間的隔離),服務間采用輕量級的通訊機制(HTTP廊敌、RPC - Netty铜跑、 WebService),這些服務按照業(yè)務拆分骡澈,并且獨立部署(自動化部署)锅纺。服務會由一個統(tǒng)一的管
理中心管理(Zookeeper、Eureka肋殴、Nacos)囤锉,服務可以采用不同的語言開發(fā),并且使用不同
的存儲技術(數(shù)據(jù)庫垂直拆分)护锤。
二.服務的注冊與發(fā)現(xiàn)--Eureka
1.注冊中心
注冊中心的作用就是為了減少服務間的調用耦合
2.Eureka
(1)Eureka是Netflix開發(fā)的服務發(fā)現(xiàn)框架官地,本身是一個基于REST的服務,主要用于定位運行在AWS域中的中間層服務烙懦,以達到負載均衡和中間層服務故障轉移的目的驱入。SpringCloud將它集成在其子項目spring-cloud-netflix中,以實現(xiàn)SpringCloud的服務發(fā)現(xiàn)功能修陡。
(2)Eureka包含兩個組件:Eureka Server和Eureka Client。
(3)Eureka Server提供服務注冊服務可霎,各個節(jié)點啟動后魄鸦,會在Eureka Server中進行注冊,這樣EurekaServer中的服務注冊表中將會存儲所有可用服務節(jié)點的信息癣朗,服務節(jié)點的信息可以在界面中直觀的看到拾因。
(4)Eureka Client是一個java客戶端,用于簡化與Eureka Server的交互,客戶端同時也就是一個內置的绢记、使用輪詢(round-robin)負載算法的負載均衡器扁达。
(5)在應用啟動后,將會向Eureka Server發(fā)送心跳,默認周期為30秒蠢熄,如果Eureka Server在多個心跳周期內沒有接收到某個節(jié)點的心跳跪解,Eureka Server將會從服務注冊表中把這個服務節(jié)點移除(默認90秒)。
Eureka Server之間通過復制的方式完成數(shù)據(jù)的同步签孔,Eureka還提供了客戶端緩存機制叉讥,即使所有的Eureka Server都掛掉,客戶端依然可以利用緩存中的信息消費其他服務的API饥追。綜上图仓,Eureka通過心跳檢查、客戶端緩存等機制但绕,確保了系統(tǒng)的高可用性救崔、靈活性和可伸縮性。
3.Eureka 對比 Zookeeper
(1)zookeeper可以獨立運行,但是Eureka不可以獨立運行,需要依賴web服務,tomcat
(2)zookeeper的分布式服務中存在著角色的關系,有服務的提供者與消費者,但是Eureka每個微服務既是消費者,也是服務的提供者.
4.Eureka服務端的搭建
(1)配置自定義的父工程(繼承SpringBoot捏顺、SpringCloud)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>springcloud_Eureka</module>
<module>springcloud_microservice_student</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>nz.study</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- <name>springcloud_demo</name>
<description>Demo project for Spring Boot</description>-->
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
</properties>
<!-- 相當于讓當前得工程繼承了SpringCloud的父工程,用這種方式可以實現(xiàn)Maven的多繼承 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<!--導入pom工程,相當于多繼承-->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 只有微服務才要依賴<build> -->
<!-- <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>-->
</project>
(2)創(chuàng)建Eureka服務
1)創(chuàng)建一個Maven工程(Eureka微服務)六孵,繼承自定義的父工程(springcloud_demo)
2)修改當前maven工程的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">
<parent>
<artifactId>springcloud_demo</artifactId>
<groupId>nz.study</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud_Eureka</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3)配置當前springboot的啟動類
package nz.study.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
//run方法的第一個參數(shù)是添加了@SpringBootApplication注解的類
//不是當前類
SpringApplication.run(EurekaServerApplication.class,args);
}
}
4)配置application.yml
server:
port: 20000
spring:
application:
#配置微服務的名稱,以后所有的微服務,都必須配置這個屬性,不然注冊中心的名稱會變成unable
name: eureka-server
#配置eureka的相關屬性
eureka:
client:
service-url:
#配置eureka的注冊地址
#defaultZone沒有提示,必須手寫
defaultZone: http://eureka1:20000/eureka,http://eureka2:20001/eureka,http://eureka3:20002/eureka
#當前的微服務就是注冊中心,注冊中心不能從注冊中心抓取服務,所以該配置需要配置成false
fetch-registry: false
#使得當前微服務不注冊到注冊中心
register-with-eureka: false
5)啟動SpringBoot工程 - 啟動Eureka服務端
6)訪問注冊中心,http://localhost:20000
5.微服務(Eureka客戶端)的搭建
(1)Eureka客戶端的搭建
- 創(chuàng)建一個Maven工程草丧,繼承springcloud_demo工程
- 配置Maven工程的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">
<parent>
<artifactId>springcloud_demo</artifactId>
<groupId>nz.study</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud_microservice_student</artifactId>
<dependencies>
<!-- 微服務需要對外提供功能,所以需要添加web依賴 -->
<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-client</artifactId>
</dependency>
</dependencies>
<!-- 打包插件,不寫不影響運行,但是打包會出問題 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 配置啟動類
package nz.study.student;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication(scanBasePackages = "nz.study")
//springcloud 2.x 之后 該注解可以省略
@EnableEurekaClient
public class StudentApplication {
public static void main(String[] args) {
SpringApplication.run(StudentApplication.class,args);
}
}
- 配置application.yml
server:
port: 8080
#微服務的名稱
spring:
application:
#特別注意:微服務的名稱一定不要用下劃線
name: micro-student
eureka:
client:
service-url:
#配置注冊中心的地址,因為微服務需要注冊,也需要抓取服務所以另兩個配置默認為true,可以不用配置.
defaultZone: http://localhost:20000/eureka
- 編寫微服務的功能接口(根據(jù)微服務本身的業(yè)務不同狸臣,編寫不同的接口)
package nz.study.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stu")
public class StuController {
/**
* 根據(jù)學生id查詢學生姓名
*
* @RequestBody -> 返回json (×)
*
* @RequestBody -> 將方法的返回值,放入response響應體中
*
* 響應體 -> 數(shù)值,字符串(json),二進制流,...
*
* @param sid
* @return
*/
@RequestMapping("/queryName")
public String getNameById(Integer sid){
switch (sid){
case 1:
return "小紅";
case 2:
return "小明";
case 3:
return "小剛";
default:
return "查無此人";
}
}
}
三.Eureka集群(偽)
1.eureka集群的工作模式
2.Eureka集群的搭建(偽集群)
1)將eureka服務端復制2份
2)修改eureka服務的端口(因為是偽集群,在一臺機器上昌执,需要修改端口)
3)找到本機的hosts文件(C:\Windows\System32\drivers\etc\hosts),分別給本機設置3個主機名
注意:第一次修改hosts文件烛亦,一般沒有權限,所以需要修改下文件權限懂拾。
4)修改3個eureka服務的service-url配置
server:
port: 20002
spring:
application:
#配置微服務的名稱,以后所有的微服務,都必須配置這個屬性,不然注冊中心的名稱會變成unable
name: eureka-server
#配置eureka的相關屬性
eureka:
client:
service-url:
#配置eureka的注冊地址
#defaultZone沒有提示,必須手寫
defaultZone: http://eureka1:20000/eureka,http://eureka2:20001/eureka,http://eureka3:20002/eureka
#當前的微服務就是注冊中心,注冊中心不能從注冊中心抓取服務,所以該配置需要配置成false
fetch-registry: false
#使得當前微服務不注冊到注冊中心
register-with-eureka: false
5)啟動三臺eureka服務
6)所有的微服務的注冊地址必須改成eureka集群的地址
server:
port: 8080
#微服務的名稱
spring:
application:
#特別注意:微服務的名稱一定不要用下劃線
name: micro-student
eureka:
client:
service-url:
#配置注冊中心的地址,因為微服務需要注冊,也需要抓取服務所以另兩個配置默認為true,可以不用配置.
defaultZone: http://eureka1:20000/eureka,http://eureka2:20001/eureka,http://eureka3:20002/eureka
四.Eureka的自我保護機制
1.自我保護機制
Eureka如果收到的微服務心跳相對于應該收到的微服務心跳來說煤禽,如果低于了85%,那么就會觸
發(fā)Eureka的自我保護機制岖赋。一旦自我保護機制啟動檬果,Eureka會保護所有的微服務,不被移除唐断,哪
怕當前微服務已經下線选脊,仍然會保留到Eureka微服務列表中。
2.Eureka自我保護機制觸發(fā)后的表現(xiàn)
3. 自我保護機制的作用
(1)為什么Eureka要一種看起來如此傻逼的設計脸甘?- 自我保護機制是為了保證微服務間的高可用性恳啥,
避免腦裂的影響
(2)為什么Zookeeper要設計一個過半數(shù)存活原則?感覺特別浪費資源丹诀? - 為了讓整個集群一定只有
一個Leader
(3)CAP原則:任何一個分布式系統(tǒng)钝的,都只能滿足CAP中的2個原則翁垂,因為分區(qū)問題不可避免,所以P
是必選的硝桩,一般的系統(tǒng)沿猜,都是從C和A中做選擇。Zookeeper是CP設計碗脊,而Eureka是AP設計啼肩。
C(一致性)
A(可用性)
P(分區(qū)容錯性)
4.zookeeper的過半數(shù)存活的設計
5.Eureka的自我保護設計
6.總結
自我保護機制一旦啟動,確實會保護那些真的出問題的微服務望薄,所以Eureka設計了一個閾值疟游,當
15%的心跳都丟失的時候,才會發(fā)生自我保護機制痕支。因為這個時候颁虐,相對于15%的機器掛掉來
說,發(fā)生腦裂的概率大一些卧须。但是有沒有可能真的是15%機器掛掉了另绩?這個時候Eureka是不能幫
我們判斷的,需要客戶端本身有一定的容錯機制花嘶,比如斷路器
7.在實際項目中,到底是AP設計好,還是CP設計好?
取決于業(yè)務笋籽,對于注冊中心來說,偶爾拿到出問題的微服務椭员,其實對于整個架構來講沒有太大問題车海,微服務架構最害怕整個注冊中心服務不可用,因此對于注冊中心來說隘击,AP(高可用)設計強于CP(一致性)設計侍芝。并不是說一致性不好,對于分布式鎖的業(yè)務來講埋同,一定要CP州叠,不然整個集群的業(yè)務會混亂.