• Spring Cloud (二):服务发现 Eureka 和 Consul


    Eureka

    Netflix 开发的组件,使用 Eureka 可以配合其他 Netflix 的组件比如 API 网关 ZUUL

    2.0 起不再开发维护了
    https://github.com/Netflix/eureka/wiki

    The existing open source work on eureka 2.0 is discontinued. The code base and artifacts that were released as part of the existing repository of work on the 2.x branch is considered use at your own risk.
    
    Eureka 1.x is a core part of Netflix's service discovery system and is still an active project.
    

    Server

        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    @EnableEurekaServer
    @SpringBootApplication
    public class Demo1Application {
        public static void main(String[] args) {
            SpringApplication.run(Demo1Application.class, args);
        }
    }
    
    server.port=8761
    eureka.instance.hostname=localhost
    eureka.client.registerWithEureka=false
    eureka.client.fetchRegistry=false
    eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8761/eureka/
    

    一个 Client 程序向 Server 注册自己的信息

        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        </properties>
    
        <dependencies>
            <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.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    server.port=8762
    
    eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
    eureka.client.healthcheck.enabled=true
    spring.application.name=service-provider-1
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class EurekaClientApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaClientApplication.class, args);
        }
    }
    
    @RestController
    public class Controller {
        @RequestMapping("/api")
        public String index() {
            return "Greetings from Eureka Client!";
        }
    }
    

    登上 Eureka Server 的 URL http://localhost:8761/ 可以看到注册了一个服务,这个服务的端口名字是 service-provider-1,端口是 8762,以及有这个服务对应的 IP

    再写一个程序,通过 Eureka Server 找到上面这个服务

        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    server.port=8763
    ## 如果 Eureka Server 使用默认的 8761 端口,并且这个程序不注册,就不需要写 Eureka 信息
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class EurekaConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaConsumerApplication.class, args);
        }
    }
    
    @RestController
    public class Controller {
        @Autowired
        private DiscoveryClient discoveryClient;
     
        @RequestMapping("/queryService")
        public String query() {
            List<ServiceInstance> instances = discoveryClient.getInstances("service-provider-1");
            StringBuilder urls= new StringBuilder();
            for(ServiceInstance instance : instances){
                urls.append(instance.getHost()+":"+instance.getPort()).append(",");
            }
            return "service name : service-provider-1<br>" + "host : " + urls.toString();
        }
    }
    

    查询 http://localhost:8763/queryService 可以看到返回

    service name : service-provider-1
    host : 192.168.0.101:8762,

    Consul

    Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置
    https://www.consul.io/docs/intro

    与 Eureka 相比,Consul 提供更完整的功能,包括了

    • 服务发现,和 Eureka 类似
    • 健康检查,比如定期检查某个服务是否返回 200,检查当前节点的内存使用率是否超过 90% 等
    • Key-Value 存储,可用于动态配置,功能标记,leader 选举,一致性协定,等等
    • 安全服务通信,可以产生分发安全认证给服务,建立双向安全链接
    • 多数据中心

    和 Eureka 是 Spring Boot 实现不同,Consul 是通过 go 语言编写的

    安装 Consul

    sudo apt-get install consul
    

    debug 环境可以用 -dev 只启动一个用就可以

    ## 如果机器有多个 IP 就需要用 bind 指定一个进行绑定
    consul agent -dev -bind=10.0.2.1
    

    启动后就可以访问 http://localhost:8500

    生产环境下应该启动 Consul 集群,集群包括 Server 和 Client

    Server 的数量是有限的若干个,比如 3 个,5 个,通常为奇数,方便选举,Server 负责数据的存储和同步,可能是为了防止每个服务都直接和 Server 打交道造成 Server 压力太大,又为每台跑服务的机器安装 Client,因为每台机都有,所以 Client 可以有很多很多个,Client 不存储数据,只是将本机的服务请求、服务状态,整合然后统一和 Server 进行交互

    而每个服务实际上是在和本机的 Consul Client 打交道,Consul Server 对它们是透明的

    这里的 Server、Client 和平时理解的可能有点区别,可能叫 Consul Server 和 Consul Agent/Proxy 比较合适,但在这里 Server 和 Client 都被称为 Agent

    假设起 3 个 server 和 1 个 client

    consul agent -server -ui -bootstrap-expect=3 -node=s1 
                         -data-dir=~/projects/consul/data -config-dir ~/projects/consul/consul.d 
                         -bind=10.0.2.15 -client=0.0.0.0
    
    consul agent -server -ui -bootstrap-expect=3 -node=s2 
                         -data-dir=~/projects/consul/data -config-dir ~/projects/consul/consul.d 
                         -bind=10.0.2.16 -client=0.0.0.0 -join=10.0.2.15
    
    consul agent -server -ui -bootstrap-expect=3 -node=s3 
                         -data-dir=~/projects/consul/data -config-dir ~/projects/consul/consul.d 
                         -bind=10.0.2.17 -client=0.0.0.0 -join=10.0.2.15
    
    consul agent -node=c1 
                         -data-dir=~/projects/consul/data -config-dir ~/projects/consul/consul.d 
                         -bind=10.0.2.18 -client=0.0.0.0 -join=10.0.2.15
    

    可以查看集群成员

    consul members
    

    退出集群

    consul leave
    

    注册服务

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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-web</artifactId>
        </dependency>
    </dependencies>
    
    server.port=8501
    spring.application.name=spring-cloud-consul-service-1
    spring.cloud.consul.host=localhost
    spring.cloud.consul.port=8500
    # 注册到 consul 的服务名称
    spring.cloud.consul.discovery.serviceName=consul-service-1
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConsulServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsulServiceApplication.class, args);
        }
    }
    
    @RestController
    public class Controller {
        @RequestMapping("/hello")
        public String hello() {
            return "consul-service-1";
        }
    }
    
    # 实现另一个 service,注册的名字一样,但端口(或 IP)不一样,这样可以在消费端实现负载均衡
    server.port=8502
    spring.application.name=spring-cloud-consul-service-1
    spring.cloud.consul.host=localhost
    spring.cloud.consul.port=8500
    # 注册到 consul 的服务名称
    spring.cloud.consul.discovery.serviceName=consul-service-1
    

    消费服务

    pom 文件参考 service-1
    
    spring.application.name=spring-cloud-consul-consumer
    server.port=8503
    spring.cloud.consul.host=127.0.0.1
    spring.cloud.consul.port=8500
    # 设置不需要注册到 consul 中
    spring.cloud.consul.discovery.register=false
    
    @SpringBootApplication
    public class ConsulConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsulConsumerApplication.class, args);
        }
    }
    
    @RestController
    public class ServiceController {
        @Autowired
        private LoadBalancerClient loadBalancer;
        @Autowired
        private DiscoveryClient discoveryClient;
     
        @RequestMapping("/services")
        public Object services() {
            // 获取 consul-service-1 服务的信息
            // 这里会返回两个,因为有两个服务注册了这个名字
            return discoveryClient.getInstances("consul-service-1");
        }
     
        @RequestMapping("/discover")
        public Object discover() {
            // 通过 LoadBalancerClient 获取 consul-service-1 服务的其中一个 host
            // 可以看到有时返回 8501 端口,有时返回 8502 端口,这样就实现了负载均衡
            return loadBalancer.choose("consul-service-1").getUri().toString();
        }
    }
    

    CAP(C:一致性,A:可用性,P:分区容错性)理论:分布式系统只能满足 CAP 的其中两个

    P 是必须保证的
    保证 C 就要保证同步,那么同步没完成就不能用,这样就保证不了 A
    保证 A 就必须立即返回结果,那么就不能等同步完成,这样就保证不了 C

    Consul 属于 CP,优先保证一致性
    Eureka 属于 AP,优先保证可用性

    ZooKeeper(CP)、etcd(CP) 一定程度上也提供了分布式协调的功能

  • 相关阅读:
    vue检查用户名是否重复
    后端注册接口完善
    django添加检查用户名和手机号数量接口
    Vue联调,图片及短信验证码
    swift webView 提出这样的要求你能忍吗?
    iOS 如何给Xcode7项目添加“.pch”文件
    swift 定制自己的Button样式
    Swift 为你的webView定制标题
    swift 如何获取webView的内容高度
    如何在MAC上使用SVN,简单几行命令搞定
  • 原文地址:https://www.cnblogs.com/moonlight-lin/p/14129458.html
Copyright © 2020-2023  润新知