Spring cloud是一個基於Spring Boot實現的服務治理工具包,在微服務架構中用於管理和協調服務的。
組成部分

spingcloud的五大神獸
服務發現——Netflix Eureka
客服端負載均衡——Netflix Ribbon/Feign
服務網關——Netflix Zuul
斷路器——Netflix Hystrix
分布式配置——Spring Cloud Config
Spring cloud入門-搭建環境
1)建環境
以maven多模塊化的方法搭建
2)注冊中心
由於Spring Cloud為服務治理做了一層抽象接口,所以在Spring Cloud應用中可以支持多種不同的服務治理框架,比如:Netflix Eureka、Consul、Zookeeper。在Spring Cloud服務治理抽象層的作用下,我們可以無縫地切換服務治理實現,並且不影響任何其他的服務注冊、服務發現、服務調用等邏輯。
3)服務提供者
4)服務消費者

1.1. 搭建環境pxm.xml配置
<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.SR1</spring-cloud.version>
<springboot.version>2.0.5.RELEASE</springboot.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
-
Spring cloud入門-Eureka注冊中心
-
由於Spring Cloud為服務治理做了一層抽象接口,所以在Spring Cloud應用中可以支持多種不同的服務治理框架,比如:Netflix Eureka、Consul、Zookeeper。在Spring Cloud服務治理抽象層的作用下,我們可以無縫地切換服務治理實現,並且不影響任何其他的服務注冊、服務發現、服務調用等邏輯。
Eureka是netflix的一個子模塊,也是核心模塊之一,Eureka是一個基於REST的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務注冊與發現對於微服務架構來說是非常重要的,有了 服務發現和注冊,只需要使用服務的標識符,就可以訪問到服務,而不需要修改服務,而不需要修改服務調用的配置文件了,功能類似於dubbo的注冊中心,比如zookeeper。
原理

三大角色:
Eureka server提供服務注冊和發現
Eureka Server提供服務注冊服務。各個服務提供者節點啟動后,會在Eureka Server中進行注冊,這樣Eureka server中的服務注冊表中將會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀的看到
Service Provider服務提供方將自身服務注冊到Eureka,從而使服務消費方能夠找到。
Service Consumer服務消費方從Eureka獲取注冊服務列表,從而能夠消費服務。
Eureka client是一個java客戶端,用於簡化eureka server的交互,在應用啟動后,將會向Eureka Server發送心跳。如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳,Eureka Server將會從服務注冊表把這個服務節點移除。
注冊中心的搭建
創建一個普通maven項目
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> </dependency> <!--Eureka服務端支持--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
yum配置
server: port: 7001 eureka: instance: hostname: localhost client: registerWithEureka: false #是否要注冊到eureka fetchRegistry: false #表示是否從Eureka Server獲取注冊信息 serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #單機配置
主類
@SpringBootApplication @EnableEurekaServer//標識是eureka服務端 public class EnrekaServerApplication_7001 { public static void main(String[] args) { SpringApplication.run(EnrekaServerApplication_7001.class); } }
注意事項
自我保護引發的錯誤

