eureka简介
eureka是Netflix开发的服务发现组件,本身是一个基于REST的服务。Spring Cloud将它集成在其子项目spring-cloud-netflix中,以实现Spring Cloud的服务发现功能。eureka现在已经从1.0升级到2.0,可惜的是eureka2.0不在开源,但也不影响我们的使用。由于基于REST服务,自然而然的就能想到,这个服务一定会有心跳检测、健康检查和客户端缓存等机制。
Eureka包括两个端:
- Eureka Server:注册中心服务端,用于维护和管理注册服务列表。
- Eureka Client:注册中心客户端,向注册中心注册服务的应用都可以叫做Eureka Client(包括Eureka Server本身)。
搭建一个注册中心服务端
- 创建一个SpringBoot项目,导入依赖包 Web 下的 Spring Web,Spring Cloud Discovery下的 Eureka Server
- 在application.properties里面进行配置,配置内容如下
server.port=8761 spring.application.name=eureka-server # 这里写多个地址表示搭建多个注册中心的时候,使他们互相注册,达到高可用效果 eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka,http://localhost:8763/eureka # 不把自己注册到注册中心 #eureka.client.register-with-eureka=false #eureka.client.fetch-registry=false
- 在Application入口类里面写上相应的注解后启动项目
@EnableEurekaServer
- 若要通过一个项目启动多个注册中心服务端实现集群,可以在一个idea项目里面模拟实现,方法如下
在运行和debug按钮的左边有一个下拉框,选择 Edit Configurations,在左边栏里找到相应的要多次启动的项目启动入口,然后在右上角勾选上 Allow parallel run,最后点击 最下方的 Apply 和 OK 就可以实现一个项目启动多次了
注意:要通过一个项目启动多个项目的话,就要把配置文集那里面的端口改成不相同的,否则启动不了
搭建一个注册中心客户端
- 创建一个 SpringBoot 项目,导入依赖包 Web 下的Spring Web,和 Spring Cloud Discovery 下的 Eureka Discovery Client
- 在application.properties里面进行配置,配置内容如下
# 项目端口号 server.port=8776 # 应用名称 spring.application.name=eureka-client # 注册中心服务端的ip eureka.client.service-url.defaultZone=http://10.2.1.66:8761/eureka
- 在Application入口类里面写上相应的注解后启动
@EnableEurekaClient
- 若也要通过一个项目启动多个注册中心客户端实现集群,那么方法跟上面的是一样的
使用 Feign+Eureka实现负载均衡与断路器
首先,Feign是什么?
Feign是一个声明式WebService客户端.使用Feign能让编写WebService客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
为 什 么 要 实 现 断 路 器 模 式?
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon或Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
为了解决这个问题,业界提出了断路器模型。
断路器模式的简单原理:
在微服务架构中,一个请求需要调用多个服务是非常常见的,较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次)断路器将会被打开。断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。
下面开始以使用 Feign+Eureka实现负载均衡为目标,同时也实现断路器模式,快速搭建一个简单的项目
- 创建一个 SpringBoot 项目,导入依赖包 Web 下的Spring Web,和 Spring Cloud Discovery 下的 Eureka Discovery Client,和 Spring Cloud Routing 下的 OpenFeign
- 在application.properties里面的进行配置,配置信息如下
server.port=8781 spring.application.name=feign eureka.client.service-url.defaultZone=http://localhost:8761/eureka # 开启 断路器 功能 //feign.hystrix.enabled=true
- 在Application启动入口里加上相应的注解
@EnableFeignClients @EnableEurekaClient
- 在Client项目里面创建一个Controller类,用来测试当前访问的是哪个客户端
@RestController public class HelloController { /** * 将配置文件中server.port属性 注入到port变量中 * 可以通过观察端口的不同,判断当前走的是哪个项目 */ @Value("${server.port}") private String port; @GetMapping("/hi") public String hi(){ return "hello world"+port; } }
- 在Feign项目里面创建一个Controller类,用来远程调用服务
// value 指定远程调用的服务名称/应用名称 // fallback 这是实现断路器模式的关键,当远程服务调用失败时,将直接获得该类里面提供的信息:执行HiServiceBack中的内容 @FeignClient(value = "eureka-client",fallback = HiServiceBack.class) public interface IHiService { @GetMapping("/hi") String sayHi(); }
- fallback 当发生长时间未响应的情况,就会执行HiServiceBack中的内容,所以我们创建一个HiSeviceBack类
@Component public class HiServiceBack implements IHiService { @Override public String sayHi() { return "sorry"; } }
- 若也要通过一个项目启动多个Feign客户端实现集群,那么方法跟上面的是一样的
使用 Zuul+Eureka 实现过滤效果
zuul是什么?
Zuul包含了对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka。
下面开始以使用 Zuul+Eureka实现过滤为目标,快速搭建一个简单的项目
- 创建一个 SpringBoot 项目,导入依赖包 Web 下的Spring Web,和 Spring Cloud Discovery 下的 Eureka Discovery Client,和 Spring Cloud Routing 下的 Zuul
- 在application.properties里面的进行配置,配置信息如下
server.port=80 spring.application.name=zuul eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka,http://localhost:8763/eureka # 配置转发规则 zuul.routes.user.path=/user/** zuul.routes.user.service-id=eureka-client zuul.routes.stu.path=/stu/** zuul.routes.stu.service-id=feign
- 在Application启动入口里加上相应的注解
@EnableEurekaClient @EnableZuulProxy
- 创建一个过滤器,并继承ZuulFilter
@Component public class MyFilter extends ZuulFilter { /** * 过滤器类型 * @return */ @Override public String filterType() { return "pre"; } /** * 指定过滤器执行顺序 * @return */ @Override public int filterOrder() { return 0; } /** * 是否需要执行过滤器 * @return */ @Override public boolean shouldFilter() { return false; } /** * 过滤器具体时间 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { // 获取请求上下文对象 RequestContext currentContext =RequestContext.getCurrentContext(); // 获取Request对象 HttpServletRequest request = currentContext.getRequest(); // 从Request中获取token信息进行验证 String token = request.getParameter("token"); // if (token == null) { // 禁止让zuul做出响应 currentContext.setSendZuulResponse(false); // 设置响应状态码 currentContext.setResponseStatusCode(401); // 通过上下文拿到response对象 try { currentContext.getResponse().getWriter().write("token is empty"); } catch (IOException e) { e.printStackTrace(); } } return null; } }
可以通过关闭某个项目,模拟一个服务器宕机的情况,然后进行访问,查看效果