SpringCloud Eureka 服务治理

 

Eureka是Netflix的服务发现组件,基于REST,SpringCloud将它集成在子项目Spring Cloud Netflix中,实现服务发现。

 

Eureka包含Server、Client两部分

  • Eureka Server  接收服务注册、保存各服务节点的信息
  • Eureka Client   即各服务节点,内置负载均衡器Ribbon。

 

 


 

 

Eureka的架构

 

 

 

 

 


 

 

Eureka Server

Maven创建父子工程,新建子模块eureka-server。

Eureka和ZK不同,ZK是安装软件作为注册中心,Eureka是自己写一个服务作为注册中心。

 

(1)创建时勾选 Spring Cloud Discovery -> Eureka Server 

 也可以手动加eureka server的依赖:

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

 

 

(2)引导类上加  @EnableEurekaServer

 

 

(2)配置文件可以使用.properties,但springcloud官方使用yml,我们也使用yml,重命名一下

server:
  port: 8761

eureka:
  instance:
   #设置为所在机器的主机名(域名)或者ip地址,如果是主机名上线时需要在dns上注册 hostname: 127.0.0.1 client: #不注册到其它Eureka Server上,表示这是一个Eureka Server registerWithEureka: false #不从其它Eureka Server上拉取、同步注册信息,表示这是单机版的Eureka Server fetchRegistry: false serviceUrl: #这个Eureka Server的注册中心地址,服务都会注册到这个地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

如果要搭建Eureka Server集群,将上面2个false改为true

 

 

(4)启动,127.0.0.1:8761 访问Eureka Server的控制台

ip是运行Eureka Server的机器的ip,port是上面配置文件中的port

 

 

 


 

 

 

新建子模块order-service作为服务提供者

每一个服务都是Eureka Client

 

(1)创建时勾选 Developer Tools -> Lombok,Web -> Spring Web,Spring Cloud Discovery -> Eureka Discovery Client

 也可以手动加eureka client依赖:

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

 

 

(2)引导类上加@EnableEurekaClient (非必需)

@EnableEurekaClient是eureka的注解,也可以换为@EnableDiscoveryClient(springcloud的注解)

也可以不加,因为项目的classpath中有Eureka Client的依赖 spring-cloud-starter-netflix-eureka-client 时,启动应用时会自动在引导类上加 @EnableEurekaClient。

 

 

(3)配置文件

server:
  port: 8771

spring:
  application:
    #服务名称
    name: order-service

eureka:
  client:
    #注册中心地址,如果
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/

如果是Eureka Server集群,多个url之间逗号分隔。不必写全部的Eureka Server,写一部分即可。

注册时只注册到第一个Eureka Server,Eureka Server之前会相互同步数据,后面的url都是备胎,第一个故障才会使用第二个,以此类推。

 

 

(4)实体类、controller

@Getter
@Setter
public class Order implements Serializable{
    private Long id;
    //.....
    private Long userId;
}
@Controller
@RequestMapping("/api/v1/order")
public class OrderController {

    @RequestMapping("/list/{user_id}")
    @ResponseBody
    public List<Order> findOrdersByUserId(@PathVariable("user_id") Long userId){
        //模拟
        ArrayList<Order> orders = new ArrayList<>();
        Order order = new Order();
        order.setId(1L);
        order.setUserId(userId);
        orders.add(order);
        return orders;
    }
    
}

把pojo对象转换为作为json传输时不需要序列化,但有些场景可能要用到序列化,最好加上。

v1表示api版本,此处只是模拟一下,并没有写在service层。

 

 

 


 

 

 

新建子模块user-service作为服务消费者

(1)创建时依然勾选 Developer Tools -> Lombok,Web -> Spring Web,Spring Cloud Discovery -> Eureka Discovery Client

 

(2)引导类上加@EnableEurekaClient (非必需)

 

(3)配置文件

server:
  port: 8781

spring:
  application:
    #服务名称
    name: user-service

eureka:
  client:
    #注册中心地址,如果
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/

 

 

(4)实体类、controller

@Getter
@Setter
public class Order implements Serializable{
    private Long id;
    //.....
    private Long userId;
}
@Controller
@RequestMapping("/api/v1/user")
public class UserController {
    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("order/{user_id}")
    @ResponseBody
    public List<Order> findOrdersByUserId(@PathVariable("user_id") Integer userId){
        List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class);
        return orders;
    }

}

