SpringCloud之 Eureka注册中心


提示:以下是本篇文章正文内容,SpringCloud 系列学习将会持续更新

在这里插入图片描述

Eureka注册中心

官方文档:https://docs.spring.io/spring-cloud-netflix/docs/current/reference/html/

前面我们了解了如何对单体应用进行拆分,并且也学习了如何进行服务之间的相互调用 (项目 Gitee 地址 )。但是存在一个问题,就是虽然服务拆分完成,但是没有一个比较合理的管理机制,如果单纯只是这样编写,在部署和维护起来,肯定是很麻烦的。
可以想象一下,如果某一天这些微服务的端口或是地址大规模地发生改变,我们就不得不将服务之间的调用路径大规模的同步进行修改,这是多么可怕的事情。我们需要削弱这种服务之间的强关联性,因此我们需要一个集中管理微服务的平台,这时就要借助我们这一部分的主角了。

Eureka 能够自动注册并发现微服务,然后对服务的状态、信息进行集中管理,这样当我们需要获取其他服务的信息时,我们只需要向 Eureka 进行查询就可以了。
在这里插入图片描述
像这样的话,服务之间的强关联性就会被进一步削弱。

一、服务注册与发现

1.1 依赖导入

🍓①父工程 SpringCloud 版本管理

我们先在父工程中添加一下 SpringCloud 的依赖 进行版本管理,这里选用 2021.0.1 版本。注意:SpringCloud 版本一定要和 SpringBoot 版本兼容,我用的 SpringBoot 是 2.7.6,其它版本查阅官方文档。
官网查看:https://spring.io/projects/spring-cloud#learn

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>2021.0.1</version>
			<type>pom</type>
			<scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
🍓②Eureka 服务端依赖

