Eureka
创建单机版注册中心
创建module (cloud-eureka-server-7001)
改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>cloud2020</artifactId>
<groupId>com.zzp.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server-7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.zzp.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>
Eureka包含两个组件:Eureka Server 和 Eureka Client
Eureka Server 提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面直观看到。
Eureka Client 通过注册中心访问
是一个java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会在Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多次心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移删(默认90秒)。
添加application.yml配置:
server:
port: 7001 # 端口号
spring:
application:
name: cloud-eureka-service # 项目名称
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
allow-redirects: false # 是否向注册中心注册本服务:true为是。注册中心不需要将自己注册进去
fetch-registry: false # false表示自己是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址,多个时用逗号隔开
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动类:加注解@EnableEurekaServer
package com.zzp.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author zzp
* @create 2021-02-12
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
启动后页面访问:http://127.0.0.1:7001/
cloud-provider-payment-8001服务和cloud-consumer-order-80服务
yml文件添加配置
# eureka 配置
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
在cloud-consumer-order-80的yml文件再添加配置项目名称:
spring:
application:
name: cloud-order-service # 项目名称
pom文件添加依赖
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
启动类添加:注解@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
然后启动80和8001两个服务,查看Eureka页面
可以看到:CLOUD-ORDER-SERVICE 和 CLOUD-PAYMENT-SERVICE
请求接口访问:
Eureka集群
为了模拟实际情况,所以修改下hosts文件
C:\Windows\System32\drivers\etc下找到hosts文件添加以下内容
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
修改Eureka7001的yml文件
server:
port: 7001 # 端口号
spring:
application:
name: cloud-eureka-service # 项目名称
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
allow-redirects: false # 是否向注册中心注册本服务:true为是。注册中心不需要将自己注册进去
fetch-registry: false # false表示自己是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址,多个时用逗号隔开
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
创建Eureka7002参看Eureka7001项目
改Eureka7002的application.yml文件:
server:
port: 7002 # 端口号
spring:
application:
name: cloud-eureka-service # 项目名称
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
allow-redirects: false # 是否向注册中心注册本服务:true为是。注册中心不需要将自己注册进去
fetch-registry: false # false表示自己是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
# 集群版
defaultZone: http://eureka7001.com:7001/eureka/
分别启动Eureka7001和Eureka7002
eureka7001指向eureka7002
eureka7002指向eureka7001
把cloud-order-service和cloud-payment-service注册到eureka7001和eureka7002中
修改cloud-order-service和cloud-payment-service的yml配置文件:
# eureka 配置
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
# defaultZone: http://localhost:7001/eureka
#集群
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
把defaultZone的单机改成集群
启动
创建支付者8002(模拟多台微服务)
参看cloud-provider-payment-8001创建
application.yml配置文件 改成端口号 8002
server:
port: 8002 # 端口号
payment-8001和payment-8002的控制层添加端口号输出(servicePort)
package com.zzp.springcloud.controller;
import com.zzp.springcloud.entities.CommonResult;
import com.zzp.springcloud.entities.Payment;
import com.zzp.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author zzp
* @create 2021-02-10
*/
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String servicePort;
@PostMapping(value = "/payment/create")
public CommonResult create(@RequestBody Payment payment){
int count = paymentService.create(payment);
log.info("*******插入结果:{}",count);
if(0 < count ){
return new CommonResult(200,"插入数据库成功,servicePort: " + servicePort,count);
}else {
return new CommonResult(404,"插入数据库失败",null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("*******查询结果:{}",payment);
if(null != payment ){
return new CommonResult(200,"查询成功,servicePort: " + servicePort,payment);
}else {
return new CommonResult(404,"没有对应记录,查询ID: "+id,null);
}
}
}
启动payment服务测试:
在启动Oder80服务
但是80服务是是一直访问8001,由于之前的restTemplate访问地址写死了ip
把地址改成:
public static final String PAYMENT_URL = “http://CLOUD-PAYMENT-SERVICE”;
请求:
请求出错,因为cloud-payment-service有两台服务
设置RestTemplateConfig添加@LoadBalanced(实现Ribbon负载均衡)
package com.zzp.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* @author zzp
* @create 2021-02-12
*/
@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
再访问:
actuator微服务信息完善
这里会显示自己的主机名称
服务名称修改:
在payment8001和payment8002的application.yml
添加:
instance:
info-id: payment8001 # 服务名称设置
# eureka 配置
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
# defaultZone: http://localhost:7001/eureka
#集群
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001 # 服务名称设置
payment8001服务配置写info-id: payment8001
payment8002服务配置写info-id: payment8002
Oder80服务的application.yml添加
instance:
instance-id: order80 # 服务名称设置
访问信息有ip信息提示:
在application.yml的#eureka 配置 添加:
instance:
instance-id: payment8002 # 服务名称设置
prefer-ip-address: true # 访问路径可以显示ip地址
instance下级添加
prefer-ip-address: true # 访问路径可以显示ip地址
服务发现Discovery
对于注册进Eureka里面的微服务,可以通过服务发现获得改服务的信息
修改cloud-provider-payment-8001的Controller
package com.zzp.springcloud.controller;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import com.zzp.springcloud.entities.CommonResult;
import com.zzp.springcloud.entities.Payment;
import com.zzp.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* @author zzp
* @create 2021-02-10
*/
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String servicePort;
@Resource
private DiscoveryClient discoveryClient;
@PostMapping(value = "/payment/create")
public CommonResult create(@RequestBody Payment payment){
int count = paymentService.create(payment);
log.info("*******插入结果:{}",count);
if(0 < count ){
return new CommonResult(200,"插入数据库成功,servicePort: " + servicePort,count);
}else {
return new CommonResult(404,"插入数据库失败",null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("*******查询结果:{}",payment);
if(null != payment ){
return new CommonResult(200,"查询成功,servicePort: " + servicePort,payment);
}else {
return new CommonResult(404,"没有对应记录,查询ID: "+id,null);
}
}
@GetMapping(value = "/payment/discovery")
public Object discovery(){
List<String> services = discoveryClient.getServices();
for(String element : services){
log.info(">>>>>>>(element)服务名称: {}",element);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances){
log.info("InstanceId: " + instance.getInstanceId() + "\t" + "Host: " + instance.getHost() + "\t"
+ "Port: "+ instance.getPort() + "Uri: "+ instance.getUri());
}
return this.discoveryClient;
}
}
在PaymentMain8001启动添加:@EnableDiscoveryClient
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
访问:
日记输出:
Eureka自我保护
概述
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入保护模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
修改7001 yml文件
出厂默认,自我保护机制是开启的
eureka.server.enable-self-preservation = true
eureka下级配置添加
server:
enable-self-preservation: false # 禁用自我保护模式
eviction-interval-timer-in-ms: 2000 # 2秒
Eureka自我保护机制关闭
8001的yml配置添加:
eureka.instance下级配置添加:
# eureka客户端想服务端发动心跳的时间间隔,单位为秒(默认是30秒)。开发的时候可以设置小一些,以保证服务关闭后注册中心及时剔除服务
lease-renewal-interval-in-seconds: 1
# eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒)。开发时候设置小一些
lease-expiration-duration-in-seconds: 2
启动7001和8001(配置单机)
手动停掉8001服务,Eureka马上页面没有服务了
注: Eureka停更了
访问:https://github.com/Netflix/eureka/wiki