目录:
SpringCloud基础(0)
SpringCloud基础(1)
SpringCloud基础(2)
SpringCloud基础(3)
SpringCloud基础(4)
SpringCloud基础(5)
6 服务注册中心Consul
前文中介绍了Spring Cloud的核心组件,包括服务注册与发现组件Eureka,熔断器Hystrix,配置中心Spring Cloud Config和服务网关Zuul。
在前文的基础上进行工作。先将Spring Cloud的版本进行升级:将pom.xml中的parent模块版本升级为1.5.4.RELEASE,同时将spring-cloud-dependencies组件升级为Dalston.SR1版本。
Spring Cloud Consul是一个服务发现框架,与Eureka作用类似。当然常用的服务发现框架或者说服务注册中心还有Zookeeper,etcd等。对比图如下:
各个框架的具体差异就不讨论了,这里用Consul替换掉前文中的Eureka。
从官网https://www.consul.io/downloads.html下载consul服务注册中心。以开发模式启动consul:
consul agent –dev
打开http://localhost:8500,可以看到consul的ui界面。
将服务提供者的依赖模块替换:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</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-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后修改配置文件为:
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
服务接口修改为:
@RestController
public class ComputeController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
DiscoveryClient discoveryClient;
@GetMapping("/dc")
public String dc() {
String services = "Services: " + discoveryClient.getServices();
System.out.println(services);
return services;
}
}
服务消费者依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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-actuator</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>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置文件:
spring.application.name=consul-consumer
server.port=2101
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
服务消费者主类:
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
new SpringApplicationBuilder(ConsumerApplication.class).web(true).run(args);
}
}
消费接口类:
@RestController
public class ConsumerController {
@Resource
LoadBalancerClient loadBalancerClient;
@Resource
RestTemplate restTemplate;
@GetMapping("/consumer")
public String dc() {
ServiceInstance serviceInstance = loadBalancerClient.choose("consul-provider1");
String url = "http://" + serviceInstance.getHost()+ ":" + serviceInstance.getPort() + "/dc";
System.out.println(url);
return restTemplate.getForObject(url, String.class);
}
}
分别启动服务提供者和服务消费者,访问http://localhost:2101/consumer。返回Services: [consul, consul-consumer, consul-provider1]。
以上是以consul作为注册中心,如果采用eureka作为注册中心的话,除了eureka注册中心需要自己构建外,其他基本一样。
7 Hystrix监控
在前面介绍过,断路器根据快照时间窗口内的请求情况来判断是否需要进行熔断,而这些请求情况的指标信息都是HystrixCommand和HystrixObservableCommand实例在执行过程中记录的重要度量信息,它们除了Hystrix断路器实现中使用以外,对于系统运维也有非常大的帮助。这些指标信息会以“滚动时间窗”与“桶”结合的方式进行汇总,并在内存中驻留一段时间,以供内部或外部进行查询使用,Hystrix Dashboard就是这些指标内容的消费者。
创建一个服务实例my-consumer3。这里仍然以eureka为注册中心,添加依赖:
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Dalston.SR1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>
配置文件为:
spring.application.name=consumer3
server.port=2103
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
控制器为:
@RestController
public class ConsumerController {
@Resource
ConsumerService consumerService;
@GetMapping("/consumer")
public String dc() {
return consumerService.consumer();
}
@Service
class ConsumerService {
@Resource
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "fallback")
public String consumer() {
return restTemplate.getForObject("http://compute-service/add?a=1&b=2", String.class);
}
public String fallback() {
return "fallbck";
}
}
}
主类需要开启@EnableCircuitBreaker注解:
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ConsumerApplication3 {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication3.class,args);
}
}
启动服务注册中心和compute-service服务实例及本实例之后,可以通过调用本实例提供的consumer接口进而调用compute-service服务。
接着创建mysc-hystrixdashboard实例。依赖:
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Dalston.SR1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
配置文件:
spring.application.name=hystrix-dashboard
server.port=1301
主类:
@SpringCloudApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class,args);
}
}
实际上,官方也提供了监控包:hystrix-dashboard-#.#.#.war,下载后放到服务器上,一样地使用。不过这里为了方便就使用自己创建的监控实例。
启动hystrix监控实例,访问http://localhost:1301后可以看到Hystrix Dashboard首页。从首页描述可以得知,Hystrix Dashboard支持三种不同的监控方式,分别是:
默认的集群监控:通过URLhttp://turbine-hostname:port/turbine.stream开启,实现对默认集群的监控。
指定的集群监控:通过URLhttp://turbine-hostname:port/turbine.stream?cluster=[clusterName]开启,实现对clusterName集群的监控。
单体应用的监控:通过URLhttp://hystrix-app:port/hystrix.stream开启,实现对具体某个服务实例的监控。
对集群的监控需要整合turbine才能实现。这里先看对单个服务实例的监控。再consumer3实例中引入了actuator和hystrix依赖包,因此可以实现对该实例的hystrix监控。
7.1 单实例监控
启动consumer3,调用一次consumer3提供的consumer接口(如果一次都没调用,监控页面就一直在loading中)。接着访问http://localhost:1301/hystrix,在输入框中输入要监控的实例地址:http://localhost:2103/hystrix.stream,可以看到该实例的hystrix监控信息。
监控台首页中有两个参数,分别是Delay和Title。其中Delay是用来控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性降低客户端的网络和cpu消耗。Title对应了监控地址的内容,默认使用具体监控实例的url,可以通过配置该信息来展示更合适的标题。
具体实例的监控页面可以看到一个实心圆和一条曲线。
实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,其健康度从绿色,黄色,橙色。红色依次递减。同时,实心圆的大小随着请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的大小和颜色,可以在大量实例中快速发现故障实例和高压力实例。
曲线:用来记录两分钟内流量的相对变化,可以通过它来观察流量的上升和下降趋势。
其他:竖线隔开的两列数字,左边的依次代表请求成功数,短路和熔断数。右边的依次代表请求超时数,线程池拒绝数和失败/异常数。右边百分数代表最近10秒的错误比例。Host和Cluster数值表示该主机和集群上的请求频率,Circuit表示断路器状态。最下面左侧的是集群下的主机报告,右侧的是百分比延迟统计。
7.2 监控数据聚合
在实际的生产环境中有多个实例,对多实例需要将度量指标数据进行聚合,因此需要整合turbine。
在前文的hystrix监控例子中,实现的架构如下图所示:
在上述架构基础上,引入Turbine来对服务的Hystrix数据进行聚合展示。聚合方式有两种。
通过HTTP收集聚合
创建turbine工程,依赖为:
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Dalston.SR1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
创建应用主类TurbineApplication,并使用@EnableTurbine注解开启Turbine:
@Configuration
@EnableAutoConfiguration
@EnableTurbine
@EnableDiscoveryClient
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
在application.properties加入eureka和turbine的相关配置,具体如下:
spring.application.name=turbine
server.port=8989
management.port=8990
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
turbine.app-config=consumer3
turbine.cluster-name-expression="default"
turbine.combine-host-port=true
参数说明:
turbine.app-config指定了需要收集监控信息的服务名。
turbine.cluster-name-expression指定了集群名称为default,当服务数量非常多时,可以启动多个turbine服务来构建不同的聚合集群,而该参数可以用来区分这些不同的聚合集群,同时该参数可以在Hystrix仪表盘中定位不同的聚合集群,只需要在Hystrix Stream的URL中通过cluster参数来指定。
turbine.combine-host-port设置为true,可以让同一主机上的服务通过主机名与端口号的组合来进行区分,默认情况下以host来区分不同的服务,这会使得在本地调试时本机上的不同服务聚合成一个服务来统计。
启动服务注册中心server1和server2,服务提供者provider2,服务消费者consumer3,Hystrix监控以及turbine聚合实例,在http://localhost:1301/hystrix监控首页中输入http://localhost:8989/turbine.stream后进行监控,将会看到针对服务consumer3的聚合数据监控。架构为:
通过消息代理收集聚合
Spring Cloud在封装turbine的时候,还实现了基于消息代理的收集实现。因此可以将所有需要收集的监控信息都输出到消息代理中,然后turbine服务再从消息代理中异步的获取这些监控信息,最后将这些监控信息聚合并输出到Hystrix Dashboard中。通过引入消息代理,Turbine和Hystrix Dashboard实现的监控架构可以改成如下:
创建一个maven工程,名为mysc-turbinemq。在pom.xml中添加依赖:
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Dalston.SR1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
这里的spring-cloud-starter-turbine-amqp实际上包装了spring-cloud-starter-turbine-stream和pring-cloud-starter-stream-rabbit。
在主类中开启@EnableTurbineStream注解:
@SpringBootApplication
@EnableAutoConfiguration
@EnableTurbineStream
public class TurbinemqApplication {
public static void main(String[] args) {
SpringApplication.run(TurbinemqApplication.class,args);
}
}
配置application.properties文件:
spring.application.name=turbine-amqp
server.port=8989
management.port=8990
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
然后在消费者consumer3中的pom.xml文件修改一下,添加对amqp的依赖,使监控信息能输出到消息队列里:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-hystrix-amqp</artifactId>
</dependency>
然后停止前文的turbine聚合实例,启动turbinemq实例,访问监控页面,可以实现同样的监控效果,但这里的监控信息收集是通过消息代理异步实现的。
代码地址:https://github.com/howetong/mysc/tree/branch1