Spring Cloud应用学习
新的项目要使用到Spring Cloud,所以现行学习一下,之后在继续学习JDK的源码。
本文将从以下几点来学习Spring Cloud
1.为什么要使用Spring Cloud
2.怎么使用Spring Cloud
3.Spring Cloud工作原理
官方文档中这样描述Spring Cloud:
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,
智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持
实现这些模式的服务和应用程序。他们将在任何分布式环境中运行良好,包括开发人员自己的笔记本电脑,裸机
数据中心,以及Cloud Foundry等托管平台。
那么接下来,我开始按照这些描述来学习Spring Cloud。
1.Spring Cloud服务注册
1.1 为什么需要服务中心
这个问题是我在学习Spring Cloud时最关心的问题,对于框架来说,配置的东西百度上很多,反而是解决了那些问题和工作原理成了需要理解的重点。
简单描述一下微服务架构是为了解决什么问题。随着系统结构、架构的演变,系统功能的增加,用户量的增加,开发人员的增加等各种增加情况下,需要有一个比较好扩展的系统架构来快速、尽量减少代码改动的前提下以支持系统功能的开发,用户量增加导致的硬件资源横向扩容,以及开发人员增加时的协同工作效率。在此基础上需要解决系统的稳定性、容错性、高并发的支持性等。以及随着系统功能的增加如何有效的管理系统,排查、定位系统问题。同时当参与项目的人(包含测试、运维、业务等人员)越来越多时,如何能更高效的彼此之间协同办公的效率等等。所以微服务架构需要考虑的不仅仅是软件架构本身,需要从参与到整个项目实施过程中的各个环节,可能的问题以及人员协同的整体情况去考虑。让整个项目做到可用(满足功能以及硬件资源的横向扩容)、可行(满足整个系统运行中的各个点的监控、排错等)、可持续(满足系统功能的可持续集成、以及系统运行的可持续性)以及高效(系统运行的高效、人员协同工作的高效、功能迭代的高效等)。
1.2 Eureka的应用场景
Spring Cloud提供了微服务解决的一整套方案,而Eureka是其重要组件,所以先要了解什么是“微服务”。在大型系统架构中,会拆分多个子系统。这些系统往往都有这几个功能:提供接口,调用接口,以及该子系统自身的业务功能。这样的一个子系统就称为一个“微服务”。(可以理解为一个子系统的代码所实现的功能)
比如百度的搜索子系统,就具备了:根据用户的输入的信息对信息分词功能、对每个分词给予权重功能、然后根据分词和权重等信息计算出网页相关度功能、最后把相关度高的网页按照一定算法排序后提供结果功能、记录用户录入信息功能等等业务功能。同时它还提供用户录入信息提供的接口给其它子系统调用,如地图子系统、广告推荐子系统会调用该接口后完成各自的业务功能。同时搜索子系统也会调用其它子系统的接口,如调用地图子系统的地图显示接口等。
1.3 Eureka如何管理服务调用
eureka如何管理服务调用的?我们先来看个图:
→在Eureka Client启动的时候,将自身的服务的信息发送到Eureka Server。然后进行2调用当前服务器节点中的其他服务信息,保存到Eureka Client中。当服务间相互调用其它服务时,在Eureka Client中获取服务信息(如服务地址,端口等)后,进行第3步,根据信息直接调用服务。(注:服务的调用通过http(s)调用)→当某个服务仅需要调用其他服务,自身不提供服务调用时。在Eureka Client启动后会拉取Eureka Server的其他服务信息,需要调用时,在Eureka Client的本地缓存中获取信息,调用服务。→Eureka Client通过向Eureka Serve发送心跳(默认每30秒)来续约服务的。 如果客户端持续不能续约,那么,它将在大约90秒内从服务器注册表中删除。 注册信息和续订被复制到集群中的Eureka Serve所有节点。 以此来确保当前服务还“活着”,可以被调用。→来自任何区域的Eureka Client都可以查找注册表信息(每30秒发生一次),以此来确保调用到的服务是“活的”。并且当某个服务被更新或者新加进来,也可以调用到新的服务。简单的了解了eureka如何管理服务调用的之后,我们看看官网提供的图片,进一步了解更多信息(官网地址:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance):
这个图从上而下,首先看到us-east-1c、us-east-1d、us-east-1e这些代表了一个可用区。简单举个栗子,假设一个Eureka Server集群下面的分布情况是这样的:
“北京集群中心”是一个区域,北京市内的机房A和B为可用区(对应官网图片中的us-east-1c、us-east-1d、us-east-1e)。区域(Region)和可用区(Zone或者Availability Zone)均是AWS的概念。在非AWS环境下,我们可以简单地将region理解为Eureka某个地区的集群中心,zone理解成该区域的每个机房。每个区域是通过外网连接,所以速度、稳定性上不能保证。而每个可用区之间一般是内网直连,保证速度。想更多了解AWS概念的可用查看http://blog.csdn.net/awschina/article/details/17639191
回到官网的图片可以看出在这个体系中,有2个主体:Eureka Server和Eureka Client。Eureka Server:提供服务注册:各个微服务启动时,会通过Eureka Client向Eureka Server进行注册自己的信息(例如服务信息和网络信息),Eureka Server会存储该服务的信息。
提供服务信息提供:服务消费者在调用服务时,本地Eureka Client没有的情况下,会到Eureka Server拉取信息。
提供服务管理:通过Eureka Client的Cancel、心跳监控、renew等方式来维护该服务提供的信息以确保该服务可用以及服务的更新。
信息同步:每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过P2P复制的方式完成服务注册表的同步。同步时,被同步信息不会同步出去。也就是说有3个Eureka Server,Server1有新的服务信息时,同步到Server2后,Server2和Server3同步时,Server2不会把从Server1那里同步到的信息同步给Server3,只能由Server1自己同步给Server3。
每个可用区有一个Eureka集群,并且每个可用区至少有一个eureka服务器来处理区内故障。为了实现高可用,一般一个可用区中由三个Eureka Server组成。
Eureka Client
Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。并且管理当前微服务,同时为当前的微服务提供服务提供者信息。
Eureka Client会拉取、更新和缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者。
Eureka Client在微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒)以续约自己的信息。如果Eureka Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服务节点(默认90秒)。
Eureka Client包含服务提供者Applicaton Service和服务消费者Application
ClientApplicaton Service:服务提供者,提供服务给别个调用。
Application Client:服务消费者,调用别个提供的服务。往往大多数服务本身既是服务提供者,也是服务消费者。
其它动作:
Register:服务注册
当Eureka客户端向Eureka Server注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等。
Renew:服务续约
Eureka Client会每隔30秒发送一次心跳来续约。 通过续约来告知Eureka Server该Eureka客户仍然存在,没有出现问题。 正常情况下,如果Eureka Server在90秒没有收到Eureka客户的续约,它会将实例从其注册表中删除。 建议不要更改续约间隔。
Fetch Registries:获取注册列表信息
Eureka客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。每次返回注册列表信息可能与Eureka客户端的缓存信息不同, Eureka客户端自动处理。如果由于某种原因导致注册列表信息不能及时匹配,Eureka客户端则会重新获取整个注册表信息。 Eureka服务器缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka客户端和Eureka 服务器可以使用JSON / XML格式进行通讯。在默认的情况下Eureka客户端使用压缩JSON格式来获取注册列表的信息。
Cancel:服务下线
Eureka客户端在程序关闭时向Eureka服务器发送取消请求。 发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:DiscoveryManager.getInstance().shutdownComponent();
Eviction 服务剔除
在默认的情况下,当Eureka客户端连续90秒没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。
1.4 如何使用Spring Cloud的注册服务
Spring Cloud使用erureka server, 然后所有需要访问配置文件的应用都作为一个erureka client注册上去。eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳,在默认情况下erureka server也是一个eureka client ,必须要指定一个 server。
1.4.1 创建一个Eureka Server
1、首先创建一个maven工程,并在工程中引入相关的资源包,所有的使用以Eclipse为例:
创建maven工程,然后起一个名字。
2、然后引入一些必要的资源包
<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.lin</groupId>
<artifactId>springcloud.helloworld.eureka.server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springcloud.helloworld.Eureka.server</name>
<description>Demo Spring Eureka Server</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring boot test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
3、然后我们创建一个服务类EurekaServerApplication,
package springcloud.helloworld.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(EurekaServerApplication.class, args);
}
}
这里要注意一下,想要实现一个服务注册中心的功能非常简单,只需要在项目的启动类EurekaServerApplication上使用@EnableEurekaServer注解即可。
但是,默认情况下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为。registerWithEureka: false
4、创建一个eureka server的配置文件application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
5、最后的工程结构图
6、试着去启动服务,然后访问http://localhost:8761, 界面如下
“No instances available” 表示暂时没有client注册,到此,一个简单的Eureka Server就ok了。
1.4.2 创建一个Eureka Client
1、首先创建一个maven工程,并在工程中引入相关的资源包,所有的使用以Eclipse为例:
创建maven工程,然后起一个名字。
2、然后引入一些必要的资源包
<?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.lin</groupId>
<artifactId>springcloud.helloworld.eureka.client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud.helloworld.eureka.client</name>
<packaging>jar</packaging>
<description>Demo Spring Boot Client</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
3、创建主类EurekaClientApplication
使用@EnableEurekaClient注解表明是client
package springcloud.helloworld.eureka.client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaClientApplication {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(EurekaClientApplication.class, args);
}
@Value("${server.port}")
String port;
@RequestMapping("/")
public String home() {
return "hello world from port " + port;
}
}
4、eureka client的配置文件application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8762
spring:
application:
name: service-helloworld-lin
5、最后的工程结构图
6、试着去启动服务,然后访问localhost:8762, 界面如下
然后刷新localhost:8761,可以看到 SERVICE-HELLOWORLD-LIN 已经被注册到服务器上去了
资料来源:
https://www.jianshu.com/p/2fa691d4a00a
https://www.cnblogs.com/chry/p/7248947.html
https://springcloud.cc/spring-cloud-dalston.html