Spring Cloud 详细入门系列(一)
在入门前,第一件事是了解全貌。
首先,让我们先大概知悉 Spring Cloud 能为我们做到什么。
从官网、各类博客、以及相关技术类论坛中提炼了下述比较关键的作用,这也是它大放异彩的基本要素:
- 微服务框架,提供全套的分布式系统解决方案,比较传统的技术,会更加稳定且具有容错性;
- 只作集成封装(挺多开源框架与组件,包括对 SpringBoot 的深度集成,继承了其优秀的“约定大于配置”,能通过注解以及 yml 进行配置);
- 对开发者友好,十分容易上手,如配置、断路机制、选举、分布式 session、状态管理等常规处理提供了简便的操作,便于上手。
- 对 IDE 其实也友好,只要支持 Spring Boot,基本上也能开发 Spring Cloud,例如我的 VsCode 就可以进行使用。
第三点最为重要,决定了这项技术是否是通用的,或者是仅适用小部分组织,目前来看,它甚至适用于个人开发。
了解 Spring Cloud 的基础概念「重要」
截至至此随笔的发布日期,目前的Spring Cloud有着下述的基本概念,先尝试理清楚它们之间的关系,然后逐个实践,这样有助于你继续了解此框架。
- EureKa(服务注册与发现)
- Config(分布式统一管理配置)
- Zuul(服务网关)
- Ribbon(客户端负载均衡器)
- Feign(声明 Web 服务客户端)
- Hystrix(断路器「熔断器」)
上述概念仅需记忆中文即可,因为除了核心服务外,其余都是类似于积木的存在,是可被替换的,例如服务网关 Spring Cloud Zuul,也可能被替换为 Spring Cloud Gateway,故此特别说明;
嗯。。怎么说呢,积木的形状是确切的,但是颜色我们管不着,所以只需要记住形状就可以。
那么,它们之间的关系是怎样的呢?
图来自网络,大概讲解一下:
整体来说,就像是一个有序的机构:既有招待 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),我发至网络仅为分享(发现数篇文章被翻译了五六种外国语言了,有些需要充值才能解锁),勿当作牟利的工具噢。