14 微服務電商【黑馬樂優商城】:day03-springcloud(Hystix,Feign)

本項目的筆記和資料的Download,請點擊這一句話自行獲取。html

day01-springboot(理論篇) ;day01-springboot(實踐篇)git

day02-springcloud(理論篇一)  ;day02-springcloud(理論篇二)  ;day02-springcloud(理論篇三) ;day02-springcloud(理論篇四) ;github

day03-springcloud(Hystix,Feign)  ;day03-springcloud(Zuul網關)
spring

 

14 微服務電商【黑馬樂優商城】:day03-springcloud


 

0.學習目標

  • 會配置Hystix熔斷
  • 會使用Feign進行遠程調用
  • 能獨立搭建Zuul網關
  • 能編寫Zuul的攔截器

1.Hystix

Hystix,即熔斷器。json

主頁:https://github.com/Netflix/Hystrix/springboot

 

 Hystix是一個延遲和容錯庫,用於隔離訪問遠程服務、第三方庫,防止出現級聯失敗。mybatis

 

1.2.熔斷器的工做機制:

 正常工做的狀況下,客戶端請求調用服務API接口:app

 

 當有服務出現異常時,直接進行失敗回滾,服務降級處理: 負載均衡

 當服務繁忙時,若是服務出現異常,不是粗暴的直接報錯,而是返回一個友好的提示,雖然拒絕了用戶的訪問,可是會返回一個結果。dom

 這就比如去買魚,日常超市買魚會額外贈送殺魚的服務。等到逢年過節,超時繁忙時,可能就不提供殺魚服務了,這就是服務的降級。

 系統特別繁忙時,一些次要服務暫時中斷,優先保證主要服務的暢通,一切資源優先讓給主要服務來使用,在雙11、618時,京東天貓都會採用這樣的策略。

1.3.動手實踐

1.3.1.引入依賴

首先在user-consumer中引入Hystix依賴: 

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

 

1.3.2.開啓熔斷

1.3.2.改造消費者

咱們改造user-consumer,添加一個用來訪問的user服務的DAO,而且聲明一個失敗時的回滾處理函數:

 

@Component public class UserDao { @Autowired private RestTemplate restTemplate; private static final Logger logger = LoggerFactory.getLogger(UserDao.class); @HystrixCommand(fallbackMethod = "queryUserByIdFallback") public User queryUserById(Long id){ long begin = System.currentTimeMillis(); String url = "http://user-service/user/" + id; User user = this.restTemplate.getForObject(url, User.class); long end = System.currentTimeMillis(); // 記錄訪問用時:
        logger.info("訪問用時:{}", end - begin); return user; } public User queryUserByIdFallback(Long id){ User user = new User(); user.setId(id); user.setName("用戶信息查詢出現異常!"); return user; } }

 

  • @HystrixCommand(fallbackMethod="queryUserByIdFallback"):聲明一個失敗回滾處理函數queryUserByIdFallback,當queryUserById執行超時(默認是1000毫秒),就會執行fallback函數,返回錯誤提示。
  • 爲了方便查看熔斷的觸發時機,咱們記錄請求訪問時間。

在原來的業務邏輯中調用這個DAO: 

@Service public class UserService { @Autowired private UserDao userDao; public List<User> queryUserByIds(List<Long> ids) { List<User> users = new ArrayList<>(); ids.forEach(id -> { // 咱們測試屢次查詢,
            users.add(this.userDao.queryUserById(id)); }); return users; } }

 

1.3.3.改造服務提供者

改造服務提供者,隨機休眠一段時間,以觸發熔斷:

@Service public class UserService { @Autowired private UserMapper userMapper; public User queryById(Long id) throws InterruptedException { // 爲了演示超時現象,咱們在這裏然線程休眠,時間隨機 0~2000毫秒
        Thread.sleep(new Random().nextInt(2000)); return this.userMapper.selectByPrimaryKey(id); } }

1.3.4.啓動測試

而後運行並查看日誌:

id爲九、十、11的訪問時間分別是:

id爲12的訪問時間: 

 

 所以,只有12是正常訪問,其它都會觸發熔斷,咱們來查看結果:

1.3.5.優化

雖然熔斷實現了,可是咱們的重試機制彷佛沒有生效,是這樣嗎?

其實這裏是由於咱們的Ribbon超時時間設置的是1000ms:

而Hystix的超時時間默認也是1000ms,所以重試機制沒有被觸發,而是先觸發了熔斷。

因此,Ribbon的超時時間必定要小於Hystix的超時時間。

咱們能夠經過hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds來設置Hystrix超時時間。

hystrix: command: default: execution: isolation: thread: timeoutInMillisecond: 6000 # 設置hystrix的超時時間爲6000ms

 


2.Feign

在前面的學習中,咱們使用了Ribbon的負載均衡功能,大大簡化了遠程調用時的代碼:

String baseUrl = "http://user-service/user/"; User user = this.restTemplate.getForObject(baseUrl + id, User.class)

若是就學到這裏,你可能之後須要編寫相似的大量重複代碼,格式基本相同,無非參數不同。有沒有更優雅的方式,來對這些代碼再次優化呢?

這就是咱們接下來要學的Feign的功能了。

2.1.簡介

