服务注册与发现---Eureka


Eureka是美国Netflix公司出品的服务注册与发现组件,Spring Cloud集成了该组件,然而时代发展,技术革新,Eureka已经停止更新了,但部分老的Spring Cloud的服务注册与发现组件还是用的Eureka。
学学了解了解,也有裨益,毕竟思想没有变化。

Eureka停更说明

1. Eureka系统架构

在这里插入图片描述
Eureka采用了CS的设计架构,Eureka Server 作为服务的注册功能的服务器,它是服务注册中心。而系统的其他服务,使用Eureka的客户端连接到Eureka Server 并维持心跳链接。这样系统的维护人员可以通过Eureka Server来监控系统中各个微服务是否正常运行。
服务注册与发现中,有一个注册中心(Eureka Server)。当服务器启动的时候,会把当前自己的服务器的信息,例如服务IP地址端口等以别名的方式注册到注册中心上(Eureka Server)。另一方服务以别名的方式去注册中心上获取到的实际通信地址(IP+Port),然后在实现本地的远程调用,调用方式可以是Restful风格的接口(例如Spring boot 的 Controller)或者 RPC(例如Alibaba 的 Dubbo)。
核心设计思想是使用服务中心管理每个服务之间的依赖关系(服务治理概念),这样可以在部署时方便的扩容或迁移服务,而不用去维护服务之间的依赖关系,说的直白一点就是,服务部署的IP和端口发生变化,注册中心的数据同时发生变化(服务启动的时候会向中心自动注册),服务的消费者,可以从注册中心通过约定的别名(一般是服务名)获取变更后服务的IP和端口,然后去调用这个服务。

Eureka包含两个组件:
Eureka Server提供服务来注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有的可用节点的信息,服务节点的信息可以在界面中直观看到。

Eureka Client通过注册中心进行访问
是一个java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期30秒)。如果Eureka Server在多个心跳周期没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)

2. Eureka编码举例

2.1 先创建Eureka Server

创建一个Spring boot应用,导入一下依赖

        <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>

application.yml:

server:
  port: 7001

# eureka 配置
eureka:
  instance:
    # eureka 的服务器实例名称
    hostname: localhost
  client:
    # false 表示不向注册中心注册自己
    register-with-eureka: false
    # false 表示本服务就是注册中心,本服务的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置于Eureka  Server交互的地址,注册服务和查询服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

在主类上加@EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

启动服务,访问localhost:7001
在这里插入图片描述

2.2 编写一个Provider

pom中添加如下依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

配置application.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
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123
  http:
    encoding:
      charset: UTF-8
      force: true

# eureka client配置
eureka:
  client:
    # 表示是否将自己注册进 EurekaServer, 默认true
    register-with-eureka: true
    # 是否从Eureka Server抓取自己的注册信息,默认true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      # 注册中心地址
      defaultZone: http://localhost:7001/eureka

