Eureka注册中心
Spring Cloud 2020.0.0版本开始,已移除大部分相关的Netflix OSS组件,Eureka没有被移除,feign使用openfeign封装
- Spring Cloud Netflix Zuul - Zuul是一个API网关服务,Spring Cloud推荐使用Spring Cloud Gateway作为替代。
- Spring Cloud Netflix Ribbon - Ribbon是一个客户端负载均衡器,Spring Cloud推荐使用Spring Cloud LoadBalancer作为替代。
- Spring Cloud Netflix Hystrix - Hystrix是一个熔断器和延迟容忍库,Spring Cloud推荐使用Resilience4j作为替代。
- Spring Cloud Netflix Archaius - Archaius是一个配置管理库,Spring Cloud推荐使用Spring Cloud Config作为替代。
Eureka作用
- 服务注册:每个微服务启动时,会将自己的信息(如服务名称、IP地址、端口号等)注册到Eureka服务器上。通过Eureka客户端维持心跳连接,Eureka服务器就知道有哪些服务在运行。
- 服务发现:当一个微服务需要调用另一个微服务时,它可以向Eureka服务器查询,获取目标服务的位置信息(如IP地址和端口号),实现本地RPC调用
- 负载均衡:Eureka可以与负载均衡器(如Ribbon)结合使用,帮助分配请求到多个实例上,从而实现负载均衡,提升系统的性能和可靠性。
- 故障转移:如果某个服务实例宕机,Eureka会自动将其从注册列表中移除,其他服务就不会再尝试访问这个宕机的实例,从而实现故障转移。
Eureka核心
结构组成
Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息。
Eureka Client通过注册中心进行访问
一个Java客户端,内置一个使用轮询负载算法的负载均衡器。在应用启动后,会将当前节点信息注册到Eureka Server中,然后会向Eureka Server发送心跳(默认周期30秒)。如果Eureka Server在多个心跳周期内没有收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移出(默认90秒)
自我保护机制
当Eureka Server在一定时间内(默认是15分钟)检测到的心跳丢失比例超过了阈值(默认是85%)时,Eureka Server会认为可能是网络分区或其他原因导致的临时故障,而不是所有实例都宕机,将会进入自我保护状态(如下图),不会注销任何微服务。
# 在自我保护期间,节点宕机也不会被清除,此时服务消费者就将消费一个无效的服务,可以将其关闭,使用服务熔断、重试、降级等等替代
eureka:
server:
enable-self-preservation: false # 关闭自我保护机制
AP策略
Eureka正是采用AP策略,即保证服务的可用性以及分区容错性,降低了服务的一致性;

Eureka Server 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务,而 Eureka Client 在向某个 Eureka 注册时,如果发现连接失败,则会自动切换至其它节点。只要有一台 Eureka Server 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。
Eureka节点检测配置
# 以下配置在Eureka的服务端,服务节点忽然下线,Eureka并不会立刻知道,在一定的时间间隔内,可能会将部分不可以的服务节点传递给负载均衡组件,调小下方时间可以一定程度上改善这个问题(但是必然会对服务器造成压力)
eureka:
instance:
# eureka客户端和eureka服务端进行服务续约的时间间隔,默认是30s
lease-renewal-interval-in-seconds: 30
# eureka服务端从可用服务列表剔除不可用服务的时间间隔,默认是90s,即:3个心跳检测间隔
lease-expiration-duration-in-seconds: 90Eureka和Dubbo区别:
- Dubbo是个微服务整体架构的框架,提供的功能包括服务注册发现,远程调用,监控等等。对标的项目大概是Feign+Ribbon+Hystrix。Dubbo的服务发现模块基于zookeeper实现,对应Eureka。
- Eureka。是spring cloud之下一个专门负责微服务服务注册和发现的组件,Eureka就是为了服务发现而设计的。是Dubbo对应的概念的一个部分。

Eureka单节点构建
子工程:serve端
pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>yml文件
server:
port: 7001
eureka:
instance:
hostname: localhost #Eureka 服务实例的主机名,这里设置为 localhost,表示服务运行在本地。
client:
#当前应用是否将自己注册到Eureka服务注册中心
register-with-eureka: false
#当前应用是否从Eureka服务注册中心获取服务列表
fetchRegistry: false
service-url:
defaultZone: http://localhost:7001/eureka # Eureka 服务注册中心的 URL主启动
//添加上注释
@SpringBootApplication
//SPringBoot低版本必须要添加上该注解才可以启用Eureka,其会导入一些自动配置的对象到IOC容器中。高版本不需要
@EnableEurekaServer
public class EurekaMain {
public static void main(String[] args) {
SpringApplication.run(EurekaMain.class, args);
}
}访问Eureka服务端页面:http://localhost:7001

