SpringCloud(二)Eureka服务注册与发现
写在前面:
- 你好,欢迎你的阅读!
- 我热爱技术,热爱分享,热爱生活, 我始终相信:技术是开源的,知识是共享的!
- 博客里面的内容大部分均为原创,是自己日常的学习记录和总结,便于自己在后面的时间里回顾,当然也是希望可以分享自己的知识。目前的内容几乎是基础知识和技术入门,如果你觉得还可以的话不妨关注一下,我们共同进步!
- 除了分享博客之外,也喜欢看书,写一点日常杂文和心情分享,如果你感兴趣,也可以关注关注!
- 微信公众号:傲骄鹿先生
说明:1、专栏涉及到的源码已经同步至 https://github.com/SetAlone/springcloud2020(持续更新)
2、springcloud系列博文内容为学习《尚硅谷2020最新版SpringCloud(H版&alibaba)框架开发教程》的记录,此系列课程是目前看来个人觉得非常不错的资源,在此可以与大家进行分享。
3、个人收集到了课程源码和所需的脑图、笔记等资源,如需要私信我即可。查找资源不易,希望可以给个点赞和关注。
一、基础知识
1、什么是服务治理
Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务治理。
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,所以需要使用 服务治理,管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
2、什么是服务注册
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他服务,使用Eureka的额客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册和发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息以别名方式注册到注册中心上。另一方(消费服务提供者)以该别名的方式去注册中心上获取到实际的服务通讯地址,然后在实现本地RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理理念)。在任何的RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。
3、Eureka的两个组件
二、单机Eureka构建
1、IDEA生成EurekaServer端服务注册中心
1)建moudle
在父工程上右键,new——>moudle,新建一个新的maven项目,不需要选择向导。命令为cloud-eureka-server7001。
2)改pom
<?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">
<parent>
<artifactId>springcloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot web actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
3)写yml
在resources文件夹下创建application.yml文件
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4)主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001
{
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
5)测试
因为是服务注册中心,所以不需要编写业务类。进行测试:
在浏览器中输入http://localhost:7001/进行测试,如下为测试结果图:
2、EurekaClient端cloud-provider-payment8001 将注册进EurekaServer成为服务提供者provider
1)选定8001模块
2)改pom,在8001模块的pom文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3)写yml
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
4)主启动
在主启动类PaymentMain8001中添加@EnableEurekaClient注解
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
5)测试
启动Eureka Server,然后进行测试。http:localhost:7001
3、EurekaClient端cloud-consumer-order80 将注册进EurekaServer成为服务消费者consumer
1)选定cloud-consumer-order80模块
2)改pom,在80模块的pom文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3)写yml
server:
port: 80
spring:
application:
name: cloud-payment-service
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
4)主启动
在主启动类OderMain8001中添加@EnableEurekaClient注解
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
5)测试
三、集群Eureka构建
1、Eureka集群原理说明
服务注册:将服务信息注册到注册中心
服务发现:从注册中心上获取到服务信息
其实质就是:key-value形式的。Key:服务的名字 value:服务调用地址
执行步骤:
1、先启动eureka注册中心
2、启动服务提供者(我们这里的服务提供者就是payment支付服务)
3、服务提供者在启动后会把自身的信息(如服务地址,以别名方式注册到)注册到eureka中
4、消费者(我们这里是order服务)在需要调用接口的时候,使用服务别名去注册中心获取到实际的RPC远程调用地址
5、消费者获取到调用地址后,底层实际是利用HttpClient技术实现远程调用的
6、消费者获得服务地址后会缓存在本地的JVM内存中,默认每隔30秒更新移除服务调用地址
如果我们的注册中心只有一个,在发生故障的情况下,就会导致整个的服务不可用,我们可以通过搭建Eureka注册中心集群的方式,实现负载均衡和故障容错。
原理说明:
前面我们实现了单机Eureka搭建,既然是集群搭建,就意味着有多个。比如我们现在单台的eureka端口是7001,假设还有一台服务是7002.那么7001的注册地址应该是7002,7002的注册地址是7001.这样就相互注册了。7001会每30s给7002同步一次心跳,同理7002也会的。所以就相互守望了。因此我们可以用一句话进行概括:互相注册,互相守望。
2、集群Eureka构建步骤
1)建moudle
按照上面构建cloud-eureka-server7001的构建步骤,进行cloud-eureka-server7002的构建
2)改pom
复制7001moudle的pom文件即可
3)修改映射配置文件
当我们有两个应用进行相互注册相互守望时,eureka服务端的实例名称不能重复,因此需要修改映射配置文件,找到C:\Windows\System32\drivers\etc路径下的hosts文件,对其进行修改,增加两个虚拟的域名:
修改完成后刷新host文件,打开cmd命令窗口,进行如下的操作:
出现上面的界面则说明我们的映射配置文件已修改成功了。
4)写yml(依次修改7001和7002的yml文件)
7001:
server:
port: 7001
spring:
application:
name: cloud-eureka-service
eureka:
instance:
# eureka服务端的实例名称
hostname: eureka7001.com
client:
# false表示不向注册中心注册自己
register-with-eureka: false
# false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要检索服务
fetch-registry: false
service-url:
# 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
7002:
server:
port: 7002
spring:
application:
name: cloud-eureka-service2
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
3、将支付服务8001微服务发布到上面2台Eureka集群配置中
修改8001的yml文件,将原来的单机版修改为集群版即可。
#单机版
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4、将订单服务80微服务发布到上面2台Eureka集群配置中
修改80的yml文件,将原来的单机版修改为集群版即可。
#单机版
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
5、支付服务提供者8001集群环境搭建
1)参考cloud-provider-payment8001,新建cloud-provider-payment8002
2)复制pom文件
3)复制yml文件,修改里面的端口号
4)复制主启动类
5)复制业务类
分别修改8001和8002的controller文件,
6)测试
我们可以看到CLOUD-PAYMENT-SERVICE是有两台机器。分别是8001和8002
再来分别访问8001和8002的服务:
我们可以看到把对应服务的端口号返回到页面上了。
再使用消费者order80测试:
我们发现无论我们怎么刷新访问的端口都是8001。但是,我们payment确实启动了两个项目8001和8002啊。那么为什么呢?
查看OderController,我们可以看到访问服务的连接是写死的,既然后面启动了两个服务,我想要既可以访问8001的端口也要访问8002的端口,那么怎么做呢?
6、负载均衡
如果我们修改成服务名称呢?那么服务名称是什么?服务名称就是我们在eureka集群注册的application列表下的名称。
那么我们直接把CLOUD-PAYMENT-SERVICE这个服务名字复制到PAYMENT_URL中可以吗?
重启完成之后,我们重新访问:
重新访问的时候,我们看到提示信息是说:java.net.UnknownHostException: CLOUD-PAYMENT-SERVICE。没有找到这个host异常。
为什么呢?我们知道,这个服务是注册到eureka的服务的别名,而不是真实存在的。如果要想访问到,这里就需要使用到负载均衡了。
怎么修改呢?需要修改RestTemplate的配置类中添加@LoadBalanced注解赋予RestTemplate负载均衡的能力。
修改如下:
在order80项目中,ApplicationContextConfig类里面getRestTemplate方法上面添加@LoadBalance注解即可。如下图:
修改完成之后,再次访问页面,然后刷新页面,我们可以看到端口是8001和8002来回切换的。
7、测试
四、actuator微服务信息完善
1、主机名称:服务名称修改
主机名称:服务名称修改
当前问题:服务注册含有主机名称,要想按照规范的要求,只暴露服务名,不要出现主机名。
分别找到8001和8002的yml文件,添加配置即可:
2、访问信息有ip信息提示
我们可以通过如下的配置,将我们微服务的ip地址进行显示,方便我们进行调试和排错。分别在8001和8002的yml文件中进行添加:
修改完成后效果如下:
五、服务发现Discovery
对于注册eureka里面的微服务,可以通过服务发现来获得该服务的信息,具体的步骤如下:
修改cloud-provider-payment8001的Controller
在8001的主启动上添加注解@EnableDiscoveryClient
六、eureka自我保护
我们暂时将7001和8001模块还原到eureka的单机模式用以eureka自我保护的测试:
在7001的yml文件中进行配置:
在8001的yml文件中进行配置:
在启动7001和8001后,停止8001来模仿故障,就会出现如下的结果:其服务
其服务马上就会被删除了。