zoukankan      html  css  js  c++  java
  • 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的支持最好。

     

  • 相关阅读:
    nginx windows could not build server_names_hash, you should increase server_names_hash_bucket_size: 32
    两个spring boot项目war部署到tomcat 其中一个无法正常启动
    spring boot 集成axis1.4 java.lang.NoClassDefFoundError: Could not initialize class org.apache.axis.client.AxisClient
    springmvc 控制器 读取properties文件
    EntityFramework+EntityFramework.SqlServerCompact部署网站
    Dapper+SqlServerCe部署
    swagger.net 使用nginx 代理时出现端口号导致出错
    vs2017 EFCore 迁移数据库命令
    itextsharp html转成pdf 特殊符号异常处理
    java web项目部署到tomcat 8.5 此驱动程序不支持 Java Runtime Environment (JRE) 1.8 版。请使用支持 JDBC 4.0 的 sqljdbc4.jar 类库
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/12295914.html
Copyright © 2011-2022 走看看