SpringCloudHystrixTurbineHystrixDashboard之前已经知道,它的主要作用是监控某个微服务,但是在实际情况下,不可能只监控一个微服务,我们有很多微服务,所以我们需要监控很多微服务。这时候就需要使用turbine[?t??ba?n]来完成;单个hystrix服务的监控(如下图):多个hystrix服务的监控(如下图):具体步骤:首先准备一个turbine模块1.创建一个34-springGCloud-service-turbine项目,还是一个Springboot项目;2.添加依赖:org.springframework.cloudspring-cloud-starter-netflix-turbine3.配置文件:server.port=3722#不注册中心自己注册eureka.client.register-with-eureka=false#eureka注册中心连接地址eureka.client.service-url.defaultZone=http://192.168.10.128:8761/eureka,http://192.168.10.128:8762/eureka,http://192.168.10.128:8763/eureka#Configureturbineturbine.app-config=34-SPRINGCLOUD-SERVICE-PORTAL,34-SPRINGCLOUD-SERVICE-PORTAL-2#需要有这个,否则无法聚合多个项目turbine.cluster-name-expression="default"4.添加到main方法的入口类注解:@EnableTurbine//开启turbine@SpringBootApplicationpublicclassTurbineApplication{publicstaticvoidmain(String[]args){SpringApplication.run(TurbineApplication.class,args);}}接下来为了监控多个使用hystrix的项目,我们准备一个项目,其中使用了hystrix:34-springGCloud-service-portal-2(可以复制一份34-springGCloud-service-portal项目来制作)注意必须先访问每一个使用hystrix的最优熔断器的功能界面,然后测试turbine,否则不访问,测试就没有数据;http://localhost:8080/cloud/goodsFeignHystrixhttp://localhost:8081/cloud/goodsLimithttp://localhost:8080/actuator/hystrix.streamhttp://localhost:8081/actuator/hystrix.streamhttp://localhost:3722/turbine.streamSpringCloudZuul通过前面内容的学习,我们基本可以搭建一个简化版的微服务架构了,我们有注册中心Eureka,可以在注册中心注册服务。我们有Ribbon或者Feign来实现对服务的负载均衡调用,我们有Hystrix来实现服务熔断;我们来看看下面的微服务架构图:在上面的架构图中,我们的服务包括:内部服务ServiceA和内部服务ServiceB,都是集群部署,每个服务部署3个实例,它们会注册和通过EurekaServerregistryService订阅,OpenService是对外服务,也是集群部署。外部调用者通过负载均衡设备调用OpenService服务。比如负载均衡使用Nginx、LVS、HAProxy。这种实现是否合理,或者有没有更好的实现方式?如何?接下来主要讨论这个问题讨论1.如果我们的微服务中有很多独立的服务需要对外提供服务,那么我们如何管理这些接口呢?尤其是项目很大的时候?2.在微服务中,一个独立的系统被拆分成许多独立的服务。为了保证安全,权限管理也是一个无法回避的问题。如果在每个服务中都添加相同的权限验证码来保证系统不被非法访问,那么工作量太大,维护起来也很不方便。为了解决上述问题,在微服务架构中提出了API网关的概念。它就像一个安全检查站。所有外部请求都需要经过它的调度过滤,然后由API网关进行请求路由、负载均衡、权限验证等。和其他功能;然后是一站式微服务开发框架SpringCloud,基于NetflixZuul实现了SpringCloudZuul,利用SpringCloudZuul可以实现一套API网关服务;ZuulZuul包括请求路由和过滤两个最重要的功能:路由功能负责将外部请求转发到具体的微服务实例,是实现外部访问统一入口的基础,过滤功能负责介入请求的处理,即实现请求校验、服务聚合等功能。基础;Zuul和Eureka是集成的,Zuul本身注册为Eureka服务治理下的一个应用,其他微服务的信息都是从Eureka获取的,也就是通过Zuul跳转之后获取未来微服务的访问权限。路由功能:项目加入依赖:org.springframework.cloudspring-cloud-starter-netflix-eureka-clientorg.springframework.cloudspring-cloud-starter-netflix-zuul由于Zuul最终会注册到eureka中,所以我们这里也依赖eureka;配置文件:server.port=80#是eureka注册中心首页Application的Spring一栏.application.name=34-springGCloud-service-zuul#每隔2s向服务器发送一次心跳,证明你是still"surviving"eureka.instance.lease-renewal-interval-in-seconds=2#告诉服务器,如果我在10s内没有给你发送心跳,就意味着我倒下了,把我踢出eureka.instance。lease-expiration-duration-in-seconds=10#告诉服务器服务实例使用IP作为链接,而不是取机器名eureka.instance.prefer-ip-address=true#告诉服务器服务实例的id服务实例必须是唯一的,即eureka注册中心首页的Status栏eureka.instance.instance-id=34-sprinGCloud-service-zuul#eureka注册中心连接地址eureka.client.service-url.defaultZone=http://192.168.10.128:8761/eureka,http://192.168.10.128:8762/eureka,http://192.168.10.128:8763/eureka在启动类上:@EnableZuulProxy@SpringBootApplicationpublicclassZuulApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ZuulApplication.class,args);}}这样一个简单的zuul就搭建好了,我们可以通过zuul来访问微服务,并添加对应的微服务名称来启动项目,比如:http://localhost/34-sprinGCloud-service-portal/cloud/goodsFeignhttp://localhost:80/这个是zuul本身的34-sprinGCloud-service-portal这个是要调用的项目名/cloud/goodsFeign这个是被调用控制器上的接口路径;在实际开发中,我们肯定不会通过微服务名来调用它。比如我要调用消费者,我可能只需要一个/cloud/goodsFeign,而不是/34-springGCloud-service-Portal/cloud/goodsFeign可以加入如下配置:#Configureroutingruleszuul.routes。portal.service-id=34-springGCloud-service-portalzuul.routes.portal.path=/portal/**然后:http://localhost/portal/cloud/goodsFeignHystrix/**代表所有(多个)层/cloud/goodsFeignHystrix/*代表一层;如果是/*,/api/goods将不会被路由;这个时候,我们可以通过Defined规则来访问,但是我们仍然可以用之前的微服务名来调用,这是不合理的。首先,有多个地址。第二,一般的微服务名最好不要暴露,所以我们一般都会禁用微服务名调用添加配置:zuul.ignored-services=34-springGCloud-service-portal这里可以发现我们不能通过微服务名来调用,但是如果通过微服务名一个一个配置这个配置,难免有点比较复杂,所以一般是这样配置Disableall:zuul.ignored-services=*可能有时候我们的接口调用需要一定的规范,比如调用微服务的APIURL前缀需要加上/api针对这种情况,zuul也考虑了一下,给出了解决方案:zuul.prefix=/api例如:http://localhost/api/portal/cloud/goodsFeignHystrixwildcardfilter:限流,权限验证,日志过滤器(filter)是zuul的核心组件,zuul的大部分功能都是通过过滤器来实现的。Zuul中定义了4种标准过滤器类型,它们对应于请求的典型生命周期。PRE:在路由请求之前调用此过滤器。该过滤器可用于实现身份验证、在集群中选择请求的微服务、记录调试信息等。ROUTING:该过滤器将请求路由到微服务。该过滤器用于构造发送到微服务的请求,使用ApacheHttpClient或NetfilxRibbon请求微服务POST:路由到微服务后执行该过滤器。此类过滤器可用于将标准HTTP标头添加到响应、收集统计信息和指标、从微服务向客户端发送响应等等。ERROR:当另一个阶段发生错误时执行此过滤器。如果要编写一个过滤器,则需继承ZuulFilter类实现其中的方法:@ComponentpublicclassLogFilterextendsZuulFilter{@OverridepublicStringfilterType(){returnFilterConstants.ROUTE_TYPE;}@OverridepublicintfilterOrder(){returnFilterConstants.PRE_DECORATION_FILTER_ORDER;}@OverridepublicbooleanshouldFilter(){returntrue;}@OverridepublicObjectrun()throwsZuulException{RequestContextcurrentContext=RequestContext.getCurrentContext();HttpServletRequestrequest=currentContext.getRequest();StringremoteAddr=request.getServerName();System.out.println("访问地址:"+request.getRequestURI());returnnull;}从代码中可以看出,自定义zuulFilter需要实现如下方法。filterType:返回过滤器的类型。有pre、route、post、error等几个值,分别对应上面几个filter。具体可以参考com.netflix.zuul.ZuulFilter.filterType()中的注释;filter0rder:返回一个int值指定过滤器的执行顺序,不同的过滤器允许返回相同的数字。shouldFilter:返回一个布尔值,判断过滤器是否应该执行,true表示执行,false表示不执行。run:过滤器的具体逻辑;zuul过滤器的禁用SpringCloud默认为Zuul编写和启用了一些过滤器,如DebugFilter、FormBodyWrapperFilter等,这些过滤器存放在spring-cloud-netflix-zuul的jar包中,在某些场景下,我应该怎么做如果我想禁用某些过滤器怎么办?只需在application.properties中设置zuul...disable=true即可。例如,要禁用我们上面写的过滤器,只需这样配置:zuul。LogFilter.route.disable=trueZuul的异常处理SpringCloudZuul处理异常非常方便。但由于SpringCloud发展较快,版本之间存在差异。本案例以Finchley.RELEASE版本为例。来说明SpringCloudZuul中的异常处理问题。首先我们看一张Zuul官方请求的生命周期图:1、正常情况下,所有的请求都是按照pre、route、post的顺序执行,然后post返回response2。在pre阶段,如果有自定义过滤器,则执行自定义过滤器3。如果pre、routing、post任一阶段抛出异常,则执行error过滤器。我们可以统一处理异常:如何实现,步骤:1.禁用zuul默认的异常处理SendErrorFilter过滤器,然后自定义我们自己的Errorfilter过滤器zuul.SendErrorFilter.error.disable=true@ComponentpublicclassErrorFilterextendsZuulFilter{@OverridepublicStringfilterType(){return"error";}@OverridepublicintfilterOrder(){return1;}@Overridephouleans{returntrue;}@OverridepublicObjectrun()throwsZuulException{try{RequestContextcontext=RequestContext.getCurrentContext();ZuulExceptionexception=(ZuulException)context.getThrowable();System.out.println("进入系统异常拦截"+exception.getMessage());HttpServletResponseresponse=context.getResponse();response.setContentType("application/json;charset=utf8");response.setStatus(exception.nStatusCode);PrintWriterwriter=null;try{writer=response.getWriter();writer.print("{code:";+exception.nStatusCode+",message:\""+exception.getMessage()+"\"}");}catch(IOExceptione){e.printStackTrace();}finally{if(writer!=null){writer.错误信息,比如被调用的微服务停止了;一般情况下,服务方会自己进行服务的熔断降级,但是对于zuul本身,也应该进行zuul降级处理;我们需要一个zuul降级,实现方式如下:.set("Content-Type","text/html;charset=UTF-8");returnheaders;}@OverridepublicInputStreamgetBody()throwsIOException{//响应体returnnewByteArrayInputStream("服务正在维护中,请稍后重试。".getBytes());}@OverridepublicHttpStatusgetStatusCode()throwsIOException{returnHttpStatus.BAD_REQUEST;}@OverridepublicintgetRawStatusCode()throwsIOException{returnHttpStatus.BAD_REQUEST.value();}@OverridepublicStringgetStatusText()throwsIOException{returnHttpStatus.BAD_REQUEST.getReasonPhrase();}@Overridepublicvoidclose(){}};}}