子工程:client
如果一个服务可以部署在多台机器上,使用相同的application name注册到Eureka,通过ribbon等工具即可负载均衡调用。
pom文件
<!--服务消费者和提供者pom文件中引入Eureka的client包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> yml文件
#eureka.instance下的hostname即主机名不配置的话默认为电脑名
#instanceID不配置的话默认值为主机名+服务名+端口
#prefer-ip-address表示猜测主机名(hostname)为ip形式,不配置的话默认为false
spring:
application:
name: item-service # 微服务名称
eureka:
client:
register-with-eureka: true #这个配置项决定是否将自己注册到 Eureka 服务注册中心
fetchRegistry: true #这个配置项决定是否将自己注册到 Eureka 服务注册中心
service-url:
defaultZone: http://localhost:7001/eureka #Eureka服务注册中心的URL
启动类
//添加注解
@EnableEurekaClient
@SpringBootApplication
public class EurekaMain {
public static void main(String[] args) {
SpringApplication.run(EurekaMain.class, args);
}
}注册成功

Eureka集群构建

Server端
并不是Eureka集群中每一个节点都有所有的注册信息,而是每个节点都有部分,如果某个Eureka集群节点宕机了,其上面的注册信息就会转到其他节点上。

#将Server1注册到Server2,Server2注册到Server1
server:
port: 10101
spring:
application:
name: eureka01-server #微服名称
eureka:
client:
register-with-eureka: true # 是否将该服务注册到eureka服务端
fetch-registry: true # 是否从eureka服务端获取其他服务实例
service-url: # eureka的注册地址
defaultZone: http://${spring.cloud.client.ip-address}:10102/eureka # 暴露的注册地址
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 使用ip地址注册
instance-id: 127.0.0.1:10101 # 实例id(默认的实例名是微服务名称)
server:
port: 10102
spring:
application:
name: eureka02-server #微服名称
eureka:
client:
register-with-eureka: true # 是否将该服务注册到eureka服务端
fetch-registry: true # 是否从eureka服务端获取其他服务实例
service-url: # eureka的注册地址
defaultZone: http://${spring.cloud.client.ip-address}:10101/eureka
instance:
hostname: localhost
prefer-ip-address: true
instance-id: 127.0.0.1:10102Client端
server:
port: 9000
spring:
application:
name: item-service # 微服务名称
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10101/eureka,http://127.0.0.1:10102/eureka # 注册到Eureka
instance:
prefer-ip-address: true # 使用ip地址注册服务(默认情况下是以主机注册)
instance-id: ${spring.cloud.client.ip-address}:${server.port} # 实例ididea模拟步骤
1、使用Server1配置启动SpringBoot,然后注释Server1配置,修改为Server2配置
2、编辑当前SpringBoot项目配置,将其复制一份,再次运行,即可得到配置文件不同的两个运行实例

也可以开启VM选项后,手动添加参数配置后运行

Consul
spring整合文档:https://docs.spring.io/spring-cloud-consul/docs/current/reference/html/
安装运行
下载Consul后,将其解压到合适位置,在控制面板中进入Consul目录,执行consul agent -dev启动Consul。
访问服务:http://localhost:8500/
作为注册中心
服务提供者
pom
<!--SpringCloud consul discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--consul用于健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>yml
server:
port: 8001
spring:
application:
name: cloud-payment-service
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}启动类
@SpringBootApplication
//下方注解可以省略
@EnableDiscoveryClient
public class Main8001
{
public static void main(String[] args)
{
SpringApplication.run(Main8001.class,args);
}
}controller
@RestController
public class OpenFeignController {
@Value("${server.port}")
private String port;
@GetMapping("/openfeign")
public String openFeign() {
return "openFeign:"+port;
}
}服务消费者
pom
<!--SpringCloud consul discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>yml
server:
port: 80
spring:
application:
name: cloud-consumer-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
#优先使用服务ip进行注册
prefer-ip-address: true
service-name: ${spring.application.name}启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}controller
@RestController
public class OpenFeignController {
@Autowired
private OpenFeignService openFeignService;
@GetMapping("/openfeignTest")
public String openFeign() {
return openFeignService.openFeign();
}
}service
@Service
//注册在Eureka中的服务的名称,字母数字及‘-’组合,不能有下划线,不区分大小写
@FeignClient("cloud-payment-service")
public interface OpenFeignService {
@GetMapping("/openfeign")
String openFeign();
}作为配置中心
pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--引入健康检查的依赖,用于健康检查监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}controller
@RestController
//用于动态刷新配置,放在读取配置,需要动态刷新的类上
@RefreshScope
public class OpenFeignController {
@Value("${server.port}")
private String port;
//从consul中动态读取配置
@Value("${consul.test}")
private String consulTest;
@GetMapping("/openfeign")
public String openFeign() {
return "openFeign:"+port+",consulTest:"+consulTest;
}
}bootstrap.yml
正常项目启动流程