现在我们就来搭建一个 Eureka 服务器,只需要创建一个新的 Maven 项目即可(eureka-server
接着我们为Eureka服务端添加 Eureka 依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>
🍓③Eureka 客户端依赖

我们的三个微服务客户端,首先还是需要导入 Eureka 依赖

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

回到目录…

1.2 服务注册

🍉①创建 Eureka 服务端的主类

需要使用@EnableEurekaServer注解:

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
🍉②设置 Eureka 服务端的配置文件
server:
  port: 8888
eureka:
  instance:
    hostname: localhost # eureka服务端的实例名称
  client:
    # 是否在服务中心注册自己, 默认为 true
    register-with-eureka: false
    # false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

好了,现在差不多可以启动了,启动完成后,直接localhost:8888即可访问 Eureka 的管理后台:
在这里插入图片描述

🍉③设置 Eureka 客户端的配置文件
spring:
  application:
    name: userservice
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8888/eureka

OK,无需在启动类添加注解,直接启动就可以了,然后打开 Eureka 的服务管理页面,可以看到我们刚刚开启的服务:
在这里插入图片描述
当我们的服务启动之后,会每隔一段时间跟 Eureka 发送一次心跳包,这样 Eureka 就能够感知到我们的服务是否处于正常运行状态。

回到目录…

1.3 服务发现

🍌①远程调用

那么,现在我们怎么实现服务发现呢?
原本的微服务远程调用,那么就必须要知道其他服务的地址:

RestTemplate template = new RestTemplate();
User user = template.getForObject("http://localhost:8082/user/"+uid, User.class);

修改后的微服务远程调用:

a. 我们手动将 RestTemplate 声明为一个 Bean 注册到 Ioc 容器中,然后添加@LoadBalanced注解,这样 Eureka 就会对服务的调用进行自动发现,并提供负载均衡:

@Configuration
public class BeanConfiguration {
    @Bean
    @LoadBalanced // 负载均衡
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

b. 而现在有了 Eureka 之后,我们只需要用服务名称对其查询:

@Service
public class BorrowServiceImpl implements BorrowService {
    @Resource
    private BorrowMapper borrowMapper;
    @Resource
    // RestTemplate 支持多种方式的远程调用
    private RestTemplate template;

    @Override
    public UserBorrowView getBorrowViewByUid(int uid) {
        // 现在拿到借阅关联信息了,怎么调用其他服务获取信息呢?
        List<Borrow> borrowList = borrowMapper.getBorrowsByUid(uid);

        // 这里不用再写IP,直接写服务名称 userservice
        User user = this.template.getForObject("http://userservice/user/"+uid, User.class);
        // 这里通过调用 getForObject 来请求其他服务,并将结果自动进行封装
        List<Book> bookList = borrowList
                .stream()
                .map(b -> template.getForObject("http://bookservice/book/"+b.getBid(), Book.class))
                .collect(Collectors.toList());
        return new UserBorrowView(user, bookList);
    }
}

现在我们就可以正常调用了:
在这里插入图片描述

回到目录…

🍌②负载均衡

🐳同一个服务器多开实例,设置不同的端口:

a. Edit Configuration… -> 选中 UserApplication -> 新建目录 Move into new folder -> 在该目录下新建 Spring Boot -> 进行如下配置
在这里插入图片描述
b. 启动所有实例:
在这里插入图片描述
c. 此时,我们在 Eureka 后台也可以看到新增的实例:
在这里插入图片描述


🐳如何观察 Eureka 对我们多实例的负载均衡:

a. 我们有2个 UserApplication 的实例,可以在控制层的某个服务调用代码中添加日志打印:当前实例的IP:PORT

@RestController
@Slf4j
public class UserController {
    @Resource
    private UserService userService;
    @Resource
    Environment environment; // org.springframework.core.env.Environment

    @GetMapping("/user/{uid}")
    public User findUserById(@PathVariable("uid") int uid) throws UnknownHostException {
        String hostIp = InetAddress.getLocalHost().getHostAddress();
        String port = environment.getProperty("server.port");
        log.info(hostIp + ":" + port + " 的findUserById()被访问了!");
        return userService.getUserById(uid);
    }
}

b. 然后重新启动。我们多次访问http://localhost:8082/borrow/3,其中 BorrowService 就会进行远程调用 UserService,这时我们通过查看 UserApplication-1 和 UserApplication-2 的控制台日志,就可以发现它们是被轮询调用的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样,服务自动发现以及简单的负载均衡就实现完成了,并且,如果某个微服务挂掉了,只要存在其他同样的微服务实例在运行,那么就不会导致整个微服务不可用,极大地保证了安全性。

回到目录…

1.4 心跳机制与自动保护机制

🍆①介绍
  • Eureka 心跳机制: 在应用启动后,节点们将会向 Eureka Server 发送心跳,默认周期为 30 秒,如果 Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,Eureka Server 将会从服务注册表中把这个服务节点移除 (默认90秒)。

  • Eureka自动保护机制: Eureka Server 在运行期间会去统计心跳成功的比例在 15分钟之内 是否低于 85% 。如果低于85%, Eureka Server 会认为当前实例的客户端与自己的心跳连接出现了网络故障,那么 Eureka Server 会把这些实例保护起来,让这些实例不会过期导致实例剔除。

这样做的目的是为了减少网络不稳定或者网络分区的情况下,Eureka Server 将健康服务剔除下线的问题。 使用自我保护机制可以使得 Eureka 集群更加健壮和稳定的运行。进入自我保护状态后,会出现以下几种情况:

  1. Eureka Server 不再从注册列表中移除因为长时间没有收到心跳而应该剔除的过期服务;
  2. Eureka Server 仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上,保证当前节点依然可用。
  3. 在 SpringCloud 中,可以使用 eureka.server.enable-self-preservation = false 禁用自我保护模式。
🍆②关闭自我保护机制

 Eureka 的自我保护机制指的是,当网络发生问题导致服务访问失败时,eureka 注册中心不会马上把应用剔除,继续保留一段时间。但这样对我们实际开发来说,需要频繁重启应用的时候,不方便测试,需要将自我保护机制关闭。

Ⅰ 修改 eureka 服务端:

eureka:
  server:
    # 关闭自我保护机制,保证不可用服务被及时剔除
    enable-self-preservation: false
    # 心跳检测时间,设置成2秒
    eviction-interval-timer-in-ms: 2000

Ⅱ 修改 eureka 客户端:

eureka:
  instance:
    # eureka客户端向服务端发送心跳的时间间隔,单位是秒(默认30秒)
    lease-renewal-interval-in-seconds: 1
    # eureka服务端在收到最后一次心跳后等待时间的上限,单位为秒(默认90秒),超时将会剔除服务
    lease-expiration-duration-in-seconds: 2

配置完成之后,经测试可体验到在服务关闭后非常快速地剔除应用。

回到目录…

二、注册中心高可用: 搭建 Eureka 集群

各位可否想过这样的一个问题?虽然Eureka能够实现服务注册和发现,但是如果Eureka服务器崩溃了,岂不是所有需要用到服务发现的微服务就GG了?

为了避免,这种问题,我们也可以像上面那样,搭建Eureka集群,存在多个Eureka服务器,这样就算挂掉其中一个,其他的也还在正常运行,就不会使得服务注册与发现不可用。当然,要是物理黑客直接炸了整个机房,那还是算了吧。
在这里插入图片描述
我们来看看如何搭建Eureka集群,这里由于机器配置不高,就搭建两个Eureka服务器组成集群。

①服务端创建两个配置文件

application-1.yml

server:
  port: 8801
spring:
  application:
    name: eurekaserver  # 所有eureak的这个值要设置为同一个
eureka:
  instance:
    # 由于不支持多个localhost的Eureka服务器,但是又只有本地测试环境,所以就只能自定义主机名称了
    # 如果报错主机名称改为 eureka01
    hostname: eureka01
  client:
    # false表示自己就是注册中心
    fetch-registry: false
    service-url:
      # 注意这里填写其他 Eureka 服务器的地址,不用写自己的
      defaultZone: http://eureka02:8802/eureka

application-2.yml

server:
  port: 8802
spring:
  application:
    name: eurekaserver
eureka:
  instance:
    hostname: eureka02
  client:
    fetch-registry: false
    service-url:
      defaultZone: http://eureka01:8801/eureka

②修改本地 hosts

这里由于我们修改成自定义的地址,需要在 hosts 文件中将其解析到 127.0.0.1 才能回到 localhost。
Linux 下文件路径为 /etc/hosts
Windows 下文件路径为 C:\Windows\system32\drivers\etc\hosts,需要获取权限比较麻烦,可以利用火绒安全软件直接修改
在这里插入图片描述
Windows系统修改hosts后需要刷新DNS缓存使之生效,在cmd命令行中执行命令:ipconfig/flushdns

回到目录…

③开启两个 EurekaServer 实例

对创建的两个配置文件分别添加启动配置,直接使用-Dspring.profiles.active指定启用的配置文件即可:
在这里插入图片描述

接着启动这两个注册中心,这两个 Eureka 管理页面都可以被访问,我们访问其中一个:
在这里插入图片描述
可以看到下方replicas中已经包含了另一个Eureka服务器的地址,并且是可用状态

回到目录…

④修改Eureka客户端的配置文件

eureka:
  client:
    service-url:
      # 将两个Eureka的地址都加入,这样就算有一个Eureka挂掉,也能完成注册
      defaultZone: http://localhost:8801/eureka, http://localhost:8802/eureka

可以看到,服务全部成功注册,并且两个 Eureka 服务端都显示为已注册:
在这里插入图片描述

接着我们模拟一下,将其中一个Eureka服务器关闭掉,可以看到它会直接变成不可用状态:
在这里插入图片描述
当然,如果这个时候我们重启刚刚关闭的Eureka服务器,会自动同步其他Eureka服务器的数据。

回到目录…


总结:
提示:这里对文章进行总结:
本文是对SpringCloud的学习,学习了它的组件Eureka注册中心,包括服务的注册与发现,高可用(Eureka集群的搭建)。之后的学习内容将持续更新!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只咸鱼。。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值