Spring Cloud入门1——Eureka&Ribbon&Hystrix

上篇中,主要了解了Spring Cloud的一些简单组件以及他们的功能。

现在动手简单的使用一下Spring Cloud的一些组件。


服务发现:(Eureka)

前面提到,Eureka分为服务端和客户端,服务端是服务注册中心,而客户端是提供服务的。


创建服务注册中心(服务端)

首先在pom文件中加入以下依赖:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.3.8.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka-server</artifactId>
	</dependency>
</dependencies>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Brixton.SR7</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
在Application文件中增加@EnableEurekaServer注解,表明这是服务端

@EnableEurekaServer
@SpringBootApplication
public class SpringcloudEurekaServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringcloudEurekaServerApplication.class, args);
	}
}
在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为。在application.properties或yml中禁止客户端注册行为,否则会报错。

server.port=1111

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/

服务端就写好了,可以访问localhost:1111进行访问。可以看到,这时候是没有服务的。



接下来创建客户端

创建客户端,并在注册中心中注册自己。

还是首先添加依赖:这里和上面不同的地方只有对Eureka的依赖。

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.3.8.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>


<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Brixton.SR7</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
在Application文件中加入@EnableDiscoveryClient注解,表明这是一个客户端。

@EnableDiscoveryClient
@SpringBootApplication
public class SpringcloudEurekaServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringcloudEurekaServiceApplication.class, args);
	}
}
然后我们需要向注册中心中注册自己,只需要在application.properties或yml文件中增加配置即可:

spring.application.name=compute-service
server.port=2222
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
defaultZone指定了服务注册中心的位置。

注册了之后我们就可以在客户端编写客户端提供的服务了。比如这里提供了add加法服务。

@RestController
public class ComputeController {
	
    private final Logger logger = Logger.getLogger(getClass());
    
    @Autowired
    private DiscoveryClient client;
    
    @RequestMapping(value = "/add" ,method = RequestMethod.GET)
    public Integer add(@RequestParam Integer a, @RequestParam Integer b) {
        ServiceInstance instance = client.getLocalServiceInstance();
        Integer r = a + b;
        logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);
        return r;
    }
}
在提供的服务中,只需要使用DiscoveryClient就可以得到关于调用者的信息。

客户端也完成了,这个时候可以再次访问localhost:1111。


可以发现,客户端已经在服务端上注册了。


我们看一下架构图:


很显然,工作流程是这样的:Service Consumer -> Proxy Server -> Client(Load Balancer) -> Servie Discovery -> Target Service

我们编写好了上图的红色的部分,接下来应该对服务进行负载均衡了,也就是对客户端的负载均衡,我们使用Ribbon来完成这件事。

首先我们启动服务端和两个客户端,客户端分别开在2222和2223端口。即:


开启了两个服务,接下来我们使用Ribbon进行负载均衡。


新建一个项目。

在pom文件中添加如下依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</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>
        <scope>test</scope>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
	    <groupId>org.springframework.cloud</groupId>
	    <artifactId>spring-cloud-dependencies</artifactId>
	    <version>Brixton.RELEASE</version>
	    <type>pom</type>
	    <scope>import</scope>
	</dependency>
    </dependencies>
</dependencyManagement>
使用@EnableDiscoveryClient注解在将其注册在注册中心。并且提供一个返回RestTemplate的bean实例,使用@LoadBalanced注解对这个实例进行负载均衡这样,使用这个实例去获取服务的时候,就会帮我们进行负载均衡了。
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
	
	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
	
	public static void main(String[] args) {
		SpringApplication.run(RibbonApplication.class, args);
	}
}

在application.properties中注册:

spring.application.name=ribbon-consumer
server.port=3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

创建了bean实例,我们就可以通过@Autowired来获取这个RestTemplate了,并且使用这个实例去调用服务。
@RestController
public class ConsumerController {
	
    @Autowired
    RestTemplate restTemplate;
    
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add() {
        return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
    }
}
启动这个项目,并且访问多次localhost:3333/add可以发现确实进行了负载均衡。


在微服务架构中,服务被拆分成一个一个的单元,各个单元之间相互依赖调用。如果某个单元由于网络原因或者别的单元故障奔溃,那么会直接导致调用方对外的服务也发生延迟。若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,最终导致自身服务的瘫痪,这样的结构相对于传统的web开发模式来说更加可怕,为了解决这个问题,我们可以采用断路器。

在分布式架构中,当某个服务单元发生故障,使用断路器返回一个错误的相应,而不是进行长时间的等待,这样就不会使得线程被长时间占用,导致服务器的瘫痪。

Spring Cloud提供了Hystrix这么一个组件来实现断路器的功能。


首先启动Eureka服务端和客户端。

对Ribbon的项目进行以下修改:

首先在pom文件中增加以下依赖:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
在application中增加@EnableCircuitBreaker注解,表明使用断路器。

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {
	
	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
	
	public static void main(String[] args) {
		SpringApplication.run(RibbonApplication.class, args);
	}
}
Hystrix使用消息队列的方式,如果连接的服务崩溃,则异步回调某个方法进行处理。

新增一个Service类,在这个类中定义好如何访问,以及失败之后的返回等。

@Service
public class ComputeService {
	
    @Autowired
    RestTemplate restTemplate;
    
    @HystrixCommand(fallbackMethod = "addServiceFallback")
    public String addService() {
        return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
    }
    
    public String addServiceFallback() {
        return "error";
    }
}
这里重点是@HystrixCommand注解:表明该方法为hystrix包裹,可以对依赖服务进行隔离、降级、快速失败、快速重试等等hystrix相关功能

列举几个属性:
1. fallbackMethod 降级方法
2. commandProperties 普通配置属性,可以配置HystrixCommand对应属性,例如采用线程池还是信号量隔离、熔断器熔断规则等等
3. ignoreExceptions 忽略的异常,默认HystrixBadRequestException不计入失败
4. groupKey() 组名称,默认使用类名称
5. commandKey 命令名称,默认使用方法名

最后修改一下Controller即可:

@RestController
public class ConsumerController {
	
	@Autowired
    private ComputeService computeService;
	
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add() {
    	return computeService.addService();
    }
}
对于断路器,针对生产环境,,Netflix还给我们准备了一个非常好用的运维工具, 那就是Hystrix Dashboard和Turbine.可以帮助我们更好的观察。


当客户端关闭时访问:


客户端启动时访问:


成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值