上一篇:从一个简单的springCloud项目开始—搭建一个微服务框架
<spring-cloud.version>Hoxton.SR8</spring-cloud.version> <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
1.初始Eureka
说到Eureka就不得不说说服务治理 和服务注册和发现
1.1、服务治理
在微服务盛行的今天,服务的颗粒度被拆分的很细,同时服务数量也在增长,在原生中,服务治理更多的情况下与容器调度平台结合,形成一站式的自动化调度平台;不管使用什么调度系统,服务治理的原理和范畴是不会改变的,只是不同的实现方式;服务治理主要包括了服务发现,负载均衡,限流,熔断,超时,重试,服务追踪等。
为什么需要服务治理?在那些方面的需要才出现服务治理?当我们服务间互相调用的时候,我们之前的做法都是使用httpclient去请求,不会通过第三方统一管理,要不就是统一配置路径(数据库,配置文件等),要不就是代码直接写死,如果我们有个服务地址需要更改,如果有调用该服务的所有的地址配置都需要调整,维护成本高,而且也容易丢失,当服务超多的时候可能也改不全地址为系统稳定性带来风险;由于类似这样的问题,才会有了服务治理,同时也出现了一批服务治理相关的组件也就是注册中心;代表有:zookeeper、Eureka、Consul、Nacos。
总结来说微服务架构通讯,通讯之间依赖关系非常大,每个服务的url管理复杂混乱,如果通过传统的方式对url管理,一旦地址变化后,还需要人工修改rpc远程调用地址,如果这时候采用服务URl治理技术,可是实现对整个动态服务的注册与发现等。
1.2、服务注册与发现
当服务启动时会把当前自己服务的信息,比如服务地址通讯地址等以别名的方式注册到注册中心上,另一方,以该别名的方式去注册中心上获取到实际的通讯地址,然后实现本地rpc远程调用。
为什么需要服务发现?如果没有服务发现模块,服务网络位置信息的配置会耦合在具体服务消费这的配置中,从而导致系统难以维护;但是有个问题服务消费者是如何知道服务提供者的ip和端口的,在简单的体系架构中,静态配置(比如DNS、Nginx负载均衡配置等)的方法解决;每个服务都部署在同一个位置,并且很少做改动。传统的单体式应用的网络地址发生变化的概率较少,在发生改变的时候,需要开发或者运维人员手动更新,重新加载配置文件。但是在微服务架构中,微服务更新,发布频繁,并且经常会根据负载情况进行弹性伸缩,因为微服务应用实例的网络地址变化是一个很常态的事情,而之前提到的静态配置的解决方案,明显不适合高频动态的场景,所以,我们需要由一种机制,让消费者在服务提供者的ip地址发生变化的时候能够快速及时地获取到最新的服务信息。
服务发现是指寻找一个服务provider的网络位置信息,服务发现是支持大规模SOA和微服务架构的核心模块,需要具有服务注册,服务查找,服务健康检查和服务变更通知等关键功能。
1.3、Eureka怎么实现服务注册和发现的
Eureka采用了CS的设计架构,Eureka Server服务端作为服务注册功能的服务器,它是服务注册中心,而系统中其他微服务,使用Eureka Client客户端链接到Eureka Server服务端并保持心跳的链接,这样系统运维以及开发人员就可以通过Eureka Server来监控整个系统中各个微服务是否正常运行。
Eureka原理图:Eureka Server将服务信息注册进注册中心&从注册中心上获取服务信息;实质就是存key服务取value调用地址;(1.生产者把自身信息注册到注册中心;例:服务地址以别名的方式注册进注册中心;2.消费者调用生产者接口时,使用服务别名去注册中心获取实际的RPC远程调用地址;3.消费者获取到地址后,底层实际利用的是HTTPClient技术实现远程调用;4.消费者获取服务地址后会缓存到jvm内存中,默认没间隔30s更新一次服务调用地址。)
2.搭建Eureka服务端和客户端(使用Spring Initializer初始化一个SpringBoot项目,后续都会使用这种方式)
大家可以在上章节我们建的工程下面建Eureka Server和Eureka Client模块(这两个模块我们使用之前生产者和消费者代替),也可重新建立一个工程来做后续springcloud组件相关的学习,我这里就是重新建立一个工程,后面的学习都在这个工程下。
项目结构
springcloud-demo //父工程
|—springcloud-demo-eurekaserver 注册中心
|—springcloud-demo-provider //生产者
|—springcloud-demo-consumer //消费者
2.1、创建新工程 springcloud-demo
创建一个空的maven工程,修改pom.xml,引入核心依赖
<?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.qizh.springcloud</groupId>
<artifactId>springcloud-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2.2、创建Eureka Server注册中心模块
2.2.1、右击父工程—>new—>选择module
2.2.2、选择Spring Initializr 选择jdk和默认spring库就好
填写module相关服务信息
2.2.3、选择模块需要的springCloud组件,我们这里创建的是Eureka Server,所以我们需要选择Eureka Server组件就好了,然后next,完成即可
2.2.4、修改启动类,启用Eureka注册中心功能
package com.qizh.springcloud.springclouddemoeurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class SpringcloudDemoEurekaserverApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudDemoEurekaserverApplication.class, args);
}
}
2.2.5、修改配置文件,这里自动生成的配置文件为application.properties;修改为yml文件;后面我们配置文件主要使用yml
# 指定运行端口和上下文
server:
port: 8003
servlet:
context-path: /springcloud-demo-eurekaserver
# 指定服务名称
spring:
application:
name: springcloud-demo-eurekaserver
# 指定主机地址
eureka:
instance:
hostname: localhost
client:
# 指定是否从注册中心获取服务(注册中心不需要开启);false表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
# 指定是否将服务注册到注册中心(false不向注册中心注册自己)
register-with-eureka: false
service-url:
#设置eureka server交互的地址和注册服务都需要依赖这个地址;单机就是指向自己
defaultZone: http://localhost:8003/springcloud-demo-eurekaserver//eureka/
2.2.6、启动Eureka Server并访问 http://localhost:8003/springcloud-demo-eurekaserver/
能正常访问就说明我们注册中心已经正常启动了;接下来就是把服务注册到注册中心然后去消费
2.3、把生产者和消费者的服务注册到注册中心 Eureka Server
2.3.1、把生产者 springcloud-demo-provider 的服务注册到注册中心
2.3.1.1、添加Eureka Client依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.3.1.2、修改yml配置文件
#eureka配置
eureka:
client:
#表示是否将自己注册进eureka 默认为true
register-with-eureka: true
#是否从EurekaServer中抓取已有的注册信息,默认为true,单点无所谓,集群必须设置true才能和ribbon使用负载均衡
fetch-registry: true
service-url:
#单机配置
defaultZone: http://localhost:8003/springcloud-demo-eurekaserver//eureka/
2.3.1.3、在启动类中增加启动Eureka Client注解:
@EnableEurekaClient
@SpringBootApplication(scanBasePackages = {"com.qizh.springclouddemo"})
public class CloudDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CloudDemoApplication.class,args);
}
}
2.3.1.4、再查看注册中心http://localhost:8003/springcloud-demo-eurekaserver/
在这里就可以看到生产者已经注册到注册中心了;可以对比之前未注册的注册中心为:No instances available;注册成功后application则显示的是该服务的服务名即为yml配置文件中的spring.application.name;
我们再次访问之前访问生产者的测试地址:http://localhost:8001/springcloud-demo-provider/ping
截止当前我们已经完成了生产者在注册中心的测试,接下来我们继续完成消费者在注册中心的注册。
2.3.3、把消费者springcloud-demo-consumer 的服务注册到注册中心
把消费者注册到注册中心和把生产者注册到注册中心是一样的这里就不再细说,重复生产者注册到注册中心的操作
这时候我们再访问注册中心http://localhost:8003/springcloud-demo-eurekaserver/
再访问消费者的测试地址:http://localhost:8002/springcloud-demo-consumer//consumer/ping
到目前为止我们就完成了整个注册过程。
我们一般看到的注册中心都会有安全认证的;这个感兴趣的可以结合spring-boot-starter-security在Eureka Server中添加相关配置自行完成。
2.2、搭建注册中心集群,之前我们搭建的都是单机模块,但是在我们正常投入使用过程中,都是远远不够的,微服务RPC远程服务调用最核心的就是高可用,如果有一台宕机了,那么所有的服务都不能使用了,所以我们就需要集群,来实现负载和容错;Eureka Server集群是需要指向其他的Eureka Server,有多个需要闭环指向;比如有Eureka1、Eureka2、Eureka3这三个注册中心,Eureka1指向Eureka2,Eureka2指向Eureka3,Eureka3指向Eureka1完成闭环指向。
Eureka集群需要相互注册,相互守望;Eureka Server注册中心集群和Dubbo的zookeeper注册中心结构还是有很大不同,Eureka Server集群中每个节点都是平等的,集群所有的节点同时对外提供服务的发现和注册等功能,同时每个Eureka Server集群的每个节点又是一个微服务。CAP理论指出:一个分布式系统不可能同时满足C(一致性)、A(可用性)、P(分区容错性);由于分布式系统中必须保证分区容错性,因此我们只能在A、C做权衡,zookeeper保证的是CP,Eureka保证的是AP。
我们一般是部署多个应用;重复之前Eureka Server创建过程重新创建就好了;我这里采用修改idea启动profiles的配置来完成多个注册中心的部署;这里我只完成2个相互指向,如果需要更多的可以自己做一下,
既然我们要配置多个服务中心,那么我们就需要多个注册中心服务,首先我们通过配置hosts来配置多个域名;我的是windows:C:\Windows\System32\drivers\etc
2.2.1、配置hosts:
127.0.0.1 eureka8003
127.0.0.1 eureka8004
2.2.2、修改启动配置
copy一个yml文件
application.yml
# 指定主机地址
eureka:
instance:
hostname: localhost
client:
# 指定是否从注册中心获取服务(注册中心不需要开启);false表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
# 指定是否将服务注册到注册中心(false不向注册中心注册自己)
register-with-eureka: false
service-url:
#设置eureka server交互的地址和注册服务都需要依赖这个地址;单机就是指向自己
defaultZone: http://eureka8004:8004/springcloud-demo-eurekaserver/eureka/
application-eureka2.yml
# 指定主机地址
eureka:
instance:
hostname: localhost
client:
# 指定是否从注册中心获取服务(注册中心不需要开启);false表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
# 指定是否将服务注册到注册中心(false不向注册中心注册自己)
register-with-eureka: false
service-url:
#设置eureka server交互的地址和注册服务都需要依赖这个地址;单机就是指向自己
defaultZone: http://eureka8003:8003/springcloud-demo-eurekaserver/eureka/
修改启动配置:
第一个我们使用默认就好了如果说你修改了profiles,填写这里就OK
这时候我们分别启动即可:启动完成后我们访问两个注册中心;这时候我们就会发现他们互为备份了;
http://eureka8003:8003/springcloud-demo-eurekaserver/
http://eureka8004:8004/springcloud-demo-eurekaserver/
到目前为止我们eureka注册中心集群就搭建完成,然后我们修改配置让生产者和消费者注册到集群中:
修改生产者springcloud-demo-provider和消费者springcloud-demo-consumer的application.yml配置
eureka:
client:
#表示是否将自己注册进eureka 默认为true
register-with-eureka: true
#是否从EurekaServer中抓取已有的注册信息,默认为true,单点无所谓,集群必须设置true才能和ribbon使用负载均衡
fetch-registry: true
service-url:
#单机配置
defaultZone: http://eureka8003:8003/springcloud-demo-eurekaserver/eureka,http://eureka8004:8004/springcloud-demo-eurekaserver/eureka
也可以增加以下配置来修改服务名称和访问路径ip显示
eureka:
instance:
#修改服务名称
instance-id: consumer
#访问路径可以显示ip地址
prefer-ip-address: true
再次访问注册中心:我们就会发现服务已经注册到集群中
到目前为止我们就完成了整个集群的部署以及服务对注册中心集群的注册
接下来我们验证一下我们注册好的服务我就拿生产者来举例了:
3.服务发现
当我们启动服务时,将自身服务的网络地址等信息注册到服务发现组件上(eureka,zookeeper,consul),服务发现组件会存储这些信息。服务消费者会从服务发现组件的查询服务提供者的网络地址,然后根据此地址调用服务提供者的接口,服务之间发现组件需要使用一定的机制来维持心跳,服务发现组件若发现有服务没有提供心跳,那么服务发现组件就会将改服务剔除,微服务网络地址发生变更,会重新注册到服务发现组件上,使用这种方式,可以避免因网络变化导致服务之间的通信停止,服务消费者也无需人工修改网络地址,简单的说就是对于注册到Eureka中的微服务,可以通过服务发现来获得该服务的信息
修改启动类:增加注解@EnableDiscoveryClient
package com.qizh.springclouddemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @ProjectName: springclouddemo
* @ClassName: CloudDemoApplication
* @Description: TODO(一句话描述该类的功能)
* @Author: 86157
* @Date: 2022/5/21 1:23
*/
@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication(scanBasePackages = {"com.qizh.springclouddemo"})
public class CloudDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CloudDemoApplication.class,args);
}
}
增加一个测试类
@RequestMapping("pro/discoveryList")
public Object discovery(){
List<String> services = discoveryClient.getServices();
for(String str:services){
System.out.println("注册的服务有:"+str);
}
return this.discoveryClient;
}
我们访问http://localhost:8001/springcloud-demo-provider/pro/discoveryList
这里只看到一个是因为我把消费者服务没有启动
控制台输出
如果说你修改了服务名称: eureka.instance.instance-id=consumer;这里显示的就是这个id;可以通过下面这个来查看具体的服务信息;
List <ServiceInstance> instances = discoveryClient.getInstances(${eureka.instance.instance-id})