• Spring Cloud(2):服务发现(Eureka)


    Spring Cloud Eureka是Spring Cloud Netflix项目下的一个模块,作用是服务的注册和发现,并实现服务治理。它有一个(或一组,以实现高可用)服务注册中心(eureka server)并提供服务注册功能,所有的应用程序将作为服务提供方(eureka client)向eureka server注册服务,当应用程序之间相互调用时,不再通过IP地址调用,将通过eureka server,使用注册的service id来调用。

    下面,分别从5个方面来讲Eureka:Eureka Server,Eureka Client,Peer Awareness,Securing The Eureka ServerDiscovery Client

    (1)搭建Eureka Server

    首先,创建一个SpringBoot Web Aplication,在pom.xml中加入spring-cloud-starter-netflix-eureka-server包。这里使用的是Spring Boot 2.2.5和Spring Cloud Hoxton.SR3。

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.5.RELEASE</version>
        </parent>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR3</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
            <!-- Spring cloud starter: netflix-eureka-server -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>

    其次,在启动类ServerEurekaApplication中加入@EnableEurekaServer注解。

    @SpringBootApplication
    @EnableEurekaServer
    public class ServerEurekaApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServerEurekaApplication.class, args);
        }
    }

    最后,在配置文件中配置Eureka信息。

    bootstrap.yml

    spring:
      application:
        name: server-eureka

    application.yml

    ## Server info
    server:
      port: 10000
      servlet:
        context-path: /server-eureka
    
    ## Eureka info
    eureka:
      instance:
        hostname: localhost
        # You need to change these, even for an Actuator application if you use a non-default context path or servlet path
        # https://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html#_status_page_and_health_indicator
        statusPageUrlPath: ${server.servlet.context-path}/actuator/info
        healthCheckUrlPath: ${server.servlet.context-path}/actuator/health
      client:
        # 程序启动时不要通过Eureka注册服务,因为它本身就是Eureka服务
        registerWithEureka: false
        # 不会在本地缓存注册表信息
        fetchRegistry: false
        serviceUrl:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/server-eureka/eureka/
      # Eureka不会马上通知任何注册它的服务,默认情况下会等待5min。本地测试时应该注释掉此行,以加快程序运行
      # 每次服务注册需要30s的时间才能显示在Eureka服务中,因为Eureka需要接收3此心跳包,每次间隔10s,然后才能使用这个服务。
      #server:
      #  waitTimeInMsWhenSyncEmpty: 5
      server:
        waitTimeInMsWhenSyncEmpty: 0

    (2)搭建Eureka Client

    首先,创建一个SpringBoot Web Aplication,在pom.xml中加入spring-cloud-starter-netflix-eureka-client包。

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

    然后,在配置文件中配置Eureka信息。

    ## Server Info
    server:
      port: 10010
      servlet:
        context-path: /app-web
    
    ## Eureka info
    eureka:
      instance:
        # You need to change these, even for an Actuator application if you use a non-default context path or servlet path
        # https://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html#_status_page_and_health_indicator
        statusPageUrlPath: ${server.servlet.context-path}/actuator/info
        healthCheckUrlPath: ${server.servlet.context-path}/actuator/health
        # 注册服务的IP而不是服务器名称
        # preferIpAddress: true
      client:
        # 向Eureka注册服务(default is true)
        registerWithEureka: true
        # 拉取注册表的本地副本(default is true)
        fetchRegistry: true
        serviceUrl:
          defaultZone: http://localhost:10000/server-eureka/eureka/

    [注1] preferIpAddress在默认情况下,Eureka注册服务使用了主机名与外界联系,这种方式在服务器环境中是OK的,因为通过DNS可以解析成IP地址。但是,在基于容器的部署环境中(如Docker),主机名是随机生成的,且并没有DNS记录。将eureka.instance.preferIpAddress设置为true,当应用程序向eureka注册时,它使用其IP地址而不是其主机名。

    如果设置eureka.instance.prefer-ip-address为false时,那么注册到Eureka中的IP地址就是本机的IP地址。如果设置了true并且也设置了eureka.instance.ip-address那么就将此ip地址注册到Eureka中。那么调用的时候,发送的请求目的地就是此Ip地址。

    参考:

    https://www.jianshu.com/p/886947b52cb4

    https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.2.2.RELEASE/reference/html/#spring-cloud-eureka-server-prefer-ip-address

    [注2] 从Spring Cloud Edgware开始,@EnableDiscoveryClient或@EnableEurekaClient可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。Spring Cloud中的Discovery Service有多种实现,比如:eurekaconsulzookeeper。

    - @EnableDiscoveryClient 注解是基于spring-cloud-commons依赖,并且在classpath中实现

    - @EnableEurekaClient 注解是基于spring-cloud-netflix依赖,只能为eureka作用

    如果你的classpath中添加了eureka,则它们的作用是一样的。

    (3)Peer Awareness(高可用的Eureka集群)

     假设我们现在有3台Eureka Server,IP地址分别为:192.168.0.1,192.168.0.2,192.168.0.3。配置文件修改如下:

    application-peer1.yml

    ## Eureka info
    eureka:
      instance:
        # http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html#spring-cloud-eureka-server-peer-awareness
        hostname: 192.168.0.1
      client:
        # 需要修改下面两个配置,让注册中心可以向另外一个注册中心注册服务,以实现高可用
        registerWithEureka: true
        fetchRegistry: true
        # 向另2个Eureka Server注册自己
        serviceUrl:
          defaultZone: http://192.168.0.2:10000/server-eureka/eureka/,http://192.168.0.3:10000/server-eureka/eureka/

    application-peer2.yml

    eureka:
      instance:
        hostname: 192.168.0.2
      client:
        registerWithEureka: true
        fetchRegistry: true
        serviceUrl:
          defaultZone: http://192.168.0.1:10000/server-eureka/eureka/,http://192.168.0.3:10000/server-eureka/eureka/

    application-peer3.yml

    eureka:
      instance:
        hostname: 192.168.0.3
      client:
        registerWithEureka: true
        fetchRegistry: true
        serviceUrl:
          defaultZone: http://192.168.0.1:10000/server-eureka/eureka/,http://192.168.0.2:10000/server-eureka/eureka/

    当我们在Eureka Client中向Eureka Server注册时,需要修改配置文件如下:

    eureka:
      client:
        serviceUrl:
          defaultZone: http://192.168.0.1:10000/server-eureka/eureka/,http://192.168.0.2:10000/server-eureka/eureka/,http://192.168.0.3:10000/server-eureka/eureka/

    (4)使用Spring Security保护Eureka Server

    首先,在pom.xml中加入spring-cloud-starter-netflix-eureka-client包。

            <!-- Spring cloud starter: security -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-security</artifactId>
            </dependency>

    然后,添加一个user和password用于登录Eureka Server自带的页面:http://{host}:{port}/server-eureka。值得注意的是,需要disable'/eureka/**'端点的csrf()

    @EnableWebSecurity
    public class ServerEurekaWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return PasswordEncoderFactories.createDelegatingPasswordEncoder();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //@formatter:off
            PasswordEncoder encoder = new BCryptPasswordEncoder();
            auth.inMemoryAuthentication()
                .withUser("eureka-user").password("{bcrypt}" + encoder.encode("eureka-user")).roles("USER");
            //@formatter:on
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // By default when Spring Security is on the classpath,
            // it will require that a valid CSRF token be sent with every request to the app.
            // Eureka clients will not generally possess a valid cross site request forgery (CSRF) token,
            // you will need to disable this requirement for the /eureka/** endpoints.
            // https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.1.2.RELEASE/single/spring-cloud-netflix.html#_securing_the_eureka_server
            http.csrf().ignoringAntMatchers("/eureka/**");
            super.configure(http);
        }
    }

    最后,所有向Eureka Server注册的URL都要改成这样的形式:http://user:password@localhost:8761/eureka。

    上面(3)中Eureka Server集群中的相互注册:

    eureka:
      username: eureka-user
      password: '{cipher}72cd0bdd18c6928b025e9e5dfa94cce539b555c4b3364590c689df3532fa69bc'
      client:
        serviceUrl:
          defaultZone: http://${eureka.username}:${eureka.password}@192.168.0.2:10000/server-eureka/eureka/,http://${eureka.username}:${eureka.password}@192.168.0.3:10000/server-eureka/eureka/

    上面(3)中Eureka Client中的注册:

    eureka:
      username: eureka-user
      password: '{cipher}72cd0bdd18c6928b025e9e5dfa94cce539b555c4b3364590c689df3532fa69bc'
      client:
        serviceUrl:
          defaultZone: http://${eureka.username}:${eureka.password}@192.168.0.1:10000/server-eureka/eureka/,http://${eureka.username}:${eureka.password}@192.168.0.2:10000/server-eureka/eureka/,http://${eureka.username}:${eureka.password}@192.168.0.3:10000/server-eureka/eureka/

    [注] 上面密码使用JCE(Java Cryptography Extension)的对称加密,这部分可以看 Spring Cloud(4):配置服务(Config)。

    (5)在Eureka Client中使用Discovery Client来发现并调用其他Client服务

    一个微服务架构中会有多个Eureka Client,当它们向Eureka Server注册后,就可以通过下面2种方法相互调用:

    1. 使用EurekaClient(DiscoveryClient)

    @Autowired
    private EurekaClient discoveryClient;
    
    public String serviceUrl() {
        InstanceInfo instance = discoveryClient.getNextServerFromEureka("app-name", false);
        String path = String.format("http://%s:%s/aaa/bbb", instance.getHostName(), instance.getPort());
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(path, HttpMethod.GET, null, String.class);
        return response.getBody();
    }

    2. 使用带有Ribbon功能的LoadBalancerClient(负载均衡)

    @Autowired
    private LoadBalancerClient loadBalancer;
    
    public String serviceUrl() {
        ServiceInstance instance = loadBalancer.choose("app-db");
        String path = String.format("http://%s:%s/aaa/bbb", instance.getHost(), instance.getPort());
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(path, HttpMethod.GET, null, String.class);
        return response.getBody();
    }
    Hoxton.SR3
  • 相关阅读:
    sublime text
    php 实例说明 socket通信机制
    nusaop 关于webService
    vim操作集合
    gitHud设置公钥
    redis在window安装并启动
    百度云api 添加标注
    微信小程序bindTap获取对应值
    Java导出excel表
    linux 常用命令
  • 原文地址:https://www.cnblogs.com/storml/p/11009407.html
Copyright © 2020-2023  润新知