使用consul/nacos等配置中心流程

如果把 consul/nacos 地址放在 application.yml 中,显然是不合适的,Nacos 就无法根据地址去获取配置了。因此,nacos 地址必须放在优先级最高的 bootstrap.yml 文件。

spring:
application:
name: cloud-payment-service
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
config:
profile-separator: '-' # default value is ",",we update '-'
format: YAMLconsul服务端配置
创建config文件夹(以/结尾表示文件夹),然后在config下创建服务名称文件夹,最后创建data文件编写配置

常见配置
spring:
application:
name: consul-config # 应用名称
cloud:
consul:
host: 127.0.0.1 # Consul服务器地址
port: 8500 # Consul服务器端口
discovery:
instance-id: ${spring.application.name} # 服务实例ID
service-name: consul-config # 服务名称
enabled: true # 启用服务发现
register: true # 启用服务注册
deregister: true # 服务停止时取消注册
prefer-ip-address: true # 在注册时使用Consul IP,而不是hostname
health-check-url: http://localhost:8081/actuator/health # 健康检查URL
health-check-interval: 10s # 健康检查的频率
health-check-critical-timeout: 5s # 健康检查失败多长时间后,取消注册
config:
enabled: true # 启用配置中心
format: properties # Consul上面文件的格式
data-key: data # Consul上面的KEY值(或者说文件的名字)
prefix: config # 设置配置值的基本文件夹
fail-fast: false # 如果没有发现配置,是否抛出异常
defaultContext: consul-config # 设置所有应用程序使用的文件夹名称
profileSeparator: ',' # 设置用于使用配置文件在属性源中分隔配置文件名称的分隔符的值Nacos
概述
等同于注册中心+配置中心的组合,即Nacos = Eureka(服务注册中心)+Config(服务配置中心)+Bus。
进入bin目录后通过命令行启动Nacos(2.x版本在distribution\bin),访问http://localhost:8848/nacos网页,账号/密码均使用nacos登录即可
- startup.cmd:集群启动,默认的启动方式
- startup.cmd -m standalone:单机启动
Nacos支持AP和CP模式的切换:
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
Nacos作为注册中心
服务提供者
pom文件
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>yml文件
server:
port: 9001
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址主启动类
//Nacos做了一个优化,可以不用这个注解@EnableDiscoveryClient
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class,args);
}
}controller
@RestController
public class OpenFeignController {
@Value("${server.port}")
private String port;
@GetMapping("/openfeign")
public String openFeign() {
System.out.println("openFeign:"+port);
return "openFeign:"+port;
}
}服务消费者
pom文件
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 添加 openfeign 框架依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡,Nacos 2021移除了Ribbon作为负载均衡,即2021和以后的版本需要手动引入LoadBalancer实现负载均衡,2021前直接使用其内部的Ribbon实现负载均衡即可 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>yml文件
server:
port: 8000
spring:
application:
name: nacos-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者【可选】,注意:nacos-payment-provider含有IP和端口)
service-url:
nacos-user-service: http://nacos-payment-provider主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83{
public static void main(String[] args){
SpringApplication.run(OrderNacosMain83.class,args);
}
}openfeign调用
@Service
@FeignClient(value = "nacos-provider")
public interface OpenFeignService {
@GetMapping("/openfeign")
String openFeign();
}Controller层
@RestController
public class OpenFeignController {
@Autowired
private OpenFeignService openFeignService;
@GetMapping("/openfeignTest")
public String openFeign() {
return openFeignService.openFeign();
}
}Nacos作为配置中心
工程创建
pom文件
<!--允许在应用程序的主配置文件加载之前加载一些特定的配置。这对于从外部配置中心(如 Nacos、Consul等)加载配置特别有用。-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--nacos-config-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>yml文件
Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动。
Data Id结构:#
{spring.profile.active}.${file-extension} - prefix:默认值为spring.application.name,也可以通过spring.cloud.nacos.config.prefix配置
- spring.profile.active:当前环境,如果其为空,结构将变为
{file-extension} - file-extension:配置文件扩展名,只支持properties和yaml(yml)

