用springcloud zuul ribbon集群服务的时候遇到的坑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用springcloud zuul ribbon集群服务的时候遇到的坑相关的知识,希望对你有一定的参考价值。

参考技术A 使用zuul网关做服务映射的时候,部署了3个相同service   端口分别是:8769 8770 8771  当我们断掉8769服务的时候,ribbon按理说会认定8769断掉了,从而后面的请求不会再命中8769这个服务端口。然而并不是想的那样,还是一样会命中失败的服务。直接跳坑了~

做集群映射离不开eureka,以上三个服务都注册在eureka,当8769断掉后,eureka自身有心跳检测,默认是15分钟,如果服务在15分钟内没有响应则认定该服务出现故障,即下线该服务。在这期间ribbon把请求还是一样会均衡各个集群节点,因为它获取节点是否正常是通过eureka中心得到的,所以eureka如果没有下线服务,那么ribbon会一直认为该服务在线。那么这种情况怎么处理呢?

在eureka项目yml 设置eureka.server.enableSelfPreservation = false  关闭自我保护机制

在service项目yml  设置 eureka.instance.leaseRenewalIntervalInSeconds = 5 

                                                                leaseExpirationDurationInSeconds = 10

Eureka+Feign+Ribbon+Zuul+Hystrix+Config+Bus构建一套SpringCloud项目

Eureka - 注册中心


Eureka是Netflix开发的服务发现框架,SpringCloud将它集成在自己的子项目spring-cloud-netflix中,实现SpringCloud的服务发现功能。Eureka包含两个组件:Eureka Server和Eureka Client。


  1. 服务的提供者首先把自身的服务实例注册到server中

  2. 服务的消费者去注册中心获取服务列表

  3. 消费者调用服务的提供者

  4. 在服务启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有 接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90 秒)。



搭建EurekaServer微服务

依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>

配置

server: port: 8001eureka: client: register-with-eureka: false #是否将自己注册到Eureka服务中 因为自己本身就是所以无需注册 fetch-registry: false #是否从Eureka中获取注册信息 service-url: #Eureka客户端与服务端进行交互的地址 defaultZone: http://127.0.0.1:${server.port}/eureka/

在启动类上面加入注解@EnableEurekaServer


eureka客户端

依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>

配置

eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://127.0.0.1:8001/eureka/

在启动类上面加入注解@EnableEurekaClient


Feign - 服务调用


Feign用于微服务之间的调用

依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency>

在调用方的启动类上加注解

@EnableDiscoveryClient @EnableFeignClients

但是

@FeignClient(value = "springcloud-user")public interface UserClient { @RequestMapping(value = "/user/{id}",method = RequestMethod.GET) public String getUserById(@PathVariable("id") String id);}


@FeignClient注解用于指定从哪个服务中调用功能 ,注意:里面的名称与被调用的服务 名保持一致,并且不能包含下划线



在这里Feign只有接口,为什么可以使用?原因是自动实现了FeignClient接口


Hystrix - 熔断器


如图,我们发现Feign里面集成了Hystrix:


Eureka+Feign+Ribbon+Zuul+Hystrix+Config+Bus构建一套SpringCloud项目


配置

feign: hystrix: enabled: true #启动熔断器

创建熔断的实现类

@Componentpublic class UserClientImpl implements UserClient {
@Override    public String getUserById(String id) { return "系统故障,请稍后重试"; }}


添加fallback参数,指定其实现类,实现服务降级

@FeignClient(value = "springcloud-user",fallback = UserClientImpl.class)


Ribbon - 负载均衡


如图所示,我们发现Eureka已经集成了Ribbon:


Eureka+Feign+Ribbon+Zuul+Hystrix+Config+Bus构建一套SpringCloud项目


Ribbon默认使用的负载均衡策略是轮询,此外还有随机策略等


Zuul - 网关


为什么需要网关?


如果客户端直接和微服务进行通信,会存在一下问题:

1.客户端会多次请求不同微服务,增加客户端的复杂性 

2.存在跨域请求,在一定场景下处理相对复杂 

3.认证复杂,每一个服务都需要独立认证

4.难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通 信,那么重构会难以实施 

5.某些微服务可能使用了其他协议,直接访问有一定困难 上述问题,都可以借助微服务网关解决。

微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关。


Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使 用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:

1. 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求 

2.审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图

3.动态路由:动态将请求路由到不同后端集群 

4.压力测试:逐渐增加指向集群的流量,以了解性能 

5.负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求 

6.静态响应处理:边缘位置进行响应,避免转发到内部集群 

7.多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使 用多样化


整合zuul之后架构图:

Eureka+Feign+Ribbon+Zuul+Hystrix+Config+Bus构建一套SpringCloud项目

依赖:

<dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring‐cloud‐starter‐netflix‐zuul</artifactId> </dependency>

配置

zuul: routes: springcloud-user: path: /user/** #配置请求url的请求规则 serviceId: springcloud-user #指定Eureka注册中心中的服务id springCloud-student: path: /student/** serviceId: springCloud-student

加入网关之后的授权中心流程


SpringCloud - 集中配置组件


Spring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持。使用Config Server,您可以集中管理所有环境中应用程序的外部属性。客户端和服务器上的概念与SpringEnvironment和PropertySource抽象,因此它们非常适合Spring应用程序,但可以与以任何语言运行的任何应用程序一起使用。当应用程序从开发人员迁移到测试人员并进入生产过程时,您可以管理这些环境之间的配置,并确保应用程序具有在迁移时需要运行的所有内容。服务器存储后端的默认实现使用git,因此它轻松支持带标签的配置环境版本,并且可以通过各种工具来访问这些内容来管理内容。添加替代实现并将其插入Spring配置很容易。


将微服务中的配置文件提交到代码托管中心,并且删除项目中的配置文件


搭建配置中心微服务

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId></dependency>


启动类添加注解

@EnableConfigServer


配置

spring: application: name: eu-config cloud: config: server: git: uri:


配置客户端

<dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring‐cloud‐starter‐config</artifactId> </dependency>

添加bootstrap.yml

spring: cloud: config: name: user profile: dev label: master uri: http://127.0.0.1:9009


SpringCloudBus - 消息总线


当我们更新了代码托管平台中的配置文件时,我们再去测试,发现并不能立刻更新到代码工程中,只有重新启动程序才会读取配置。那我们如果想在不重启微服务的情况 下更新配置如何来实现呢? 我们使用SpringCloudBus来实现配置的自动更新。


在配置中心微服务加入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId></dependency>

配置application.yml

spring: rabbitmq: host: 192.168.206.133management: #暴露触发消息总线的地址 endpoints: web: exposure: include: bus-refresh


在客户端添加消息总线

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>

在代码托管中心的各个配置文件中添加:

spring: rabbitmq: host: 192.168.206.133