SpringCloud 之 Eureka 服务的使用场景和搭建

  • Post author:
  • Post category:其他


前言:


之前也看过别人关于 eureka 的博客,但是很少有人会去解释为啥要用 eureka,以至于迷茫了一段时间;后来看多了也就懂了,这里以个人的见解说明一下 eureka 出现的背景以及搭建的过程和注意事项。


1. Eureka 的产生



首先,一定要有一个概念, springcloud 的所有组件都是以 springboot 为基础构建的,它是依赖 springboot 而生的;它跟springboot的关系可以理解为类似 lombok 、mybatis 组件跟springboot的关系;它的一系列组件是为了解决 springboot 在实际工程中的遇到的一系列问题,举个例子:

考虑如下场景:

需求:系统A和系统B需要合并在一起对外提供服务

处理方式:

一、迁移代码,两个工程整合成一个;这种方式费时费力不讨好,如果你经历过基本不想再经历第二遍。

二、两个工程在 service 层面相互调用达到整合的目的;很显然这种方式比较好。

整合完了以后过段时间发现 B 系统的调用比较频繁,所以又开了一个实例,为了做负载均衡把 nginx 加上了,又过了一段时间系统 C 也要整合进来,系统 C 也要做负载均衡…..产品卖得很好,过段时间又集成了其他系统的功能;这样光 nginx 的配置就很麻烦,是不是迫切得需要把这些系统管理起来,是不是希望系统之间的调用简单一些, eureka 就是干这些的,调用以应用名为唯一标识,所有的服务都在注册中心进行统一管理。eureka 分为 server 和 client,server 是管理应用的,除了server,其它都是client。

2. eureka-server 搭建


springboot 跟 springcloud 有版本对应关系的,版本不对应没法使用

,可从官网(https://spring.io/projects/spring-cloud)查询,或者从接口:

https://start.spring.io/actuator/info

获取

springboot 本地版本是  2.3.2.RELEASE ,对应上述红框的 springcloud 版本。

springboot 工程目录如下:

pom 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>eureka-server</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>   <!--依赖下载仓库信息-->

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>  <!--eureka-server依赖-->
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR11</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>  <!--spring-cloud 组件版本-->

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

EurekaServer 文件(程序入口):

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@EnableEurekaServer
@SpringBootApplication
public class EurekaServer {

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

}

配置文件 application.yml,版本不一样,配置属性也会有变化,需要注意:

server:
  port: 8000

spring:
  application:
    name: eureka-server

eureka:
  server:
    # 关闭自我保护,测试 client 掉线是否生效,默认为 true
    enable-self-preservation: false
    # 去除失效服务的时间间隔(毫秒)
    eviction-interval-timer-in-ms: 10000
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

启动 eureka-server,网页输入 http://localhost:8000,这时候没有任何可用应用

3. eureka-client 搭建

server 搭建完了是不是需要注册一些应用(client)进去,搭建 client 跟 server 类似

springboot 工程目录如下:

pom 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>eureka-client-1</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>   <!--依赖下载仓库信息-->

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>  <!--eureka-client依赖-->
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR11</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>  <!--spring-cloud 组件版本-->

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
ClientApplication 文件(程序入口):
package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

配置文件 application.yml:

server:
  port: 8001

spring:
  application:
    # 应用名,应用之间调用的唯一标识;同一种应用,名字要一样
    name: eureka-client

eureka:
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则),默认30
    lease-renewal-interval-in-seconds: 5
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己),默认90
    leaseExpirationDurationInSeconds: 10
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
      # eureka-server 地址
      defaultZone: http://localhost:8000/eureka/
ControllerTest 接口测试文件:
package com.test.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/client")
public class ControllerTest {

    @GetMapping("/test")
    public String name() {
        return "this is from client-1";
    }
}

这样 client 就搭建好了,为了测试调用关系和分布式的效果,可以再搭建一个client-2;client -2 需要修改一下端口,ControllerTest  修改如下,主要是为了区别 client-1。

server:
  port: 8002

spring:
  application:
    # 应用名,应用之间调用的唯一标识;同一种应用,名字要一样
    name: eureka-client

eureka:
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则),默认30
    lease-renewal-interval-in-seconds: 5
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己),默认90
    leaseExpirationDurationInSeconds: 10
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
      # eureka-server 地址
      defaultZone: http://localhost:8000/eureka/
package com.test.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/client")
public class ControllerTest {

    @GetMapping("/test")
    public String name() {
        return "this is from client-2";
    }
}

把两个 client 都启动起来,再次查看 http://localhost:8000,可以看到启动的两个client

4. 测试 eureka-client 服务调用

新开一个 customer 工程,目录如下:

pom 文件除了 artifactId 不一样,其他跟 client 配置一样;

CustomerApplication 主程序文件跟 client 配置也类似(就是常规的springboot主程序文件);

application.yml 的 name 和 port 跟 client不一样之外,其他跟 client  配置一样。

RestConfig 是 RestTemplate 的配置文件(SpringBoot 有 feign 组件可以使用,后续再讲),因为涉及负载均衡,所以跟平时多了 @LoadBalanced 注解:

package com.test.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {

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

}
ControllerTest 接口测试文件:
package com.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/customer")
public class ControllerTest {

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/test")
    public String name() {
        ResponseEntity<String> entity = restTemplate.getForEntity("http://eureka-client/client/test", String.class);
        return entity.getBody();
    }
}

启动 customer 工程,访问测试接口,刷新几次吗,可以看到不一样的结果:

结果1:

结果2:

关闭其中一个client,过段时间再请求返回结果唯一,同时 eureka-server 界面也会少一个 client。

5. 其他建议

1. 建议使用 security 给 eureka-server加上密码,这样服务注册会安全一些(慎用,因为会带来其他问题,这个下次单独讲)

pom文件加上依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

yml文件的 defaultZone 改一下:

defaultZone: http://user:passwd@${eureka.instance.hostname}:${server.port}/eureka/

另外由于这里 security 版本比较高,所以需要在 eureka-server 的启动文件加上让 csrf 失效的方法,主要是为了解决 client 没法注册的问题:

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

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

    @EnableWebSecurity
    static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            super.configure(http);
        }
    }
}

其他组件后续再讲。



版权声明:本文为qingquanyingyue原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。