Eureka Server 在運行期間會去統計心跳失敗比例在 15 分鍾之內是否低於 85%,如果低於 85%,Eureka Server 會將這些實例保護起來,讓這些實例不會過期,但是在保護期內如果服務剛好這個服務提供者非正常下線了,此時服務消費者就會拿到一個無效的服務實例,此時會調用失敗,對於這個問題需要服務消費者端要有一些容錯機制,如重試,斷路器等
搭建服務提供者
在搭建服務提供者模塊之前我們要創建一個模塊,這個模塊是公共模塊,用來存放工共的數據
然后就是創建服務提供者,
pom.xml配置
<dependencies> <!--公共代碼依賴--> <dependency> <groupId>cn.itsource.springcloud</groupId> <artifactId>User_interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--springboot支持--> <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> </dependency> <!--eureka客戶端支持 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
yum配置
server: port: 8001 spring: application: name: USER-PROVIDER #不要使用下划線 eureka: client: service-url: defaultZone: http://localhost:7001/eureka #告訴服務提供者要把服務注冊到哪兒
程序主方法
@SpringBootApplication @EnableEurekaClient //表示是eureka的客戶端 public class UserProviderApplication_8001 { public static void main(String[] args) { SpringApplication.run(UserProviderApplication_8001.class); } }
contrller層進行測試
@RestController @RequestMapping("/provider") public class UserController { // @Autowired // private IUserService userService; @RequestMapping("/user/{id}") //user/1 public User getUser(@PathVariable("id") Long id) { // 正常應該調用service獲取用戶,現在模擬一下 return new User(id, "zs"); } }
服務消費者搭建
pom.xml配置
dependency> <groupId>cn.itsource.springcloud</groupId> <artifactId>User_interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--springboot支持--> <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> </dependency>
yml配置
server: port: 9001 spring: application: name: USER_CONSUMER
主程序
package cn.itsource.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class UserConsumerAppliction_9001 { public static void main(String[] args) { SpringApplication.run(UserConsumerAppliction_9001.class); } }
測試
調用服務提供者的接口
@Configuration // <beans></beans> public class CfgBean { @Bean //<bean class="org.springframework.web.client.RestTemplate"></bean> public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
@RestController @RequestMapping("/consumer") public class UserController { //多個方法調用只需改一處就ok public static final String URL_PREFIX = "http://localhost:8001"; @Autowired private RestTemplate restTemplate; @RequestMapping("/user/{id}") public User getUser(@PathVariable("id")Long id){ //調用遠程服務 http請求 String url = URL_PREFIX+"/provider/user/"+id; return restTemplate.getForObject(url,User.class ); } }
實現集群
實現集群以注冊中心為例。我們新建一個操作中心,操作i方法和之前的一樣,yml的配置方式變化
server: port: 7001 eureka: instance: hostname: eureka-7001.com client: registerWithEureka: false #是否要注冊到eureka fetchRegistry: false #表示是否從Eureka Server獲取注冊信息 serviceUrl: #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #單機配置 defaultZone: http://eureka-7002.com:7002/eureka/ #集群配置,如果有多個,有逗號分割,不要包含自己
7002: 模塊application.yml
server: port: 7002 eureka: instance: hostname: eureka-7002.com client: registerWithEureka: false #是否要注冊到eureka fetchRegistry: false #表示是否從Eureka Server獲取注冊信息 serviceUrl: #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #單機配置 defaultZone: http://eureka-7001.com:7001/eureka/ #集群配置,如果有多個,有逗號分割,不要包含自己
映射hosts 模擬域名解析 C:\Windows\System32\drivers\etc
127.0.0.1 eureka-7001.com
127.0.0.1 eureka-7002.com
然后就是在消費端需要注意,
把8001服務提供方代碼分別注冊到7001和7002兩個注冊中心去;完成集群操作
server: port: 8001 spring: application: name: user-provider #不要使用下划線 eureka: client: service-url: #defaultZone: http://localhost:7001/eureka #告訴服務提供者要把服務注冊到哪兒 defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka instance: prefer-ip-address: true #顯示客戶端真實ip
負載均衡
為什么需要負載均衡
為了提供並發量,有時同一個服務提供者可以部署多個。這個客戶端在調用時要根據一定的負責均衡策略完成負載調用。
1.1. Ribbon負載均衡
Ribbon是Netflix發布的雲中間層服務開源項目,主要功能是提供客戶端負載均衡算法。Ribbon客戶端組件提供一系列完善的配置項,如,連接超時,重試等。簡單的說,Ribbon是一個客戶端負載均衡器,
1.1.1. 集成原理

在服務器方配置負載均衡
我們新建一個服務端和之前的一樣的,然后在消費端進行配置
·
<!--eureka客戶端,服務消費者也要從注冊中心獲取可用服務列表-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--客戶端負載均衡實現 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
9001消費方引入ribbon
port: 9001 eureka: client: registerWithEureka: false #不注冊到Eureka,不在注冊中心顯示 service-url: #defaultZone: http://localhost:7001/eureka defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
主方法
@SpringBootApplication @EnableEurekaClient public class UserConsumerApplicaton_9001 { public static void main(String[] args) { SpringApplication.run(UserConsumerApplicaton_9001.class); } }
新建一個類用來獲取RestTemplate
@Configuration
public class CfgBean {
@Bean
@LoadBalanced //開啟負載均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
//隨機策略
@Bean
public IRule myRule(){
return new RandomRule();//通過隨機算法分配服務端
}
}
@Configuration public class CfgBean { @Bean @LoadBalanced //開啟負載均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); } } @RestController @RequestMapping("/consumer") public class UserController { //多個方法調用只需改一處就ok //public static final String URL_PREFIX = "http://localhost:8001"; public static final String URL_PREFIX ="http://USER-PROVIDER"; //通過服務名從注冊中心獲取服務列表,通過負載均衡調用 @Autowired private RestTemplate restTemplate; @RequestMapping("/user/{id}") public User getUser(@PathVariable("id")Long id){ //調用遠程服務 http請求 String url = URL_PREFIX+"/provider/user/"+id; return restTemplate.getForObject(url,User.class ); } }
完后啟動就能完成負載均衡
Feign負載均衡
Feign是一個聲明式的Web Service客戶端,它的目的就是讓Web Service調用更加簡單。Feign提供了HTTP請求的模板,通過編寫簡單的接口和插入注解,就可以定義好HTTP請求的參數、格式、地址等信息。而Feign則會完全代理HTTP請求,我們只需要像調用方法一樣調用它就可以完成服務請求及相關處理。Feign整合了Ribbon和Hystrix(關於Hystrix我們后面再講),可以讓我們不再需要顯式地使用這兩個組件。
Feign是以接口方式進行調用,而不是通過RestTemplate來調用,feign底層還是ribbo,它進行了封裝,讓我們調用起來更加happy.
通過客戶端進行負載均衡
新建一個客戶端
pom配置
<dependencies>
<!--公共代碼依賴-->
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>User_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客戶端,服務消費者也要從注冊中心獲取可用服務列表-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
配置yml
server: port: 9002 eureka: client: registerWithEureka: false #不注冊到Eureka,不在注冊中心顯示 service-url: #defaultZone: http://localhost:7001/eureka defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
主方法
@SpringBootApplication @EnableEurekaClient @EnableFeignClients(basePackages = "cn.itsource.microservice") //不在當前包下面 public class UserConsumerFeign9002Application { public static void main(String[] args) { SpringApplication.run(UserConsumerFeign9002Application.class, args); } }
寫一個接口,這個接口中的方法要和服務提供者里面訪問地址和參數等保持一致。
@FeignClient(value = "USER-PROVIDER") @RequestMapping("/provider") public interface UserCilent { @RequestMapping("/user/{id}") //user/1 User getUser(@PathVariable("id") Long id); }
在Controller中進行調用
@RestController @RequestMapping("/consumer") public class UserController { @Autowired private UserCilent userCilent; @RequestMapping("/user/{id}") public User getUser(@PathVariable("id")Long id){ System.out.println(userCilent.getClass()); return userCilent.getUser(id); } }
