注冊中心Eureka
Eureka-Server:就是服務注冊中心(可以是一個集群),對外暴露自己的地址。
提供者:啟動后向Eureka注冊自己信息(地址,服務名稱等),并且定期進行服務續約
消費者:服務調用方,在使用的時候去拉取一次,之后會定期去Eureka拉取服務列表,然后使用負載均衡算法選出一個服務進行調用。
心跳(續約):提供者和消費者定期通過http方式向Eureka刷新獲取(默認30秒)
?如果消費者之前已經調用過注冊中心獲取過提供者的地址信息,那么注冊中心宕機后,在提供者地址不變的前提下,不影響服務直接調用
引入SpringCloud為eureka提供的starter依賴:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
?編寫一個啟動類
給eureka-server服務編寫一個啟動類,一定要添加一個@EnableEurekaServer注解,開啟eureka的注冊中心功能:
@SpringBootApplication @EnableEurekaServer //開啟eureka的注冊中心功能 public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);} }
編寫一個application.yml文件,內容如下:
server:port: 10086 spring:application:name: eureka-server eureka:client:service-url: defaultZone: http://127.0.0.1:10086/eurekaregister-with-eureka: false # 自己不注冊到eureka中fetch-registry: false #自己不從eureka中拉取別的服務
啟動微服務,然后在瀏覽器訪問:http://127.0.0.1:10086
?將微服務注冊到注冊中心->引入依賴->編寫配置文件,名字要指定
spring:application:name: userservice eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka
Ribbon負載均衡
@SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}//注冊RestTemplate,第三方的類,交給IOC容器管理@Bean@LoadBalanced//自動負載均衡public RestTemplate restTemplate() {return new RestTemplate();} }
@LoadBalanced?
在遠程調用的RestTemplate,上添加了@LoadBalanced注解,即可實現負載均衡功能
原理:SpringCloud底層其實是利用了一個名為Ribbon的組件,來實現負載均衡功能的。
?SpringCloudRibbon的底層采用了一個攔截器,攔截了RestTemplate發出的請求,對地址做了修改。用一幅圖來總結一下:
基本流程如下:
攔截我們的RestTemplate請求http://userservice/user/1
RibbonLoadBalancerClient會從請求url中獲取服務名稱,也就是user-service
DynamicServerListLoadBalancer根據user-service到eureka拉取服務列表
eureka返回列表,localhost:8081、localhost:8082
IRule利用內置負載均衡規則,從列表中選擇一個,例如localhost:8081
RibbonLoadBalancerClient修改請求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,發起真實請求
Hystrix 熔斷器
雪崩問題
微服務中,服務間調用關系錯綜復雜,一個請求,可能需要調用多個微服務接口才能實現,會形成非常復雜的調用鏈路:Hystix解決雪崩問題的手段主要是服務降級和線程隔離;
服務降級的演示
第一步:導依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
第二步:在引導類上開啟Hystrix ?
@EnableCircuitBreaker//開啟斷路器 @SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}//注冊RestTemplate,第三方的類,交給IOC容器管理@Bean@LoadBalanced//自動負載均衡public RestTemplate restTemplate() {return new RestTemplate();}}
第三步:開發一個方法作為降級的處理方式要求:方法的參數和返回結果類型要和原方法findById應該一致
public String queryOrderByIdFallback(Long orderId) {return "服務器太忙,請稍后重試........"; }
?第四步:修改原有的方法,在方法上添加注解
?全局降級
?上面的寫法中每個方法都需要一個降級方法,很麻煩,我們可以使用一個全局的降級方案
@Service @DefaultProperties(defaultFallback="allMethodFallBack") //在類上添加一個注解 @DefaultProperties(defaultFallback="allMethodFallBack") public class OrderService {@HystrixCommand//指向降級方法public String queryOrderById() { return "我出錯了";}// 全局降級方法public String allMethodFallBack() {return "服務器太太太太太太太忙,請稍后重試.....";} }
?超時設置
Hystix的默認超時時長為1秒,如果這個微服務響應時間超過1秒,就會報錯,降級處理,但是有的方法本身需要執行的時間就長,自定義超時時間
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000 # 超時時間3秒
熔斷原理
熔斷功能:默認5秒內發起20次請求,失敗率超過50% 進入熔斷狀態 5秒內的其他時間都會直接進入降級方法
熔斷器有3種狀態:open close half-open
狀態機有3個狀態:
Closed:關閉狀態(斷路器關閉),所有請求都正常訪問。
Open:打開狀態(斷路器打開),所有請求都會被降級。Hystix會對請求情況計數,當一定時間內失敗請求百分比達到閾值,則觸發熔斷,斷路器會完全關閉。默認失敗比例的閾值是50%,請求次數最少不低于20次。
Half Open:半開狀態,open狀態不是永久的,打開后會進入休眠時間(默認是5S)。隨后斷路器會自動進入半開狀態。此時會釋放1次請求通過,若這個請求是健康的,則會關閉斷路器,否則繼續保持打開,再次進行5秒休眠計時。
?Feign:封裝了RestTemple 遠程調用
導入依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
創建interface接口
@FeignClient("userservice") public interface UserClient {@GetMapping("/user/{id}") //這里的返回結果和 url地址一定要和提供方保持一致User findById(@PathVariable("id") Long id); }
首先這是一個接口,Feign會通過動態代理,幫我們生成實現類。這點跟mybatis的mapper很像
@FeignClient
,聲明這是一個Feign客戶端,同時通過value
屬性指定服務名稱接口中的定義方法,完全采用SpringMVC的注解,Feign會根據注解幫我們生成URL,并訪問獲取結果
開啟Feign功能
@EnableFeignClients//開啟Feign public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}}
負載均衡
Feign中本身已經集成了Ribbon依賴和自動配置:
Feign默認也有對Hystix的集成:
feign:hystrix:enabled: true # 開啟Feign的熔斷功能
- 首先,我們要定義一個類,是在剛才編寫的UserFeignClient,作為fallback的處理類
import cn.itcast.order.pojo.User; import org.springframework.stereotype.Component;@Component public class UserClientFallback implements UserFeignClient {@Overridepublic User findById(Long id) {User user = new User();user.setId(0L);user.setUsername("用戶查詢出現異常!");return user;} }
- 然后在UserFeignClient中,指定剛才編寫的實現類,就實現了降級方法
@FeignClient(value = "userservice", fallback = UserClientFallback.class) public interface UserFeignClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id); }
Gateway網關
網關的核心功能是:路由和過濾(鑒權)
- ?搭建網關
<dependencies><!--引入gateway 網關--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency> </dependencies>
- 編寫啟動類
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class ApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatewayApplication.class,args);}}
- 編寫配置
server:port: 10010 spring:application:name: api-gatewaycloud:# 網關配置gateway:# 路由配置:轉發規則routes: #集合。# id: 唯一標識。默認是一個UUID# uri: 轉發路徑# predicates: 條件,用于請求網關路徑的匹配規則- id: userserviceuri: http://localhost:8081/predicates:- Path=/user/**
application.yml 中的uri是寫死的,就是Gateway-靜態路由
Gateway-動態路由
<dependency><--添加注冊中心Eureka--> <groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
?修改配置文件
server:port: 10010
spring:application:name: api-gatewaycloud:# 網關配置gateway:# 路由配置:轉發規則routes: #集合。# id: 唯一標識。默認是一個UUID# uri: 轉發路徑# predicates: 條件,用于請求網關路徑的匹配規則- id: user-serviceuri: lb://userservice # lb負載均衡predicates:- Path=/user/**eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka
Gateway-過濾器
GatewayFilter:局部過濾器,針對單個路由 GlobalFilter :全局過濾器,針對所有路由
全局過濾器
GlobalFilter 全局過濾器,不需要在配置文件中配置,系統初始化時加載,并作用在每個路由上。
Spring Cloud Gateway 核心的功能也是通過內置的全局過濾器來完成。
自定義全局過濾器步驟:
定義類實現 GlobalFilter 和 Ordered接口
復寫方法
完成邏輯處理
/*** 自定義全局過濾器*/ @Component public class MyGlobalFilter implements GlobalFilter, Ordered {//需求 :請求參數中帶有token 內容,就放行,否則提示未授權@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 獲取請求對象ServerHttpRequest request = exchange.getRequest(); // 獲取參數MultiValueMap<String, String> valueMap = request.getQueryParams();List<String> valList = valueMap.get("token");if(CollectionUtils.isEmpty(valList)){//異常情況,沒有token參數// 獲取響應對象ServerHttpResponse response = exchange.getResponse();// 返回響應碼response.setStatusCode(HttpStatus.FORBIDDEN);//401// 完成響應return response.setComplete();}return chain.filter(exchange);//放行}@Overridepublic int getOrder() {return 0;} }