mybatis:
  mapper-locations: classpath:mapper/*.xml
  # 所有Entity别名类所在包
  type-aliases-package: com.yp.entity

在主类上添加@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class PaymentApplication {
    public static void main(String[] args) {
        SpringApplication.run(PaymentApplication.class, args);
    }
}

启动服务,访问localhost:7001
在这里插入图片描述
会发现有一个服务cloud-payment-service(大写)已经注册上来了

2.2 编写一个Consumer

pom中添加如下依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

配置application.yml

server:
  port: 80

spring:
  application:
    name: cloud-order-service
  http:
    encoding:
      charset: UTF-8
      force: true

eureka:
  client:
    # 表示是否将自己注册进 EurekaServer, 默认true
    register-with-eureka: true
    # 是否从Eureka Server抓取自己的注册信息,默认true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      # 注册中心地址
      defaultZone: http://localhost:7001/eureka

在主类上添加@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

启动服务,访问localhost:7001
在这里插入图片描述

2.3 测试Consumer访问Provider

2.31 Consumer编写

在Consumer中写一个RestTemplete配置,主要是实现负载均衡,和Restful接口访问

@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

Consumer写Controller

@RestController
@Slf4j
public class OrderController {
    // 直接访问地址
    private static final String PAYMENT_URL = "http://localhost:8001";

    // eureka上注册的微服务
    private static final String SERVICE_NAME = "http://CLOUD-PAYMENT-SERVICE";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return restTemplate.getForObject(SERVICE_NAME + "/payment/" + id, CommonResult.class);
    }
}
2.3.2 编写Provider

在Provider中写一个Controller,为了简化,后续service、dao不再列出

@RestController
@Slf4j
public class PaymentController {
	// 仅仅是为了验证负载均衡,因为本地验证只能由端口区分
    @Value("${server.port}")
    private int servicePort;

    @Autowired
    private PaymentService paymentService;

    @GetMapping("/payment/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);

        if (payment != null) {
            return new CommonResult<>(200, "获取数据成功! servicePort: " + servicePort, payment);
        } else {
            return new CommonResult<>(500, "获取数据失败! servicePort: " + servicePort, null);
        }
    }
}
2.3.3 运行测试

在这里插入图片描述

3. Eureka集群

目的是提高容错,原理就是互相注册

3.1 配置hosts

因为本地实验,要区分多个Eureka Server,同一IP映射多个域名

127.0.0.1	eureka7001.com
127.0.0.1	eureka7002.com

3.2 创建Eureka Server的application.yml

创建application7001.yml

server:
  port: 7001

# eureka 配置
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

创建application7002.yml

server:
  port: 7002

# eureka 配置
eureka:
  instance:
    # eureka 的服务器实例名称
    hostname: eureka7002.com
  client:
    # false 表示不向注册中心注册自己
    register-with-eureka: false
    # false 表示本服务就是注册中心,本服务的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置于Eureka  Server交互的地址,注册服务和查询服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka

3.3 打Eureka Server的jar包

在pom中加入plugin

	<build>
        <finalName>eureka-server</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**.*</include>
                    <include>**/*.*</include><!-- i18n能读取到 -->
                    <include>**/*/*.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>

                <configuration>
                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
                    <!-- 指定该Main Class为全局的唯一入口 -->
                    <mainClass>com.yp.EurekaServerApplication</mainClass>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

3.4 运行 eureka-server.jar

在两个cmd窗口独立运行

java -jar eureka-server.jar --spring.config.location=D:\spring-cloud-demo\application7001.yml
java -jar eureka-server.jar --spring.config.location=D:\spring-cloud-demo\application7002.yml

在这里插入图片描述

3.5 修改Provider和Consumer的配置

ProviderConsumer的application.yml defaultZone作同样的修改
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

eureka:
  client:
    # 表示是否将自己注册进 EurekaServer, 默认true
    register-with-eureka: true
    # 是否从Eureka Server抓取自己的注册信息,默认true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      # 注册中心地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

3.5 测试结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. Provider集群验证

启动两个cloud-payment-service进程,一个端口8001,另一个8002,打包与Eureka Server一样

java -jar payment-server.jar --spring.config.location=.\application8001.yml
java -jar payment-server.jar --spring.config.location=.\application8002.yml

在这里插入图片描述
在这里插入图片描述
端口轮询:
在这里插入图片描述
在这里插入图片描述

5. Eureka Server注册信息优化

instance:
# 主机名
instance-id: payment_8001
# 访问路径显示IP
prefer-ip-address: true

eureka:
  client:
    # 表示是否将自己注册进 EurekaServer, 默认true
    register-with-eureka: true
    # 是否从Eureka Server抓取自己的注册信息,默认true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      # 注册中心地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  instance:
    # 主机名
    instance-id: payment_8001
    # 访问路径显示IP
    prefer-ip-address: true

在这里插入图片描述

6. Eureka Server注册表微服务信息

写一个Controller用于相应注册中心注册表服务实例

@RestController
@RequestMapping("/consumer")
@Slf4j
public class ServiceInstancesController {
    @Autowired
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/payment/serviceInstances")
    public List<ServiceVo> discovery() {
        List<ServiceVo> serviceVoList = new ArrayList<>();
        List<String> services = discoveryClient.getServices();
        for (String serviceName : services) {
            ServiceVo serviceVo = new ServiceVo();
            List<ServiceInstanceVo> instanceVoList = new ArrayList<>();
            serviceVo.setServiceName(serviceName);

            List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
            for (ServiceInstance serviceInstance : instances) {
                ServiceInstanceVo instanceVo = new ServiceInstanceVo();
                instanceVo.setServiceId(serviceInstance.getServiceId());
                instanceVo.setHost(serviceInstance.getHost());
                instanceVo.setPort(serviceInstance.getPort());
                instanceVo.setUri(serviceInstance.getUri().toString());
                instanceVoList.add(instanceVo);
            }
            serviceVo.setInstances(instanceVoList);
            serviceVoList.add(serviceVo);
        }

        return serviceVoList;
    }
}

在主类上加 @EnableDiscoveryClient

请求:
http://localhost/consumer/payment/serviceInstances
在这里插入图片描述
格式化:

[
    {
        "serviceName":"cloud-payment-service",
        "instances":[
            {
                "host":"192.168.110.1",
                "port":8001,
                "uri":"http://192.168.110.1:8001",
                "serviceId":"CLOUD-PAYMENT-SERVICE"
            },
            {
                "host":"192.168.110.1",
                "port":8002,
                "uri":"http://192.168.110.1:8002",
                "serviceId":"CLOUD-PAYMENT-SERVICE"
            }
        ]
    },
    {
        "serviceName":"cloud-order-service",
        "instances":[
            {
                "host":"192.168.110.1",
                "port":80,
                "uri":"http://192.168.110.1:80",
                "serviceId":"CLOUD-ORDER-SERVICE"
            }
        ]
    }
]

7. Eureka的自我保护

某时刻某一服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存,提高系统可用性,这主要是考虑网络阻塞,拥堵对健康检查的影响。
在这里插入图片描述
Eureka Service配置
server:
# 关闭自我保护
enable-self-preservation: false
# 时间间隔,单位毫秒
eviction-interval-timer-in-ms: 3000

server:
  port: 7001

# eureka 配置
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
  server:
    # 关闭自我保护
    enable-self-preservation: false
    # 时间间隔,单位毫秒
    eviction-interval-timer-in-ms: 3000

注册的服务配置
lease-renewal-interval-in-seconds: 2
# Eureka服务端在接收最后一次心跳等待时间上限,单位秒(默认90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 3

eureka:
  client:
    # 表示是否将自己注册进 EurekaServer, 默认true
    register-with-eureka: true
    # 是否从Eureka Server抓取自己的注册信息,默认true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      # 注册中心地址
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    # 主机名
    instance-id: payment_8001
    # 访问路径显示IP
    prefer-ip-address: true
    # Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
    lease-renewal-interval-in-seconds: 2
    # Eureka服务端在接收最后一次心跳等待时间上限,单位秒(默认90秒),超时将剔除服务
    lease-expiration-duration-in-seconds: 3

测试:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值