前言介绍
Hystrix Dashboard 可以定时收集接口调用信息;时长、次数、性能、熔断等各项指标来进行监控展示,但是我们每次监控都需要输入一个Hystrix 的链接例如:http://localhost:9001/actuator/hystrix.stream,但是这样并不利于我们去做整体服务的监控,并且在实际使用的过程中如果是几十到几百个接口那么这样的监控几乎达不到监控效果,就累死在监控路上了。因此我们需要使用到 Turbine 来进行监控信息聚合,可以按业务组定义配置方便监控。
案例说明
案例通过添加itstack-demo-springcloud-turbine工程模块,将单体监控汇总在统一页面进行管理,此时的监控模型,如图;
环境准备
- jdk 1.8、idea2018、Maven3
- Spring Boot 2.0.6.RELEASE
- Spring Cloud Finchley.SR2
代码示例
1itstack-demo-springcloud-05 2├── itstack-demo-springcloud-eureka-client 3│ └── src 4│ └── main 5│ ├── java 6│ │ └── org.itstack.demo 7│ │ ├── web 8│ │ │ └── EurekaClientController.java 9│ │ └── EurekaClientApplication.java 10│ └── resources 11│ └── application.yml 12├── itstack-demo-springcloud-eureka-server 13│ └── src 14│ └── main 15│ ├── java 16│ │ └── org.itstack.demo 17│ │ └── EurekaServerApplication.java 18│ └── resources 19│ └── application.yml 20├── itstack-demo-springcloud-hystrix-dashboard 21│ └── src 22│ └── main 23│ ├── java 24│ │ └── org.itstack.demo 25│ │ └── DashboardApplication.java 26│ └── resources 27│ └── application.yml 28├── itstack-demo-springcloud-hystrix-feign 29│ └── src 30│ └── main 31│ ├── java 32│ │ └── org.itstack.demo 33│ │ ├── service 34│ │ │ ├── hystrix 35│ │ │ │ └── FeignServiceHystrix.java 36│ │ │ └── FeignService.java 37│ │ ├── web 38│ │ │ └── FeignController.java 39│ │ └── FeignApplication.java 40│ └── resources 41│ └── application.yml 42├── itstack-demo-springcloud-hystrix-ribbon 43│ └── src 44│ └── main 45│ ├── java 46│ │ └── org.itstack.demo 47│ │ ├── service 48│ │ │ └── RibbonService.java 49│ │ ├── web 50│ │ │ └── RibbonController.java 51│ │ └── RibbonApplication.java 52│ └── resources 53│ └── application.yml 54└── itstack-demo-springcloud-turbine 55 └── src 56 └── main 57 ├── java 58 │ └── org.itstack.demo 59 │ └── TurbineApplication.java 60 └── resources 61 └── application.yml
完整代码欢迎关注公众号:bugstack虫洞栈 | 回复“SpringCloud专题”进行下载
itstack-demo-springcloud-eureka-client | 服务提供方
提供一个查询用户信息的简单方法,在配置文件中通过修改端口启动2次,模拟双实例应用,为调用方负载做准备。
web/EurekaClientController.java | 注意@EnableEurekaClient用于向注册中心提供服务
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@EnableEurekaClient 7@RestController 8public class EurekaClientController { 9 10 @Value("${server.port}") 11 private int port; 12 13 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 14 public String queryUserInfo(@RequestParam String userId) { 15 return "Hi 微信公众号:bugstack虫洞栈 | " + userId + " >: from eureka client port: " + port; 16 } 17 18}
EurekaClientApplication.java | 服务启动类
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7public class EurekaClientApplication { 8 9 public static void main(String[] args) { 10 SpringApplication.run(EurekaClientApplication.class, args); 11 } 12 13}
application.yml | 配置文件链接服务注册中心,8001\8002分别配置启动
1server: 2 port: 8001 / 8002 3 4spring: 5 application: 6 name: itstack-demo-springcloud-eureka-client 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/
itstack-demo-springcloud-eureka-server | 单个服务注册中心
服务注册中心用于承载接口提供方向上注册,同时正在调用方链接后可以获取指定应用的服务实例。
EurekaServerApplication.java | 通过注解@EnableEurekaServer启动服务注册与发现中心
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaServer 8public class EurekaServerApplication { 9 10 public static void main(String[] args) { 11 SpringApplication.run( EurekaServerApplication.class, args ); 12 } 13 14}
application.yml | 服务注册中心配置文件,端口7397和我们之前写netty的服务的端口一致
1server: 2 port: 7397 3 4eureka: 5 instance: 6 hostname: localhost 7 client: 8 registerWithEureka: false 9 fetchRegistry: false 10 serviceUrl: 11 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 12 13spring: 14 application: 15 name: itstack-demo-springcloud-eureka-server
itstack-demo-springcloud-hystrix-dashboard | 服务监控像仪表盘一样透视系统健康度
Spring Cloud Hystrix Dashboard只是spring cloud基于Hystrix Dashboard,将实时监控数据通过页面呈现出来。Spring Cloud Hystrix Dashboard的底层原理是间隔一定时间去“Ping”目标服务,返回的结果是最新的监控数据,最后将数据显示出来。
1Cluster via Turbine (default cluster): http://turbine-hostname:port/turbine.stream 2Cluster via Turbine (custom cluster): http://turbine-hostname:port/turbine.stream?cluster=[clusterName] 3Single Hystrix App: http://hystrix-app:port/actuator/hystrix.stream 4
DashboardApplication.java | 配置@EnableHystrixDashboard启动服务
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@EnableHystrixDashboard 7@SpringBootApplication 8public class DashboardApplication { 9 10 public static void main(String[] args) { 11 SpringApplication.run(DashboardApplication.class, args); 12 } 13 14}
application.yml | 通用配置信息
1server: 2 port: 8989 3 4spring: 5 application: 6 name: itstack-demo-springcloud-hystrix-dashboard
itstack-demo-springcloud-feign | Feign服务调用方,添加熔断Hystrix
Feign 是一个声明式的 Web Service 客户端,它的目的就是让 Web Service 调用更加简单。它整合了 Ribbon 和 Hystrix,从而让我们不再需要显式地使用这两个组件。Feign 还提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,我们就可以定义好 HTTP 请求的参数、格式、地址等信息。接下来,Feign 会完全代理 HTTP 的请求,我们只需要像调用方法一样调用它就可以完成服务请求。
Feign 具有如下特性:
可插拔的注解支持,包括 Feign 注解和 JAX-RS 注解
支持可插拔的 HTTP 编码器和解码器
支持 Hystrix 和它的 Fallback
支持 Ribbon 的负载均衡
支持 HTTP 请求和响应的压缩
service/FeignService.java | 注解方式调用,方便易用。@FeignClient会在调用时进行解析服务到具体的http://ip:port/
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@FeignClient(value = "itstack-demo-springcloud-eureka-client", fallback = FeignServiceHystrix.class) 7public interface FeignService { 8 9 @RequestMapping(value = "/api/queryUserInfo", method = RequestMethod.GET) 10 String queryUserInfo(@RequestParam String userId); 11 12}
service/hystrix/FeignServiceHystrix.java | 提供熔断服务,当发生异常时主动返回预定结果
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@Component 7public class FeignServiceHystrix implements FeignService { 8 9 @Override 10 public String queryUserInfo(String userId) { 11 return "queryUserInfo by userId:" + userId + " err!from feign hystrix"; 12 } 13 14}
web/FeignController.java | 使用接口提供服务 From Feign
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@RestController 7public class FeignController { 8 9 @Resource 10 private FeignService ribbonService; 11 12 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 13 public String queryUserInfo(@RequestParam String userId) { 14 return ribbonService.queryUserInfo(userId) + " From Feign"; 15 } 16 17}
FeignApplication.java | 注解@EnableEurekaClient、@EnableFeignClients、@EnableDiscoveryClient获取调用注册中心服务
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaClient 8@EnableDiscoveryClient 9@EnableFeignClients 10@EnableHystrix 11public class FeignApplication { 12 13 public static void main(String[] args) { 14 SpringApplication.run(FeignApplication.class, args); 15 } 16 17}
application.yml | eureka服务配置,从注册中心获取可用服务。开启hystrix=true,并设置hystrix.stream
1server: 2 port: 9001 3 4spring: 5 application: 6 name: itstack-demo-springcloud-feign 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/ 12 13feign.hystrix.enabled: true 14 15management: 16 endpoints: 17 web: 18 exposure: 19 include: hystrix.stream
itstack-demo-springcloud-ribbon | Ribbon服务调用方
Ribbon是一个基于 HTTP 和 TCP 的客户端负载均衡器。它可以通过在客户端中配置 ribbonServerList 来设置服务端列表去轮询访问以达到均衡负载的作用。
当 Ribbon 与 Eureka 联合使用时,ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心中获取服务实例列表。同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动。
service/RibbonService.java | 接口式硬编码调用不太易于维护,因此也是比较少用的方式。hystrix实际通过getFallback()返回熔断结果
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@Service 7public class RibbonService { 8 9 @Autowired 10 private RestTemplate restTemplate; 11 12 @HystrixCommand(fallbackMethod = "queryUserInfoFallback") 13 public String queryUserInfo(String userId) { 14 return restTemplate.getForObject("http://ITSTACK-DEMO-SPRINGCLOUD-EUREKA-CLIENT/api/queryUserInfo?userId=" + userId, String.class); 15 } 16 17 /** 18 * Specifies a method to process fallback logic. 19 * A fallback method should be defined in the same class where is HystrixCommand. 20 * Also a fallback method should have same signature to a method which was invoked as hystrix command. 21 * for example: 22 * <code> 23 * @HystrixCommand(fallbackMethod = "getByIdFallback") 24 * public String getById(String id) {...} 25 * 26 * private String getByIdFallback(String id) {...} 27 * </code> 28 * Also a fallback method can be annotated with {@link HystrixCommand} 29 * <p/> 30 * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()} 31 * 32 * @return method name 33 * 34 * getFallback() 35 * 36 * @Override 37 * protected Object getFallback() { 38 * final CommandAction commandAction = getFallbackAction(); 39 * if (commandAction != null) { 40 * try { 41 * return process(new Action() { 42 * @Override 43 * Object execute() { 44 * MetaHolder metaHolder = commandAction.getMetaHolder(); 45 * Object[] args = createArgsForFallback(metaHolder, getExecutionException()); 46 * return commandAction.executeWithArgs(metaHolder.getFallbackExecutionType(), args); 47 * } 48 * }); 49 * } catch (Throwable e) { 50 * LOGGER.error(FallbackErrorMessageBuilder.create() 51 * .append(commandAction, e).build()); 52 * throw new FallbackInvocationException(unwrapCause(e)); 53 * } 54 * } else { 55 * return super.getFallback(); 56 * } 57 * } 58 */ 59 public String queryUserInfoFallback(String userId) { 60 return "queryUserInfo by userId:" + userId + " err!from ribbon hystrix"; 61 } 62 63}
web/RibbonController.java | 使用接口提供服务 From Ribbon
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@RestController 7public class RibbonController { 8 9 @Resource 10 private RibbonService ribbonService; 11 12 @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET) 13 public String queryUserInfo(@RequestParam String userId) { 14 return ribbonService.queryUserInfo(userId) + " From Ribbon"; 15 } 16 17}
RibbonApplication.java | 通过注解@LoadBalanced注册rest模版,用于Ribbon接口调用。并启动@EnableHystrix
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@SpringBootApplication 7@EnableEurekaClient 8@EnableDiscoveryClient 9@EnableHystrix 10public class RibbonApplication { 11 12 public static void main(String[] args) { 13 SpringApplication.run(RibbonApplication.class, args); 14 } 15 16 @Bean 17 @LoadBalanced 18 RestTemplate restTemplate() { 19 return new RestTemplate(); 20 } 21 22}
application.yml | eureka服务配置,从注册中心获取可用服务
1server: 2 port: 9002 3 4spring: 5 application: 6 name: itstack-demo-springcloud-ribbon 7 8eureka: 9 client: 10 serviceUrl: 11 defaultZone: http://localhost:7397/eureka/
itstack-demo-springcloud-turbine | 监控信息聚合服务
通过配置汇总,将应用itstack-demo-springcloud-feign,itstack-demo-springcloud-ribbon,汇总监控。
TurbineApplication.java | 通过注解@EnableTurbine配置启动Ribbon
1/** 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例 3 * 论坛:http://bugstack.cn 4 * Create by 付政委 on @2019 5 */ 6@EnableTurbine 7@SpringBootApplication 8public class TurbineApplication { 9 10 public static void main(String[] args) { 11 SpringApplication.run(TurbineApplication.class, args); 12 } 13 14}
application.yml | eureka服务配置,从注册中心获取可用服务
1spring: 2 application: 3 name: itstack-demo-springcloud-turbine 4 5server: 6 port: 8080 7 8management: 9 port: 8081 10 11## 服务注册中心 12eureka: 13 client: 14 service-url: 15 defaultZone: http://localhost:7397/eureka 16 17## 监控汇总配置,这里配置2个应用逗号隔开 18turbine: 19 app-config: itstack-demo-springcloud-feign,itstack-demo-springcloud-ribbon 20 cluster-name-expression: new String("default") 21 combine-host-port: true
测试验证
- 启动itstack-demo-springcloud-hystrix-dashboard,访问;http://localhost:8989/hystrix
- 分别启动如下系统模拟;
- itstack-demo-springcloud-eureka-server 服务注册发现中心
- itstack-demo-springcloud-eureka-client 测试接口提供方
- itstack-demo-springcloud-hystrix-feign 接口调用方Feign
- itstack-demo-springcloud-hystrix-ribbon 接口调用方Ribbon
- itstack-demo-springcloud-turbine 监控信息汇总
- 测试监控
- 在hystrix-dashboard监控页面{http://localhost:8989/hystrix},输入;http://localhost:8080/turbine.stream
- 刷新访问两个调用方接口;http://localhost:9001/api/queryUserInfo?userId=111、http://localhost:9002/api/queryUserInfo?userId=111
- 回看刚才的监控页面;http://localhost:8989/hystrix/monitor?stream=http%3A%2F%2Flocalhost%3A8080%2Fturbine.stream,已经可以看到监控信息汇总,如图;
微信公众号:bugstack虫洞栈 & 监控信息汇总
综上总结
- 通过Turbine服务我们可以将监控信息汇总到一起进行查看,这样更加方便实际应用。
- SpringCloud 到现在的案例已经使用到了很多服务模块,它确实是一套有序集合框架,将各家优秀功能服务集成,方便使用。
- SpringBoot 、 SpringCloud,在开发一些中小型独立服务非常边界,对于一些超大型以外的公司非常合适。当然并不是一线互联网就不使用,因为这里面还牵扯到很多对应的替代产品,比如Dubbo、网关、全链路监控、路由等等,所以需要根据不同业务进行技术选型,不要被技术限制。