SpringCloud-常用組件介紹
分布式系統開發用於分布式環境(多個服務器不在同一個機房,同一個業務服務在多台服務器運行)
Spring Cloud 是基於Springboot的分布式雲服務架構,SpringCloud的設計就是為了分布式的雲環境設計
下面說一些SpringCloud項目在開發中常用的幾個組件
說組件之前,將一些分布式相關的概念
CAP定理 指分區容錯性 服務可用性 數據一致性,分布式環境:
容錯性,允許部分機器故障,但是系統人仍能正常運作
服務可用性 任何時候調用服務有響應
數據一致性 任何時候獲取數據都一樣(訪問不同機器節點相同的業務數據)
CAP定理因為分布式而存在,離開具體業務相對來說有些抽象,CAP只是說設計系統時的參考思想;但很明顯的意思就是為了提高系統穩定性,讓原來的一台服務器變成多台,提供相同服務,部分服務器壞了沒關系,其他正常服務器能提供服務,從而讓使用系統的一方不受影響,覺得這個系統是穩定的,但隨之而來的是不同服務器之間數據如何同步,協作,就成了分布式系統要面對的問題。
簡單的商城分布式系統,一個服務會運行在多台機器上,買商品下單這一個件事,需要多台服務器中的一個去完成,如果有兩台服務器宕機,就去訪問沒有宕機的服務器(容錯性)。下單是調用服務,調用服務這個過程是需要暢通的,不能等很久,下單服務在最多1秒左右就完成。(服務可用性)。下完單,被調用的服務器需要修改商品庫存數據,將庫存減一(x-1)。在這之后其他服務器訪問顯示商品庫存也是x-1,而不是x(數據一致性)。
SpringCloud-常用組件
SpringCloud分布式組件提高了系統的開發效率,穩定性,可維護性
SpringCloud-Config 服務配置,提供統一配置功能。多個服務,或者服務器啟動后,配置文件都在Config中,方便管理(分布式統一配置相關)
SpringCloud-Eureka 服務注冊,提供注冊服務。服務啟動后,可以提供自己的服務地址注冊到Eureka,暴露出來提供給其他人調用(服務可用性相關)
SpringCloud-OpenFeign 服務代理,提供代理調用服務。A服務要調用B服務,可以通過feign,feign使服務調用更方便(遠程服務調用相關,有斷路器,防止服務雪崩)
SpringCloud-Gateway 網關路由服務,提供代理訪問轉發。 訪問narule.net/api 實際訪問narule.github.io/api 可以通過Gateway來實現。(訪問安全相關)
還有很多其他組件,比如redis相關組件用於數據一致性訪問,kafka用於高吞吐消息隊列等,本文主要講上面提到的四個,通過代碼簡單說明如何使用。
example 代碼地址:springcloud-example
完整代碼請參考springcloud-example,以及maven的完整依賴;如果要啟動里面的服務,請務必先啟動config-server,因為里面的項目都是通過config統一配置,包括服務用哪個端口訪問等參數,;
Config
Config作為配置中心,能夠很方便配置每個分布式系統參數,配置文件可以通過git等倉庫專門管理
參考代碼:config
測試訪問:http://localhost:8888/eureka-server.yml http://localhost:8888/eureka-client.yml
example
關鍵配置是application.yml中配置文件的位置,一般由url指定
dependencies 依賴
serverConfig-pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8888 #服務端口
spring:
application:
name: server-config #服務名
cloud:
config:
server:
git:
uri: https://github.com/narule/spring-cloud-config #配置文件地址
#username: narule
#password: password
refresh:
enabled: true
ServerConfigApplication
啟動程序,除了SpringBootApplication,還需要EnableConfigServer注解:
package net.narule.spring.cloud.config.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
配置讀取規則
下文中所有應用程序的配置(包括端口)都是讀取的 https://github.com/narule/spring-cloud-config
如果啟動程序 spring.application.name=server1-client,並且配置了遠程配置,此程序會嘗試從遠程讀取server1-client.yml 文件的配置參數,這是springcloud-config配置規則
客戶端應用讀取配置只需要依賴spring-cloud-starter-config ,不需要在啟動類中寫什么注解
client-dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
client-application.yml
spring-cloud-starter-config 3.0 有新增配置
# client一般指定配置路徑
spring:
application:
name: config-client-one #一定要在本地指定 spring.application.name 才能讀取遠程配置
cloud:
refresh:
enabled: true
config:
uri:
- http://localhost:8888 # config-server的訪問地址
# 3.0之后新的方式 指定url
spring:
application:
name: config-client-one
config:
import:
- optional:configserver:http://narule.net:8888 #config-server的訪問地址
ConfigClientOneApplication
package net.narule.spring.cloud.config.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientOneApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientOneApplication.class, args);
}
}
Eureka
Eureka提供服務注冊,分為注冊中心和客戶端,注冊中心使用@EnableEurekaServer
客戶端有producer服務提供者,consumer 服務消費者,在使用時,都使用@EnableEurekaCilent注解,啟動服務的時候,將自己的服務信息,ip和端口號等,注冊到Eureka服務中心,讓其他eurekaclient能通過Eureka服務注冊中心獲取服務的ip和端口號。
參考代碼:eureka
測試訪問:https://localhost:1999/eureka-server
example
服務端,主要參數是服務的節點,注冊節點地址,注冊帳號密碼(可選)
server-dependencies 依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--Spring Boot Actuator,感應服務端變化-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- security 此模塊權限校驗 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
server-application.yml
server:
port: 1999
spring:
application:
name: eureka-server #注冊中心訪問path
eureka:
dashboard:
path: eureka-server
instance:
hostname: localhost
client:
registerWithEureka: false #將自己注冊微eurekaclient false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #注冊節點地址
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 10000 #服務刷新時間
EurekaServerApplication
配置文件配置好后,使用@EnableEurekaServer注解即可
package com.wunanyu.cloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
客戶端
client-dependencies
客戶端依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
client-application.yml
配置文件主要是指定注冊中心地址,通過這個配置客戶端可以把自己的服務注冊到注冊中心,或者從注冊中心獲取其他服務的信息,
spring:
application:
name: eureka-client
## 下面的配置是通過config-server讀取,如果沒有配置中心,則需要在本地配置文件中寫好
server:
port: 18080
eureka:
#客戶端
client:
#注冊中心地址
service-url:
defaultZone: http://localhost:1999/eureka/ #這里是
instance:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}# 實例id命名規則,這個用於區分同一服務在不同的機器,可應用於分布式鎖
prefer-ip-address: true #以IP地址注冊到服務中心,相互注冊使用IP地址
hostname: localhost
EurekaClientApplication
客戶端的使用是注解@EnableEurekaClient,有這個注解,啟動時會把自己的信息注冊到服務中心,當然要配置注冊中心節點信息,讓客戶端知道注冊地址在哪。
package net.narule.spring.cloud.eureka.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
@RequestMapping("/request-eureka-client/{id}")
public ResponseResult requestEurekaClient(@PathVariable String id) {
return ResponseResult.ok(id + "from-eureka-client");
}
}
OpenFeign
Feign和eureka一樣是Nexflix的組件,可以用作接口調用Eureka服務,完成服務於服務之間的調用
參考代碼:openfeign
測試訪問:http://localhost:1666/request-feign-client
example
dependencies 依賴
因為feign通過eureka調用服務,並且在分布式環境考慮到負載均衡,所以依賴除了feign,還有ribbon和eureka
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-netflix-eureka-client
</artifactId>
</dependency>
FeignClientApplication
要使用feign功能,啟動類需要使用注解@EnableFeignClients
package net.narule.spring.cloud.feign.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableFeignClients
@RestController
public class FeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
@Autowired
private FeignInterFace feignInterFace;
@RequestMapping("/request-feign-client")
public ResponseResult requestFeignClient() {
String id = String.valueOf(System.currentTimeMillis());
ResponseResult reuqestEurekaClient = feignInterFace.reuqestEurekaClient(id);
return ResponseResult.ok(reuqestEurekaClient);
}
@FeignClient("eureka-client")
interface FeignInterFace {
@RequestMapping(value = "/request-eureka-client/{id}")
public ResponseResult reuqestEurekaClient(@PathVariable("id") String id);
}
}
FeignInterface
Feign使用時,只需要寫接口,並在注解上配好url即可,不需要寫代碼實現方法,
@FeignClient("eureka-client")表示有服務名叫eureka-client,方法上的value = "/request-eureka-client/{id}" 說明eureka-client服務有/request-eureka-client/{id}的請求路徑,這是要對應的,並且eureka-client服務注冊到eureka注冊中心,不然服務調用失敗。
@FeignClient("eureka-client")
interface FeignInterFace {
@RequestMapping(value = "/request-eureka-client/{id}")
public ResponseResult reuqestEurekaClient(@PathVariable("id") String id);
}
feign-client.yml
配置文件需要指定eureka的注冊節點,因為feign最終通過eureka獲取服務信息來完成接口訪問
server:
port: 1666
eureka:
#客戶端
client:
#注冊中心地址
service-url:
defaultZone: http://localhost:1999/eureka/
Gateway
gateway是網關組件,此組件可以用來轉發請求,設置路由,比較靈活。
如果有服務訪問路徑是http://localhost:1666/request-feign-client 我們可以因為一些個性化需求改變路由
通過gateway可以讓訪問http://localhost:12000/api/feign/request-feign-client 等同於上面的訪問路徑
參考代碼:gateway
測試訪問:http://localhost:12000/api/feign/request-feign-client
example
gateway-dependencies
gateway作為網關服務,可以搭配eureka使用
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-netflix-eureka-client
</artifactId>
</dependency>
GatewayServerApplication
@SpringBootApplication
public class GatewayServerApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServerApplication.class, args);
}
}
gateway-server.yml
server:
port: 12000
spring:
cloud:
gateway:
routes:
# 路由ID(一個路由配置一個ID)
- id: eureka-c
# 通過注冊中心來查找服務(lb代表從注冊中心獲取服務,並且負載均衡)
uri: lb://eureka-client/
# 匹配到的以/api/eureka/ 通過eureka訪問 eureka-client/**
predicates:
- Path=/api/eureka/**
# 去掉匹配到的路徑的前2級 這里也就是 /api/eureka
filters:
- StripPrefix=2
- id: feign-c
uri: lb://feign-client/
# 匹配到的以/api/feign/開頭的路徑都轉發到feign-client的服務,相當於訪問 lb://feign-client/**
predicates:
- Path=/api/feign/**
# 去掉匹配到的路徑的前2級 這里也就是 /api/feign
filters:
- StripPrefix=2
discovery:
locator:
enabled: true
lowerCaseServiceId: true
eureka:
#客戶端
client:
#注冊中心地址
service-url:
defaultZone: http://localhost:1999/eureka/
