Eureka服务注册中心 3/9
- 1、服务注册与发现
- 1.1 什么是服务治理:
- 1.2 什么是服务注册与发现:
- 1.3 Eureka服务注册与发现
- 2、单机版eureka
- 2.1 创建module
- 2.2改pom依赖
- 2.3写yml配置文件:
- 2.4主启动类
- 2.5 修改服务提供者 cloud-provider-payment8001 模块,
- 2.6 修改消费者 cloud-customer-order80 模块
- 2.7 启动三个服务:
- 3、集群版eureka
- 3.1 集群原理
- 3.2 构建Eureka集群
- 3.3 将Cloud-consumer-order80,Cloud-provider-payment8001模块注册到eureka集群中
- 4、将Cloud-provider-payment模块也配置为集群模式
- 4.1 创建新模块Cloud-provider-payment8002
- 4.2 pom文件,复制8001的
- 4.3 配置文件复制8001的
- 4.4 主启动类,复制8001的
- 4.5 mapper,service,controller都复制一份
- 4.6 RestTemplate开启负载均衡注解
- 4.7 修改服务主机名和ip在eureka的web上显示
- 5、eureka服务发现
- 5.1 首先添加一个注解,在controller中
- 5.2 在主启动类上添加一个注解
- 6、Eureka自我保护
- 6.1 在 Eureka Server 的模块中的 yml 文件进行配置:
- 6.2 服务提供者配置
- 6.3 eureka配置项
1、服务注册与发现
当服务很多时,单靠代码手动管理是很麻烦的,需要一个公共组件,统一管理多服务,包括服务是否正常运行等
上面只有两个微服务,通过 RestTemplate ,是可以相互调用的,但是当微服务项目的数量增大,就需要服务注册中心。目前没有学习服务调用相关技术,使用 SpringCloud 自带的 RestTemplate 来实现RPC。
1.1 什么是服务治理:
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
1.2 什么是服务注册与发现:
Eureka采用了CS的设计结构,Eureka Server服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。这点和zookeeper很相似
在服务注册与发现中,有一个注册中心。当服务器启动时候,会把当前自己服务器的信息 比如服务地址 通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为便用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
1.3 Eureka服务注册与发现
Eureka 官方停更不停用,以后可能用的越来越少。
Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件,以实现中间层服务器的负载平衡和故障转移。
Eureka 分为 Eureka Server 和 Eureka Client及服务端和客户端。Eureka Server为注册中心,是服务端,而服务提供者和消费者即为客户端,消费者也可以是服务者,服务者也可以是消费者。同时Eureka Server在启动时默认会注册自己,成为一个服务,所以Eureka Server也是一个客户端,这是搭建Eureka集群的基础。
==Eureka Client:==一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)。通过注册中心进行访问。是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(roundrobin)负载算氵去的负载均衡器
在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
==Eureka Server:==提供服务注册服务,各个微服务节,通过配置启动后,会在Eureka Serverc中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点信息,服务节点的信息可以在界面中直观看到。
服务在Eureka上注册,然后每隔30秒发送心跳来更新它们的租约。如果客户端不能多次续订租约,那么它将在大约90秒内从服务器注册表中剔除。注册信息和更新被复制到集群中的所有eureka节点。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)来定位它们的服务(可能在任何区域)并进行远程调用。
服务提供者向注册中心注册服务,并每隔30秒发送一次心跳,就如同人还活着存在的信号一样,如果Eureka在90秒后还未收到服务提供者发来的心跳时,那么它就会认定该服务已经死亡就会注销这个服务。这里注销并不是立即注销,而是会在60秒以后对在这个之间段内“死亡”的服务集中注销,如果立即注销,势必会对Eureka造成极大的负担。这些时间参数都可以人为配置。
Eureka还有自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,所以不会再接收心跳,也不会删除服务。
客户端消费者会向注册中心拉取服务列表,因为一个服务器的承载量是有限的,所以同一个服务会部署在多个服务器上,每个服务器上的服务都会去注册中心注册服务,他们会有相同的服务名称但有不同的实例id,所以拉取的是服务列表。我们最终通过负载均衡来获取一个服务,这样可以均衡各个服务器上的服务。
2、单机版eureka
-
消费者端口80,提供者端口8001。
-
Eureka端口7001
2.1 创建module
Cloud_eureka_server_7001
2.2改pom依赖
eureka版本说明:
<!--新版本2020.02-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--旧版本2018-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
pom文件:
在这里插入代码片
2.3写yml配置文件:
server:
port: 7001
eureka:
instance:
hostname: localhost # eureka 服务端的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 设置与 Eureka Server 交互的地址,查询服务 和 注册服务都依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2.4主启动类
@EnableEurekaServer
最后写主启动类,如果启动报错,说没有配置 DataSource ,就在 主启动类的注解加上 这样的配置:
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaServerMain7001 {
public static void main(String[] args){
SpringApplication.run(EurekaServerMain7001.class, args);
log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");
}
}
启动测试,访问 7001 端口
2.5 修改服务提供者 cloud-provider-payment8001 模块,
- 在 pom 文件的基础上引入 eureka 的client包,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>springcloud2023</artifactId>
<groupId>com.tigerhhzz.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Cloud-provider-payment8001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 服务注册中心的客户端端 eureka-client -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.tigerhhzz.springcloud</groupId>
<artifactId>Cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<!--这个和web要写到一块-->
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import java.io.Console;
/**
* @author Administrator
*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8001.class, args);
log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");
}
}
- yml 文件添加关于 Eureka 的配置:
server:
port: 8001
spring:
application:
name: Cloud-provider-payment8001
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
defaultZone: http://localhost:7001/eureka/
2.6 修改消费者 cloud-customer-order80 模块
- 在 pom 文件的基础上引入 eureka 的client包,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>springcloud2023</artifactId>
<groupId>com.tigerhhzz.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Cloud-consumer-order80</artifactId>
<dependencies>
<!-- 服务注册中心的客户端端 eureka-client -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.tigerhhzz.springcloud</groupId>
<artifactId>Cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80{
public static void main(String[] args){
SpringApplication.run(OrderMain80.class,args);
log.info("OrderMain80启动成功~~~~~~~~~~~~~~~~~~~");
}
}
- yml 文件添加关于 Eureka 的配置:
server:
port: 80
spring:
application:
name: Cloud-consumer-order80
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
2.7 启动三个服务:
3、集群版eureka
3.1 集群原理
- 就是pay模块启动时,注册自己,并且自身信息也放入eureka
- order模块,首先也注册自己,放入信息,当要调用pay时,先从eureka拿到pay的调用地址
- 通过HttpClient调用 ,并且还会缓存一份到本地,每30秒更新一次
问题:微服务RPC远程服务调用最核心的是什么:
高可用,试想你的注册中心只有一个。onlyone,它出故障了那就呵呵了,会导致整个为服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错
Eureka 集群的原理:
== 相互注册,互相守望。== 每台Eureka服务器都有集群里其他Eureka服务器地址的信息
3.2 构建Eureka集群
在写配置文件前,修改一下主机的hosts文件
模拟多个 为了不用输出C:\Windows\System32\drivers\etc\hosts 添加如下:
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
-
创建 Cloud-eureka-server7002模块
这也就是第二个 Eureka 服务注册中心,pom 文件和 主启动类,与第一个Cloud-eureka-server7002一致。pom文件: 粘贴7001的即可
<?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>springcloud2023</artifactId>
<groupId>com.tigerhhzz.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Cloud-eureka-server7002</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.tigerhhzz.springcloud</groupId>
<artifactId>Cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
配置文件:
- 修改7001项目的application.yml配置文件
首先修改之前的7001的eureka项目,因为多个eureka需要互相注册
7001项目的application.yml配置文件
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka 服务器的实例地址 # eureka 服务端的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
defaultZone: http://eureka7002.com:7002/eureka/
-
修改7002项目的application.yml配置文件
7002也是一样的,只不过端口和地址改一下
7002项目的application.yml配置文件
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka 服务端的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
defaultZone: http://eureka7001.com:7001/eureka/
eureka.instance.hostname 才是启动以后 本 Server 的注册地址,而 service-url 是 map 类型,只要保证 key:value 格式就行,它代表 本Server 指向了那些 其它Server 。利用这个,就可以实现Eureka Server 相互之间的注册,从而实现集群的搭建。
- 主启动类:
复制7001的即可
7001主启动类:
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaServerMain7001 {
public static void main(String[] args){
SpringApplication.run(EurekaServerMain7001.class, args);
log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");
}
}
7002主启动类:
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaServerMain7002 {
public static void main(String[] args){
SpringApplication.run(EurekaServerMain7002.class, args);
log.info("EurekaServerMain7002启动成功~~~~~~~~~~~~~~~~~~~");
}
}
- 然后启动7001,7002即可
3.3 将Cloud-consumer-order80,Cloud-provider-payment8001模块注册到eureka集群中
- 只需要修改Cloud-consumer-order80,Cloud-provider-payment8001模块的配置文件即可:
Cloud-consumer-order80配置文件
server:
port: 80
spring:
application:
name: Cloud-consumer-order80
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
,Cloud-provider-payment8001模块配置文件
server:
port: 8001
spring:
application:
name: Cloud-provider-payment8001
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
- 两个模块都修改上面的都一样即可
然后启动两个模块
要先启动7001,7002,然后是pay模块8001,然后是order(80)
4、将Cloud-provider-payment模块也配置为集群模式
4.1 创建新模块Cloud-provider-payment8002
4.2 pom文件,复制8001的
Cloud-provider-payment8002模块的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>springcloud2023</artifactId>
<groupId>com.tigerhhzz.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Cloud-provider-payment8002</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 服务注册中心的客户端端 eureka-client -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.tigerhhzz.springcloud</groupId>
<artifactId>Cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<!--这个和web要写到一块-->
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
4.3 配置文件复制8001的
端口修改一下,改为8002
Cloud-provider-payment8001模块的配置文件
server:
port: 8001
spring:
application:
# name: Cloud-provider-payment8001
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
Cloud-provider-payment8002模块的配置文件
server:
port: 8002
spring:
application:
# name: Cloud-provider-payment8002
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
服务名称不用改,用一样的
4.4 主启动类,复制8001的
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author Administrator
*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8002 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8002.class, args);
log.info("PaymentMain8002启动成功~~~~~~~~~~~~~~~~~~~");
}
}
4.5 mapper,service,controller都复制一份
然后就启动服务即可
此时访问order模块,发现并没有负载均衡到两个pay,模块中,而是只访问8001
虽然我们是使用RestTemplate访问的微服务,但是也可以负载均衡的
4.6 RestTemplate开启负载均衡注解
注意这样还不可以,需要让RestTemplate开启负载均衡注解,还可以指定负载均衡算法,默认轮询
修改Cloud-consumer-order80模块中的config包下面的ApplicationContextConfig类:
package com.tigerhhzz.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author tigerhhzz
* @date 2023/4/8 22:52
*/
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
/*
RestTemplate提供了多种便捷访问远程http服务的方法,
是一种简单便捷的访问restful服务模板类,是spring提供的用于rest服务的客户端模板工具集
*/
}
}
4.7 修改服务主机名和ip在eureka的web上显示
actuator让Eureka显示ip
为了在微服务Eureka控制台能看到我们的某个具体服务是在哪台服务器上部署的,我们需要配置一些内容。
修改 提供者在Eureka 注册中心显示的 主机名:即修改eureka:instance:instance-id:和eureka:instance:prefer-ip-address:
修改Cloud-provider-payment8001模块的配置文件:
server:
port: 8001
spring:
application:
# name: Cloud-provider-payment8001
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 访问路径可以显示ip地址
修改Cloud-provider-payment8002模块的配置文件:
server:
port: 8002
spring:
application:
# name: Cloud-provider-payment8002
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
instance: #重点,和client平行
instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 访问路径可以显示ip地址
5、eureka服务发现
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。(即我们前面可视化页面的信息)
5.1 首先添加一个注解,在controller中
package com.tigerhhzz.springcloud.controller;
import com.tigerhhzz.springcloud.entities.CommonResult;
import com.tigerhhzz.springcloud.entities.Payment;
import com.tigerhhzz.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController //必须是这个注解,因为是模拟前后端分离的restful风格的请求,要求每个方法返回 json
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
//服务发现
@Resource
private DiscoveryClient discoveryClient;
@Value("${server.port}")
private String serverPort;
@PostMapping(value = "/payment/create")
// 注意这里的 @RequestBody 是必须要写的,虽然 MVC可以自动封装参数成为对象,
// 但是当消费者项目调用,它传参是 payment 整个实例对象传过来的, 即Json数据,因此需要写这个注解
//
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("****插入结果:" + result);
if(result > 0){
return new CommonResult(200, "插入数据库成功", result);
}
return new CommonResult(400, "插入数据库失败", null);
}
@GetMapping(value = "/payment/{id}")
public CommonResult getPaymentById(@PathVariable("id")Long id){
Payment result = paymentService.getPaymentById(id);
log.info("****查询结果:" + result);
if(result != null){
return new CommonResult(200, "查询成功", result);
}
return new CommonResult(400, "没有对应id的记录", null);
}
@GetMapping("queryAllByLimit")
public CommonResult<List<Payment>> queryAllByLimit(@RequestParam(defaultValue = "0") int offset,
@RequestParam(defaultValue = "10") int limit) {
List<Payment> payment = this.paymentService.queryAllByLimit(offset, limit);
return new CommonResult<>(200, "select success, serverPort:" + serverPort, payment);
}
@GetMapping("/customer/discovery")
public Object discovery(){
//获得服务清单列表
List<String> services = discoveryClient.getServices();
for(String service: services){
log.info("*****service: " + service);
}
// 根据具体服务进一步获得该微服务的信息
List<ServiceInstance> instances = discoveryClient.getInstances("cloud-provider-service");
for(ServiceInstance serviceInstance:instances){
log.info(serviceInstance.getServiceId() + "\t" + serviceInstance.getHost()
+ "\t" + serviceInstance.getPort() + "\t" + serviceInstance.getUri());
}
return this.discoveryClient;
}
}
5.2 在主启动类上添加一个注解
- 在主启动类上添加注解:@EnableDiscoveryClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
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;
import java.io.Console;
/**
* @author Administrator
*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8001.class, args);
log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");
}
}
打印输出:
6、Eureka自我保护
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
禁止自我保护:(如果想)
6.1 在 Eureka Server 的模块中的 yml 文件进行配置:
Cloud-eureka-server7001配置文件:
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka 服务器的实例地址 # eureka 服务端的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
defaultZone: http://eureka7002.com:7002/eureka/
server: # 与client平行
# 关闭自我保护机制,保证不可用该服务被及时剔除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
Cloud-eureka-server7002配置文件:
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka 服务端的实例名称
client:
# false 代表不向服务注册中心注册自己,因为它本身就是服务中心
register-with-eureka: false
# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
defaultZone: http://eureka7001.com:7001/eureka/
server: # 与client平行
# 关闭自我保护机制,保证不可用该服务被及时剔除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
6.2 服务提供者配置
修改 Eureka Client —Cloud-provider-payment8001模块的 心跳间隔时间:
server:
port: 8001
spring:
application:
# name: Cloud-provider-payment8001
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 访问路径可以显示ip地址
# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
least-renewal-interval-in-seconds: 1
# Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
least-expiration-duration-in-seconds: 2
修改 Eureka Client —Cloud-provider-payment8002模块的 心跳间隔时间:
server:
port: 8002
spring:
application:
# name: Cloud-provider-payment8002
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.tigerhhzz.springcloud.entities # 所有Entity 别名类所在包
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
instance: #重点,和client平行
instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 访问路径可以显示ip地址
# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
least-renewal-interval-in-seconds: 1
# Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
least-expiration-duration-in-seconds: 2
6.3 eureka配置项
在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。
面是服务续约的两个重要属性:
(1)eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。
默认为90秒
如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
该值至少应该大于leaseRenewalIntervalInSeconds
(2)eureka.instance.lease-renewal-interval-in-seconds
-
leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
默认30秒 -
eureka.client.registry-fetch-interval-seconds :表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
-
eureka.server.enable-self-preservation
是否开启自我保护模式,默认为true。
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。
Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
eureka.server.eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒
Eureka停更说明:2.0后停更了。