必须使用bootstrap.yml命名,springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application

#Data Id:nacos-config-client-dev.yaml
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置(yml和yaml都可以)
#application.yml
spring:
profiles:
active: dev #表示开发环境主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377{
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientMain3377.class, args);
}
}业务类
@RestController
//通过SpringCould原生注解@RefreshScope实现配置自动更新,放在读取配置,需要动态刷新的类上
@RefreshScope
public class ConfigClientController{
//需要现在Nacos中创建Date id为:nacos-config-client-dev.yaml的配置
//在对应配置文件中添加配置config.info 在可以读取到配置
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}Nacos配置
spring:
application:
name: nacos-demo
cloud:
nacos:
config:
# 配置nacos的配置中心地址
server-addr: 127.0.0.1:8848
# 加载多个配置
extension-configs:
# 使用数组格式 配置每个data-id 使用refresh声明是否实时刷新
- data-id: redis.properties
refresh: true
- data-id: jdbc.properties
refresh: true
# 2.4.0版本支持无账户登录 所以不需要配置用户名和密码
#username: nacos
#password: nacos选择对应Data Id和分组可以查看历史配置,以及进行回滚操作

分类概述
默认情况:Namespace=public,Group=DEFAULT_GROUP,默认Cluster是DEFAULT
Namespace:区分环境,如开发、测试、生产环境,不同的 Namespace之间是隔离的。
Group:将不同的微服务划分到同一个分组,一般以项目划分。
DataID:对应某一个微服务集群,该集群可以存在多个服务节点。

1) DataID方案
指定spring.profiles.active和DataID来使不同环境下读取不同的配置,默认空间+默认分组+新建dev和test两个DataID
Data Id结构:#
{spring.profile.active}.${file-extension}:不同环境,spring.profile.active不一致,就可以读取到不同的配置 新建dev配置DataID

- 新建test配置DataID

2) Group方案
通过Group实现环境区分,在config下增加一条group的配置即可。可配置为DEV_GROUP或TEST_GROUP



3) Namespace方案
配置中填写:
# nacos配置
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
config:
server-addr: localhost:8848 #Nacos作为配置中心地址
file-extension: yaml #指定yaml格式的配置
group: DEV_GROUP
namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4
spring:
profiles:
active: dev # 表示开发环境
#active: test # 表示测试环境
#active: info命名空间中可以创建和管理命名空间

配置列表可以切换命名空间查看配置,也可以克隆当前配置到另一个空间

Nacos集群及持久化
- 默认Nacos使用嵌入式数据库实现数据的存储(Nacos默认自带数据库derby)。所以,如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储。
- nacos的集群数据的一致性是通过raft算法来实现的,所以至少需要三台机器
Windows
nacos-server-1.4.2\nacos\conf目录下找到sql脚本,执行脚本nacos-mysql.sql在MySQL中创建数据库。
application.properties文件内添加
propertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&serverTimezone=UTC&rewriteBatchedStatements=true db.user=root db.password=fujianz123

注意:Nacos持久化之后,使用时一定要开启MySQL数据库,否则会报错
Linux
创建/opt/nacoscluster目录,解压3个节点(Nacos需要三个及以上节点才能搭建集群)
Linux服务器上mysql数据库配置:找到nacos_mysql.sql文件,创建数据库并导入表结构
三个节点conf/application.properties配置
修改每一个节点下server.port,分别设置为:8848,8849,8850,并添加以下配置
propertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config? characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=root db.password=fujianz123
三个节点/conf下配置cluster.conf
192.168.137.150:8848 192.168.137.150:8849 192.168.137.150:8850启动三个节点前,修改bin下startup.sh文件内存大小,否则,内存可能不够用。
修改nginx的配置文件:vim /usr/local/nginx/conf/nginx.conf
upstream nacoscluster{ server localhost:8848; server localhost:8849; server localhost:8850; } server{ listen 1111; server_name localhost; location / { proxy_pass http://nacoscluster; } }