问题

  • 服务消费者如何获取服务提供者的地址信息

  • 多个服务提供者时,如何选择

  • 消费者如何获取提供者的健康状态

Eureka

Eureka的作用

Eureka作为服务端。所有的服务提供者或者消费者都作为客户端。

  1. 服务提供者启动时向eureka注册自己的信息,eureka保存这些信息,消费者根据服务名称向eureka拉取提供者信息

  2. 服务消费者利用负载均衡算法,从服务列表中挑选一个

  3. 服务提供者定时向Eureaka服务端发送心跳请求,报告健康状态。eureka更新记录服务列表信息,心跳不正常的被剔除。消费者可以拉取最新的信息

架构

EurekaServer:服务端,注册中心

记录服务信息,心跳监控

EurekaClient:客户端

  1. Provider:服务提供者

注册自己的信息到EurekaServer

定时发送心跳

  1. consumer:服务消费者

根据服务名称从EurekaServer拉取服务列表

基于服务列表做负载均衡,选中一个微服务后发起远程调用

服务注册

启动客户端

pom依赖

        <!--eureka服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

配置文件

server:
  port: 10086 # 服务端口
spring:
  application:
    name: eurekaserver # eureka的服务名称
# eureka 服务端也会将自己注册进入,主要为了实现服务端的负载均衡,多个服务端通过逗号分隔
eureka:
  client:
    service-url:  # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

启动注解

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

启动服务端

pom依赖

		<!--eureka客户端依赖-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

配置文件

# 服务端名称
spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

idea实现一份代码启动多个服务

启动配置中复制配置,修改vm参数的端口,即可启动多个服务

验证

http://localhost:10086/

输入客户端地址,可以查到服务注册情况

eureka-server.jpg服务发现

修改请求地址,通过服务名代替ip+port实现远程调用

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        User user = userClient.findById(order.getUserId());
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }

给RestTemplate添加@LoadBalanced注解,实现负载均衡

    @Bean
    // 启动负载均衡
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

Nacos

服务注册

客户端

需要先下载nacos客户端

home (nacos.io)

启动文档:Nacos 快速开始

服务端

引入依赖

            <!--nacos的管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>${spring-cloud-alibaba.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

<!-- nacos客户端依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos 使用RestTemplate需要单独引入负载均衡依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

nacos版本与boot、cloud对应关系:版本说明 · alibaba/spring-cloud-alibaba Wiki (github.com)

配置文件

spring:
  application:
    name: order-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848

服务发现

RestTemplate

通erukeka,都是依赖springcloud commons,对于服务注册和发现,都会遵循DiscveryClient和ServiceRegistry这两个接口,所以不需要改动代码

服务分级存储

Nacos中分为三层隔离,分别是命名空间(namespace)隔离、组(group)隔离、集群(cluster-name)隔离。

命名空间是绝对隔离,配置和服务都不可调用。--- 例如区分线上,预防,测试

组隔离是同一命名空间下,不同组配置可以共享和继承,但是服务不能跨组调用。--例如隔离不同业务

集群隔离,是可以让同一命名空间,同一个分组下,同一集群内服务隔离或不隔离。-- 例如不同地域机房

  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        namespace: dev
        group: local
        cluster-name: jecyp

负载均衡

Nacos中提供了一个NacosRule的实现,可以优先从同集群中挑选实例。

1)给order-service配置集群信息

修改order-service的application.yml文件,添加集群配置:

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ # 集群名称

2)修改负载均衡规则

新版cloud使用loadBalancer中。如果通过配置注入,需要单独继承出来注册。如果使用@bean的形式会找不到bean。(暂时不知道啥原因)

@Component
public class MyNacosLoadBalancerClient extends NacosLoadBalancer {



    public MyNacosLoadBalancerClient(Environment environment,
                                     LoadBalancerClientFactory loadBalancerClientFactory,
                                     NacosDiscoveryProperties nacosDiscoveryProperties) {
        super(loadBalancerClientFactory.getLazyProvider(environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME), ServiceInstanceListSupplier.class),
                environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME), nacosDiscoveryProperties);
    }
}

@Configuration
public class MyRemoteServiceLoadBalancerConfiguration {


    @Bean("remoteService-userService")
    public LoadBalancerClientSpecification myLoadBalancer(){
        LoadBalancerClientSpecification myLoadBalancer = new LoadBalancerClientSpecification();
        myLoadBalancer.setName("user-service");
        myLoadBalancer.setConfiguration(new Class[]{MyNacosLoadBalancerClient.class});
        return myLoadBalancer;
    }
}

默认情况下NacosRule是同集群内随机挑选,不会考虑机器的性能问题。

因此,Nacos提供了权重配置来控制访问频率,可以设置实例的权重值,0~1之间。同集群内的多个实例,权重越高被访问的频率越高。权重设置为0则完全不会被访问

临时实例和非临时

实例默认为临时实例。临时实例采用心跳模式,非临时实例采用主动检测模式。

临时实例心跳不正常会被剔除,非临时实例则不会被剔除

默认情况下,临时实例的心跳每5s发送移除。如果超过15s没有收到客户端心跳,那就会标记为不健康。如果超过30s则会直接删除临时实例

  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        // 改为非临时实例
        ephemeral: false

tips:如果同一个实例原来为临时实例,修改为非临时后,nacos不允许其进行注册。启动服务会报错。可以将\nacos\data\protocol\raft\naming_instance_metadata文件夹里面的文件删除。重启nacos客户端

总结

image-qypy.pngNacos与eureka的共同点

都支持服务注册和服务拉取

都支持服务提供者心跳方式做健康检测

Nacos与Eureka的区别

Nacos支持服务端主动检测提供者状态

Nacos支持服务列表变更的消息推送模式,服务列表更新更及时

Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式