1. 程式人生 > >Springcloud負載均衡feign與Hystrix斷路器(四)

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