SpringCloud重复代码多,如果要使用其它服务中的实体类、工具类,得Copy过来,也可以把公共要用的代码放在一个单独的子模块中,打包成jar,引入。

 

 

(4)引导类

消费者要使用RestTemplate这个Bean,需要自己创建

@SpringBootApplication
public class UserServiceApplication {
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }

}

 

启动order-service、user-service,地址栏输入127.0.0.1:8781/api/v1/user/order/1  看到显示json数据,说明调用成功。

 

 

 


 

 

 

RestTemplate

RestTemplate用于以restful方式远程调用服务。

 

常用方法:

   //参数:远程服务接口,返回值类型(目标类型)
    List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class);

    //url中的参数可以使用+号拼接,也可以使用占位符{1},{2}...,在目标类型后面写参数值(Object...)
    List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/{1}" + userId, List.class,1);

    //可以用map来传递数据,服务提供者接收map中的键值对时,要以@PathVariable的方式来接收
    HashMap<String, Object> map = new HashMap<>();
    map.put("user_id", 1);
    List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class,map);

//可以不使用restful方式来传递参数,用?user_id=1这种方式也行,但需要修改下服务提供者的

xxxForObject(),get是查询,put是新建,post是更新,delete是删除,用法都差不多。

 

 

上面服务的url我写的是服务名order-service,在引导类中创建RestTemplate这个Bean时要加@LoadBalanced,这样拿到该服务节点列表后才会使用负载均衡器Ribbon来确定使用哪个服务节点。

url可以直接写ip:port (不推荐),http://127.0.0.1:8771/api/v1/order/list/,这样是直接调用某一个服务节点,服务消费者、提供者直连,不从Eureka Server获取节点列表,不需要加@LoadBalanced。

 

 

 


 

 

 

Eureka Server的服务保护

Eureka Server默认开启了服务保护,停掉某个服务,Eureka Server控制台会用一段红色文字提示:这个服务节点进入了保护模式。

 

服务的自我保护模式:

Eureka Server在90s内都未收到某个服务节点的心跳包时,会开启为期15min的心跳检测,这期间不会把该服务节点的信息从服务注册列表中删除。

如果15min内实际收到该节点的心跳数占应接收心跳数的比值小于0.85(默认值0.85,可设置),就认为是该服务节点与Eureka Server之间的网络故障导致的心跳包丢失,该服务节点本身没有问题,保留该节点的注册信息;如果比值大于0.85,就认为是该服务节点自身出了问题,从服务注册列表中删除该服务节点的信息。

 

 

造成的问题:该服务节点可能出问题了,但依然被当做正常节点使用。

项目上线时一般也不关闭服务保护,公司的项目,服务节点的数量往往成百上千,如果关闭服务保护,网络不稳定时(网络波动、延迟、断线等)会导致大量的服务反复注册、删除、再注册,会降低程序性能。开启服务保护,某些服务节点故障时,无非就是注册列表中有少量无效节点,不一定会调用集群中的这些无效节点,就算调用了无效节点不能正确处理请求,用户刷新几次,转发给集群中正常的节点处理就ok了。

 

 

开发、调试时可以关闭Eureka Server的服务保护,快速清理掉无效节点:

eureka:
  server:
    #关闭Eureka Server的服务保护
    enableSelfPreservation: false

 

 

 


 

 

 

Eureka Client的缓存机制

Eureka|ZK Client都会缓存Eureka|ZK Server返回的服务节点列表,缓存一直有效,直到此Client下线。

消费者调用服务时都是先从本地缓存中找有没有该服务的节点列表,没有才会从Eureka|ZK Server获取该服务的节点列表。

 

ZK Client通过订阅来监听ZK Server上服务节点列表的变化,Eureka Client通过轮询来确定缓存的服务节点列表是否有更新,有更新|变化时会自动从ZK|Eureka Server上获取服务节点列表的更新。

 

即便Eureka|ZK Server集群的所有节点都宕机,服务消费者依然可以调用服务提供者(以前调用过,有缓存)。

 

 


 

 

SpringCloud也可以使用其它的服务发现组件,比如ZK、Consul,但对Eureka的支持最好。

 

 

 

posted @ 2020-02-13 15:51  chy_18883701161  阅读(271)  评论(0编辑  收藏  举报