有道詞典的英文解釋:

 爲何叫假裝?

 Feign能夠把Rest的請求進行隱藏,假裝成相似SpringMVC的Controller同樣。你不用再本身拼接url,拼接參數等等操做,一切都交給Feign去作。

 項目主頁:https://github.com/OpenFeign/feign

2.2.快速入門

2.2.1.導入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

 2.2.2.Feign的客戶端

@FeignClient("user-service") public interface UserFeignClient { @GetMapping("/user/{id}") User queryUserById(@PathVariable("id") Long id); }
  • 首先這是一個接口,Feign會經過動態代理,幫咱們生成實現類。這點跟mybatis的mapper很像
  • @FeignClient,聲明這是一個Feign客戶端,相似@Mapper註解。同時經過value屬性指定服務名稱
  • 接口中的定義方法,徹底採用SpringMVC的註解,Feign會根據註解幫咱們生成URL,並訪問獲取結果

改造原來的調用邏輯,再也不調用UserDao:

@Service public class UserService { @Autowired private UserFeignClient userFeignClient; public List<User> queryUserByIds(List<Long> ids) { List<User> users = new ArrayList<>(); ids.forEach(id -> { // 咱們測試屢次查詢,
            users.add(this.userFeignClient.queryUserById(id)); }); return users; } }

 

2.2.3.開啓Feign功能

咱們在啓動類上,添加註解,開啓Feign功能

@SpringBootApplication @EnableDiscoveryClient @EnableHystrix @EnableFeignClients // 開啓Feign功能
public class UserConsumerDemoApplication { public static void main(String[] args) { SpringApplication.run(UserConsumerDemoApplication.class, args); } }
  • 你會發現RestTemplate的註冊被我刪除了。Feign中已經自動集成了Ribbon負載均衡,所以咱們不須要本身定義RestTemplate了。

2.2.4.啓動測試:

訪問接口:

2.3.負載均衡

Feign中自己已經集成了Ribbon依賴和自動配置:

 所以咱們不須要額外引入依賴,也不須要再註冊RestTemplate對象。

 另外,咱們能夠像上節課中講的那樣去配置Ribbon,能夠經過ribbon.xx來進行全局配置。也能夠經過服務名.ribbon.xx來對指定服務配置:

user-service: ribbon: ConnectTimeout: 250 # 鏈接超時時間(ms) ReadTimeout: 1000 # 通訊超時時間(ms) OkToRetryOnAllOperations: true # 是否對全部操做重試 MaxAutoRetriesNextServer: 1 # 同一服務不一樣實例的重試次數 MaxAutoRetries: 1 # 同一實例的重試次數

2.4.Hystix支持

Feign默認也有對Hystix的集成:

 

 只不過,默認狀況下是關閉的。咱們須要經過下面的參數來開啓: 

feign: hystrix: enabled: true # 開啓Feign的熔斷功能

 

可是,Feign中的Fallback配置不像Ribbon中那樣簡單了。

1)首先,咱們要定義一個類,實現剛纔編寫的UserFeignClient(接口),做爲fallback的處理類。

@Component public class UserFeignClientFallback implements UserFeignClient { @Override public User queryUserById(Long id) { User user = new User(); user.setId(id); user.setName("用戶查詢出現異常!"); return user; } }

 2)而後在UserFeignClient中,指定剛纔編寫的實現類

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class) public interface UserFeignClient { @GetMapping("/user/{id}") User queryUserById(@PathVariable("id") Long id); }

3)重啓測試:

咱們關閉user-service服務,而後在頁面訪問:

 

2.5.請求壓縮(瞭解)

Spring Cloud Feign 支持對請求和響應進行GZIP壓縮,以減小通訊過程當中的性能損耗。經過下面的參數便可開啓請求與響應的壓縮功能:

feign: compression: request: enabled: true # 開啓請求壓縮 response: enabled: true # 開啓響應壓縮

同時,咱們也能夠對請求的數據類型,以及觸發壓縮的大小下限進行設置:

feign: compression: request: enabled: true # 開啓請求壓縮 mime-types: text/html,application/xml,application/json # 設置壓縮的數據類型 min-request-size: 2048 # 設置觸發壓縮的大小下限

注:上面的數據類型、壓縮大小下限均爲默認值。

2.6.日誌級別(瞭解)

前面講過,經過logging.level.xx=debug來設置日誌級別。然而這個對Fegin客戶端而言不會產生效果。由於@FeignClient註解修改的客戶端在被代理時,都會建立一個新的Fegin.Logger實例。咱們須要額外指定這個日誌的級別才能夠。

1)設置com.leyou包下的日誌級別都爲debug

logging: level: com.leyou: debug

2)編寫配置類,定義日誌級別

@Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }

這裏指定的Level級別是FULL,Feign支持4種級別:

  • NONE:不記錄任何日誌信息,這是默認值。
  • BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間
  • HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息
  • FULL:記錄全部請求和響應的明細,包括頭信息、請求體、元數據。

3)在FeignClient中指定配置類:

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class, configuration = FeignConfig.class) public interface UserFeignClient { @GetMapping("/user/{id}") User queryUserById(@PathVariable("id") Long id); }

4)重啓項目,便可看到每次訪問的日誌:

 

 

=============================================

參考資料:

Spring Cloud升級最新Finchley版本的全部坑

hystrix簡介

深刻理解Hystrix之文檔翻譯

SpringBoot集成Hystrix

end

相關文章
相關標籤/搜索