Springcloud負載均衡feign與Hystrix斷路器(四)
springcloud學習總結
4、負載均衡feign與Hystrix斷路器
一、ribbon與feign有什麼區別?
Ribbon
Ribbon 是一個基於 HTTP 和 TCP 客戶端的負載均衡器
它可以在客戶端配置 ribbonServerList(服務端列表),然後輪詢請求以實現均衡負載
它在聯合 Eureka 使用時
ribbonServerList 會被 DiscoveryEnabledNIWSServerList 重寫,擴充套件成從 Eureka 註冊中心獲取服務端列表
同時它也會用 NIWSDiscoveryPing 來取代 IPing,它將職責委託給 Eureka 來確定服務端是否已經啟動
Feign
Spring Cloud Netflix 的微服務都是以 HTTP 介面的形式暴露的,所以可以用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去呼叫
而 Feign 是一個使用起來更加方便的 HTTP 客戶端,它用起來就好像呼叫本地方法一樣,完全感覺不到是呼叫的遠端方法
總結起來就是:釋出到註冊中心的服務方介面,是 HTTP 的,也可以不用 Ribbon 或者 Feign,直接瀏覽器一樣能夠訪問
只不過 Ribbon 或者 Feign 呼叫起來要方便一些,最重要的是:它倆都支援軟負載均衡
注意:spring-cloud-starter-feign 裡面已經包含了 spring-cloud-starter-ribbon(Feign 中也使用了 Ribbon)
二、feign的使用
新建consumerfeign模組
修改pom檔案增加依賴
<dependencies>
<dependency><!-- 自己定義的api -->
<groupId>springcloud</groupId>
<artifactId>springcloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- Ribbon相關 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 修改後立即生效,熱部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>springcloud</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
新建application.yml檔案
server:
port: 80
feign:
hystrix:
enabled: true
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
服務消費處理器(controller)
package com.atguigu.springcloud.controller;
import java.util.List;
import com.atguigu.springcloud.entities.Dept;
import com.atguigu.springcloud.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DeptController_Consumer
{
@Autowired
private DeptClientService service;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return this.service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list()
{
return this.service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept)
{
return this.service.add(dept);
}
}
新建配置類
package com.atguigu.springcloud.cfgbeans;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RetryRule;
@Configuration
public class ConfigBean {
@Bean
public IRule myRule()
{
//return new RoundRobinRule();
//return new RandomRule();//達到的目的,用我們重新選擇的隨機演算法替代預設的輪詢。
return new RetryRule();
}
}
主啟動類
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages= {"com.atguigu.springcloud"})
@ComponentScan("com.atguigu.springcloud")
public class DeptConsumer80_Feign_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
修改api模組,新增service包以及新建介面
package com.atguigu.springcloud.service;
import java.util.List;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.atguigu.springcloud.entities.Dept;
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService
{
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
啟動註冊中心、提供者與此消費者檢視結果
http://localhost:80/consumer/dept/list
三、Hystrix的出現以及使用
為什麼會出現
在微服務架構中,根據業務來拆分成一個個的服務,服務與服務之間可以相互呼叫(RPC) 。為了保證其高可用,單個服務通常會叢集部署。由於網路原因或者自身的原因,服務並不能保證100%可用,如果單個服務出現問題,呼叫這個服務就會出現執行緒阻塞,此時若有大量的請求湧入,Servlet容器的執行緒資源會被消耗完畢,導致服務癱瘓。服務與服務之間的依賴性,故障會傳播,會對整個微服務系統造成災難性的嚴重後果,這就是服務故障的“雪崩”效應。
初始接觸
新建模組hystrix
pom
<dependencies>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<!-- 將微服務provider註冊進eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
<dependency>
<groupId>springcloud</groupId>
<artifactId>springcloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- actuator監控資訊完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<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>
<!-- 修改後立即生效,熱部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
application
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml #mybatis所在路徑
type-aliases-package: com.atguigu.springcloud.entities #entity別名類
mapper-locations:
- classpath:mybatis/mapper/**/*.xml #mapper對映檔案
spring:
application:
name: microservicecloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloudDB01
username: root
password: 123321
dbcp2:
min-idle: 5
initial-size: 5
max-total: 5
max-wait-millis: 200
eureka:
client: #客戶端註冊進eureka服務列表內
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: microservicecloud-dept8001-hystrix #自定義hystrix相關的服務名稱資訊
prefer-ip-address: true #訪問路徑可以顯示IP地址
info:
app.name: atguigu-microservicecloud
company.name: www.atguigu.com
build.artifactId: $project.artifactId$
build.version: $project.version$
拷貝provider8001的mapper.xml、dao、service、controller
修改controller
package com.atguigu.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.atguigu.springcloud.entities.Dept;
import com.atguigu.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@RestController
public class DeptController
{
@Autowired
private DeptService service = null;
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
//一旦呼叫服務方法失敗並丟擲了錯誤資訊後,會自動呼叫@HystrixCommand標註好的fallbackMethod呼叫類中的指定方法
@HystrixCommand(fallbackMethod = "processHystrix_Get")
public Dept get(@PathVariable("id") Long id)
{
Dept dept = this.service.get(id);
if (null == dept) {
throw new RuntimeException("該ID:" + id + "沒有沒有對應的資訊");
}
return dept;
}
public Dept processHystrix_Get(@PathVariable("id") Long id)
{
return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的資訊,[email protected]")
.setDb_source("no this database in MySQL");
}
}
新建主啟動類
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //本服務啟動後會自動註冊進eureka服務中
@EnableDiscoveryClient //服務發現
@EnableCircuitBreaker//對hystrixR熔斷機制的支援
public class DeptProvider8001_Hystrix_App
{
public static void main