Spring Cloud 详细入门系列(一)

在入门前,第一件事是了解全貌。

首先,让我们先大概知悉 Spring Cloud 能为我们做到什么。

从官网、各类博客、以及相关技术类论坛中提炼了下述比较关键的作用,这也是它大放异彩的基本要素:

  1. 微服务框架,提供全套的分布式系统解决方案,比较传统的技术,会更加稳定且具有容错性;
  2. 只作集成封装(挺多开源框架与组件,包括对 SpringBoot 的深度集成,继承了其优秀的“约定大于配置”,能通过注解以及 yml 进行配置)
  3. 对开发者友好,十分容易上手,如配置、断路机制、选举、分布式 session、状态管理等常规处理提供了简便的操作,便于上手。
  4. 对 IDE 其实也友好,只要支持 Spring Boot,基本上也能开发 Spring Cloud,例如我的 VsCode 就可以进行使用。

第三点最为重要,决定了这项技术是否是通用的,或者是仅适用小部分组织,目前来看,它甚至适用于个人开发。

了解 Spring Cloud 的基础概念「重要」

截至至此随笔的发布日期,目前的Spring Cloud有着下述的基本概念,先尝试理清楚它们之间的关系,然后逐个实践,这样有助于你继续了解此框架。

  • EureKa(服务注册与发现)
  • Config(分布式统一管理配置)
  • Zuul(服务网关)
  • Ribbon(客户端负载均衡器)
  • Feign(声明 Web 服务客户端)
  • Hystrix(断路器「熔断器」

上述概念仅需记忆中文即可,因为除了核心服务外,其余都是类似于积木的存在,是可被替换的,例如服务网关 Spring Cloud Zuul,也可能被替换为 Spring Cloud Gateway,故此特别说明;

嗯。。怎么说呢,积木的形状是确切的,但是颜色我们管不着,所以只需要记住形状就可以。

那么,它们之间的关系是怎样的呢?

Spring Cloud for Microservices Compared to Kubernetes | Red Hat Developer

图来自网络,大概讲解一下:

整体来说,就像是一个有序的机构:既有招待 client 的服务员,指引他们到各个分工明确的窗口办理业务,也有保安针对某窗口排队人数过多的情况进行处理,比如让新来的人先去其它窗口,这个窗口先不开放。。

而这个机构的名字就叫做“服务注册与发现”,内部是各类服务,有序且分工明确。机构之间能产生互动,即集群,在此篇随机也有提及,如双注册服务中心,当然你也能套娃,三个四个五个也是看你需求了。

现在你不会发懵了吧,起码了解了大概的流程、以及 Spring Cloud 究竟是干啥的,如果不了解,请先放下你的中指,然后再多看一遍。

开始实践:服务注册与发现

ps:其余本篇不介绍,接下来也仅有 EureKa 的实践和说明,比如双注册,多注册的形式,假设你想了解网关之类的其它“积木”,那么你打开错随笔了,可以看看首页是否有此系列的续篇,如果没有的话就下次一定。

笔者仅学习了半天,并实践完成,过程中一次通过,花了些时间写了随笔,如果有错误麻烦你在评论区留言,我会进行修改。

在开始之前,你应该时刻注意“版本号”的依赖,事实上,学习的开始最应该注意的就是这些细节了,否则你一定会遇到报错。

另外,已经假设你初始化了 Spring Boot 的框架环境,通常各种 IDE 都具备新建 Spring Boot 项目。

可进入官网查看粗略的依赖情况,每个版本号又会细分很多种,可以选择相邻日期来推测合适的依赖。

https://spring.io/projects/spring-cloud

我的 VsCode 会显示相应的发布日期,这能有效地提示依赖情况:

此篇文章所使用的依赖为:Spring Boot 2.3.12.RELEASE,对应 Spring Cloud Hoxton.SR12,其依赖如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.12.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.dome</groupId>
	<artifactId>backend</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>backend</name>
	<description>Demo project for Spring Boot</description>

	<!-- 指定 JDK 版本 -->
  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

	<dependencies>
      <!-- 框架类 -->
	  <dependency>
	    <groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<scope>runtime</scope>
		<optional>true</optional>
	  </dependency>
      <dependency>
	    <groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
		<optional>true</optional>
	  </dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	  </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <!--引入springcloud的euekea server依赖-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
	</dependencies>

  <!-- 指定下载源和使用 SpringCloud 版本 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR12</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

</project>

搞定依赖关系后,就可以进入下一步操作,此时你的项目结构大致有以下几个关键文件:

  • ApplicationStartup.java (包含用于启动应用的主函数,名称不必在意,随便敲的)
  • pom.xml(依赖管理)
  • application.yml(应用配置)

上述三个文件是最为重要的核心部件,它们分别在:

  • ApplicationStartup 放置在 src/main/java/com/dome/backend 目录下,当然这个是IDE生成的,我只是举个例子,IDE 对此文件命名可能为:BackendApplication.java ——假设你的命名空间最后是 backend 的话。
  • pom.xml 通常在项目的根目录,与 src 同级
  • application.yml 通常可新建文件夹并纳入编译区供程序使用,而大部分 IDE 会默认于 src/resources 目录下放置

了解完关键文件后,接下来,我们仅需对它们进行简单的处理(pom.xml 略,上面有了),就可以得到一个 Spring Cloud 的基本结构了。

pom.xml 处理完毕后,IDE 会自动下载依赖 jar 包,所以你可以直接在 .java 文件中直接引用,所以,让我们先从 ApplicationStartup.java 文件(强调,可能为其它名字,不信你看看上述说明)开始吧。

对此启动类的处理,仅需加上一行代码即可。

package com.dome.backend;

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

@SpringBootApplication
@EnableEurekaServer
public class ApplicationStartup {

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

}

是的,相比较 IDE 为 SpringBoot 生成的启动类代码,仅多加了注解:@EnableEurekaServer

那么这个注解有什么作用呢?好问题,篇幅过长,不想解释,大概理解为:

它的作用是一个标识,同理,还有一个叫做 @EnableEurekaClient,另外的作用是,它会调用数个类,比如 EurekaServerAutoConfiguration、EurekaServerInitializerConfiguration,前者用于配置,如其中的方法:@ConditionalOnBean({Marker.class}) 去装载适用于 Eureka 服务端主要功能的 Bean,后者主要是初始化 EureKa 的实现类,以生命周期回调方法去初始化 EureKa。

只是粗略了解,所以有错误你可以指出,我会记录并改掉此问题。

接下来配置 yml,如下:

server:
  port: 8080

eureka:
  client:
    # 是否要将本身注册至 EureKa Server 上,默认为 true,但是当前我们不是使用集群,本身即为服务,故设置为 false
    register-with-eureka: false
    # 是否从 EureKa Server 中获取注册信息,默认为 true,很遗憾,本身即为服务,并不需要从其它 EureKa Server 节点同步信息,故设置为 false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  instance:
    hostname: node1

spring:
  application:
    # 本应用名称,集群时,此处较为重要
    name: eureka-server
  profiles:
    active: node1

 该注释的都注释了,就讲一下 ${eureka.instance.hostname} 之类的吧,你可以理解为,它会自动地到配置文件中寻找对应的节点里的值进行读取,具体就不讲解了,你也可以换成 http://node1:8080/eureka/

其次是 node1 是什么呢?好问题,其实在同一台机器上,ip 地址是固定的(127.0.0.1),假设你使用了双节点服务注册与发现的话,那你就用不了副本了,具体情况可以在其余博客中找到,篇幅问题不作讲解,仅贴结果:

你可以看见,即便注册了,也是不可用的。 

这就是使用相同ip,不同端口的配置,且适配了使用 IP 的形式:prefer-ip-address: true,但是如果有多台服务器,使用 ip 应该是较为理想的方案(没试过,若有实践可以在评论区给大家参考噢)。

所以,你需要在 hosts 文件中进行下述配置:

127.0.0.1 node1
127.0.0.1 node2

node2 是为了下文作铺垫,可以先配置,当然你愿意的话,也能加到 node[N],例如 node123456789

完成上述配置后,就可以启动你的应用程式了!

接下来,在浏览器输入:node1:8080,就能看到下述界面:

你已经掌握了 Spring Cloud EureKa 服务注册与发现的基本流程,接下来我们将尝试多注册中心的集群配置

Spring Cloud 已经帮我们做到最简化了,这也是它的优势,也是开发者们乐于见到的,没有人会拒绝简单而有效的事物,不是吗?

OK,将你的源码复制一份,第一份(原先)命名为 EureKa-1,当然你也可以按自己的喜好命名,第二份命名为 EureKa-2。

接下来,你只需要改动 application.yml 配置文件即可,简单几行变动就可以达到集群的目的。

Eureka-1 的 yml 如下:

server:
  port: 8080

eureka:
  client:
    # 是否要将本身注册至 EureKa Server 上,默认为 true,两个以上为团伙作案,故为 true
    register-with-eureka: true
    # 是否从 EureKa Server 中获取注册信息,默认为 true,两个以上为团伙作案,故设置为 true
    fetch-registry: true
    service-url:
      defaultZone: http://node2:8081/eureka/
  instance:
    hostname: node1

spring:
  application:
    # 本应用名称,集群时,此处较为重要
    name: eureka-server
  profiles:
    active: node1

EureKa-2 的 yml 如下:

server:
  port: 8080

eureka:
  client:
    # 是否要将本身注册至 EureKa Server 上,默认为 true,两个以上为团伙作案,故为 true
    register-with-eureka: true
    # 是否从 EureKa Server 中获取注册信息,默认为 true,两个以上为团伙作案,故设置为 true
    fetch-registry: true
    service-url:
      defaultZone: http://node1:8080/eureka/
  instance:
    hostname: node2

spring:
  application:
    # 本应用名称,集群时,此处较为重要
    name: eureka-server
  profiles:
    active: node2

在双注册的情况下,你会发现仅仅变动了三个属性就可以达到“团伙作案”的效果,至于为什么如此,你可以先实践后再接着往下看,先上一张效果图:

嗯,可以看见底部的 registered-replicas 以及 available-replicas 是有内容的,说明它们互相注册成功了,至于 matrix2 ,只是我把 node 换成了计算机名 matrix 而已,先不必管这些细节。 

接下来,你仅需了解 yml 中的 defaultZone 属性即可,其它几个都进行备注了,不过你也可以通过搜索引擎(比如 Bing,Google)了解,何况我还有注释

那么,defaultZone 属性,是什么作用呢?答案是:注册 EureKa 的地址,假设有多台,那么你需要以“,”(英文逗号)隔开

例如 A 服务器注册到 B、C、D 服务器,而 B 服务器注册到 A、C、D 服务器中

假设 A 宕机了,那么并不会影响到 B 服务,因为 B 服务还注册了 C 、D,即便 C、D 都崩了,还有 B 自身,它自己也是一个服务。

让我们模拟一下双注册服务下,其中一个崩掉的情况:

可以看到,未停机的 EureKa-2 会每隔一定的时间段尝试连接停机的 EureKa-1,接下来,我们打开界面看看(EureKa-1):

如期所料,无法访问,那么我们转而去 EureKa-2 的界面看看:

正常使用,但 EureKa-1 被移到不可用中。那么,接下来的流量请求,就都会压到 EureKa-2 这个服务了,这也是集群的好处,一台崩了,还有另外一台顶着不是吗?

但是这样未免。。太过暴力,假设最后一台没了,是不是就会损失客户了呢?肯定是有解决方案的,所以,敬请期待此系列后续讲解~

至此,你掌握了什么?

  • Spring Cloud EureKa 服务注册与发现的基本流程
  • 多注册中心集群配置的基本要素

写于 2021-07-13

坐标:广州

转载请联系博主,否则视为侵犯著作权,或者留下转载地址(http://www.cnblogs.com/chongsaid),我发至网络仅为分享(发现数篇文章被翻译了五六种外国语言了,有些需要充值才能解锁),勿当作牟利的工具噢。

原文地址:https://www.cnblogs.com/chongsaid/p/spring-cloud-1.html