1.Feign
我們已經將Eureka和Zuul開發完畢,而且上面注冊了兩個微服務,現在我們實現兩個微服務之間的調用。
String baseUrl = "http://127.0.0.1:10010/user-service/user/";
User user = this.restTemplate.getForObject(baseUrl + id, User.class)
這樣雖然能訪問到,但是這樣的代碼不太優雅,這里使用了spring提供的RestTemplate,已經簡化了操作,如果使用遠程的httpclient,那更是懷疑人生,怎么實現優雅的訪問呢?答案是Feign
Feign的英文含義假裝,偽裝
為什么叫偽裝?
Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣。你不用再自己拼接url,拼接參數等等操作,一切都交給Feign去做。
下面為我們的demo加上feign:
1.在consumer-demo中導入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.開發feign的客戶端,其實就是一個接口
@FeignClient("user-service") //聲明這是一個Feign客戶端,同時通過value屬性指定服務名稱
public interface UserClient {
@GetMapping("/user/{id}") //這里的返回結果和 url地址一定要和提供方保持一致
User queryById(@PathVariable("id") Long id);
}
注意:訪問路徑和返回結果一定要與服務端的提供方一致,因為feign會根據這個路徑為我們生成代理對象
3.在啟動類上開啟feign的功能
@SpringCloudApplication
@EnableFeignClients // 開啟Feign功能
public class ConsumerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(UserConsumerDemoApplication.class, args);
}
}
4.現在就可以使用feign的方式進行訪問了
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserClient userClient;
@GetMapping("{id}")
public User queryById(@PathVariable("id") Long id){
return userClient.queryById(id);
}
}
到這里feign的功能就已經實現了,單獨看controller是看不出使用了遠程調用的,這就是feign的作用
最后強調:Feign中本身已經集成了Ribbon依賴和自動配置,不用再次引入依賴,就可以直接配置ribbon相關的參數
2.ribbon
說完了feign,可以知道,feign是通過服務在Eureka上的serviceId
來找尋服務的,也就是user-service
,那么如果我們現在有兩個user-service的服務:
user-service: 192.168.100.1
user-serivice: 192.168.100.2
那么feign怎么知道你要請求的是哪個服務器呢?
這Ribbon就派上用場了。Ribbon就是專門解決這個問題的。它的作用是負載均衡,會幫你在每次請求時選擇一台機器,均勻的把請求分發到各個機器上
Ribbon的負載均衡默認使用的最經典的Round Robin輪詢算法。這是啥?簡單來說,就是如果訂單服務對庫存服務發起10次請求,那就先讓你請求第1台機器、然后是第2台機器、第3台機器、第4台機器、第5台機器,接着再來—個循環,第1台機器、第2台機器。。。以此類推
我們也可以通過配置文件更改它默認的負載均衡算法:
#這是將算法更改為了隨機
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
3.Hystrix
首先我們來了解一下什么是雪崩問題:
服務器支持的線程和並發數有限,請求一直阻塞,會導致服務器資源耗盡,從而導致所有其它服務都不可用,形成雪崩效應。
解決這個問題,我們就需要來學習一下hystrix
3.1 線程隔離
Hystrix為每個依賴服務調用分配一個小的線程池,如果線程池已滿調用將被立即拒絕,
解釋一下,假如現在有兩個服務:user-service
和order-service
,現在hystrix會為這兩個服務分配兩個小的線程池,如果user-service
宕機會導致它的線程池所有的線程都被卡着,但是並不會影響到order-service
的線程池,這兩就不會出現雪崩問題了。
3.2 服務熔斷
在線程隔離中講到,如果user-service
宕機會導致它的線程池所有的線程都被卡着,每次對user-service的訪問都會失敗,既然都會失敗,就不要再走網絡請求了,這就用到了Hystrix的服務熔斷機制:
假如5s中之內訪問一個服務20次都失敗了,那么這5s之內再去訪問這個服務就直接給熔斷了,也就是不再請求,直接判定失敗,5秒20次是Hystrix的默認值
我們可以通知配置文件修改這些參數
circuitBreaker:
requestVolumeThreshold: 10
sleepWindowInMilliseconds: 10000
errorThresholdPercentage: 50
解讀:
- requestVolumeThreshold:觸發熔斷的最小請求次數,默認10
- sleepWindowInMilliseconds:休眠時長,默認是10000毫秒
- errorThresholdPercentage:觸發熔斷的失敗請求最小占比,默認50%
3.3 服務降級
熔斷之后直接判定失敗,直接返回時不太好的,總的做的什么操作吧,這就是降級服務,也就是失敗之后執行的一個方法,在這個方法中可以去記錄請求的信息,也可以返回一些友好的 提示
我們在consumer-demo中的試一下:
1.導入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.開啟熔斷
將啟動類上的注解換成@SpringCloudApplication
@SpringCloudApplication
public class ConsumerApplication {
// ...
}
3.編寫降級邏輯
這里我們的降級邏輯,就返回一個提示好了
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallBack")
public String queryById(@PathVariable("id") Long id){
@Autowired
private UserClient userClient;
@GetMapping("{id}")
public User queryById(@PathVariable("id") Long id){
return userClient.queryById(id);
}
}
public String queryByIdFallBack(Long id){
log.error("查詢用戶信息失敗,id:{}", id);
return "對不起,網絡太擁擠了!";
}
要注意,因為熔斷的降級邏輯方法必須跟正常邏輯方法保證:相同的參數列表和返回值聲明。
這樣,這個服務降級功能就完成了