zoukankan      html  css  js  c++  java
  • Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient(中级)

            我们这里只有一台服务器,所以我们先仿集群搭建。

             完整demo项目代码:https://github.com/wades2/EurekaDemo2

            在这之前我们先分析分析Eureka相比其他注册中心的好处。在一般的应用过程中,如果注册中心service出现了问题,然而没有备用的节点去替代这个主节点去分发服务,就会造成相关注册服务的瘫痪,因此我们在分布式架构中,都会有备用节点。

            我们先看看Doubel,在doubel中,zookeeper(以下简称zk)是作为服务注册中心的,在集群配置中,会有一个主从关系节点。如果Master挂了, zk就会启动节点推举,而在节点推举的过程中,整个服务是不能使用的。但是zk强调的是CAP理论中的CP强调高的一致性,【注:什么是CAP理论:Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得】,在实际上线的站点或者网站中,30~60s的选举过程导致站点不可用,损失是很大。

             

          

    而我们再看看Eureka(如上图),Eureka是去中心化的,每个Eureka server都是平级的。Eureka取CAP中的AP,注重可用性,Eureka内置了心跳服务(用于淘汰一些“濒死”的服务器),即使当你的应用服务某个server挂掉了,其他的服务是可以立即顶上去,保证客户端向其发起请求有响应。

           两者的对比我们先大致分析到这里。具体的分析可以看我转的一篇博客:

           https://blog.csdn.net/asd529735325/article/details/85049662

          接下来我们尝试自己搭建一个分布式的包含:Eureka Server,Application Service,Application Client的Eureka注册中心。

          通过上面这张图我们可以看到,一个Eureka有三个角色:

         1、Eureka Server(通过Register, Get,Renew等接口提供注册和发现)
         2、Application Service(服务提供方,把自身服务实例注册到Eureka Server):
         3、Application Client(Service Consumer):服务调用方,通过Eureka Server获取服务实例,并调用Application Service

         

    他们主要进行的活动如下:

    每个Region有一个Eureka Cluster, Region中的每个Zone都至少有一个Eureka Server。
    Service作为一个Eureka Client,通过register注册到Eureka Server,并且通过发送心跳的方式更新租约(renew leases)。如果Eureka Client到期没有更新租约,那么过一段时间后,Eureka Server就会移除该Service实例。
    当一个Eureka Server的数据改变以后,会把自己的数据同步到其他Eureka Server。
    Application Client也作为一个Eureka Client通过Get接口从Eureka Server中获取Service实例信息,然后直接调用Service实例。
    Application Client调用Service实例时,可以跨可用区调用。(【引】)

         

            在上面一篇文章中我们已经搭建好了Eureka Server和Application Client,如果不清楚的朋友建议可以先看看这篇博文(https://blog.csdn.net/asd529735325/article/details/84992538,git代码:https://github.com/wades2/EurekaDemo ),再来本篇中一起探讨学习。

            

            为了保护eureka安全性,在上一篇的基础上,我加了service访问密码。因此在client端和集群配置的service都需要加上相互的访问密码。

            先看看我个人demo大致架构吧:

    其中:EurekaServer模块和Eurekaserver_back是两个相互平级依赖的server,EurekaClient是我们服务提供方,EurekaCaller是我们服务的调用方。大致的调用过程如下图:

    基于上一篇的基础,我们从新看看pom文件和相关配置。

    首先是Eureka Server(此处我们是集群配置,因此有两个server)

    首先修改电脑的hostname,添加:127.0.0.1 localhost server1 server2,作为两个server的相互依赖。

    两个server的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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.M3</spring-cloud.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Camden.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka-server</artifactId>
                <version>1.3.6.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
        <repositories>
            <repository>
                <id>spring-milestones</id>
                <name>Spring Milestones</name>
                <url>https://repo.spring.io/milestone</url>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
    
    
    </project>
    

    相关注意点在上一篇博客有提到,这里就不赘述。

    EurekaServer的配置文件:

    # 应用程序的名称
    spring.application.name=Eureka-server2
    
    security.user.name=user
    security.user.password=123456
    #修改启动端口
    server.port=8083
    # 是否将该实例的注册信息注册到Eureka服务器上,在只有一个Eureka服务器的情况下没必要,只是用于实例的发现
    eureka.client.register-with-eureka=true
    
    # 是否向Eureka服务器获取注册信息,在单实例的Eureka中共没必要
    eureka.client.fetch-registry=true
    #Eureka Server能够迅速有效地踢出已关停的节点,但是新手由于Eureka自我保护模式,以及心跳周期长的原因,常常会遇到Eureka Server不踢出已关停的节点的问题
    # 设为false,关闭自我保护
    eureka.server.enable-self-preservation=true
    #清理间隔
    eureka.server.eviction-interval-timer-in-ms=6000
    
    eureka.client.serviceUrl.defaultZone=http://user:123456@server2:8082/eureka
    
    eureka.instance.hostname=server1

    EurekaServer_back的配置文件:

    # 应用程序的名称
    spring.application.name=Eureka-server2
    
    security.user.name=user
    security.user.password=123456
    #修改启动端口
    server.port=8082
    # 是否将该实例的注册信息注册到Eureka服务器上,在只有一个Eureka服务器的情况下没必要,只是用于实例的发现
    eureka.client.register-with-eureka=true
    
    # 是否向Eureka服务器获取注册信息,在单实例的Eureka中共没必要
    eureka.client.fetch-registry=true
    #Eureka Server能够迅速有效地踢出已关停的节点,但是新手由于Eureka自我保护模式,以及心跳周期长的原因,常常会遇到Eureka Server不踢出已关停的节点的问题
    # 设为false,关闭自我保护
    eureka.server.enable-self-preservation=true
    #清理间隔
    eureka.server.eviction-interval-timer-in-ms=60000
    
    eureka.client.serviceUrl.defaultZone=http://user:123456@server1:8083/eureka
    
    eureka.instance.hostname=server2
    

    因为我们引入了security的jar包,保证访问server页面的安全性,因此,在client和其他节点配置的时候,都应该加上用户名和密码,把defaultZone改为:http://用户名:密码@hostname:端口号/eureka的形式。

    【注意!!!!,这里因为是相互依赖,所以在EurekaServer中defaultZone使用的是EurekaServer_back的用户名,密码和它对应的hostname+端口,同理EurekaSerer_back对应的是EurekaServer的。】

    运行类都一样:

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

    然后我们可以启动一个server访问一下:

    访问需要用户名密码,就是配置文件里面的security.user.name,和security.user.password,我们可以看到界面如下:

    这里我们可以看到因为我们8082端口的server因为没有启动,所以无法依赖到,但是已经注册进去了。我们再启动server_back可以看到界面如下:

    这样的界面就是注册成功了。然后我们开始第二部:

    Application Service注册到server里面,也就是我们上一篇说的client端,也就是我这个demo的EurekaClient:

    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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.M3</spring-cloud.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Camden.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!--<dependency>-->
                <!--<groupId>org.springframework.cloud</groupId>-->
                <!--<artifactId>spring-cloud-netflix-eureka-client</artifactId>-->
                <!--<version>1.3.6.RELEASE</version>-->
            <!--</dependency>-->
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
                <version>1.4.0.M1</version>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka-server</artifactId>
                <version>1.3.6.RELEASE</version>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
        <repositories>
            <repository>
                <id>spring-milestones</id>
                <name>Spring Milestones</name>
                <url>https://repo.spring.io/milestone</url>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
    
    
    </project>
    

    application配置文件:

    spring.application.name=Eureka-client
    
    #eureka.client.allow-redirects=false
    #修改启动端口
    server.port=8084
    eureka.client.serviceUrl.defaultZone=http://user:123456@localhost:8083/eureka,http://user:123456@localhost:8082/eureka
    #eureka.client.register-with-eureka=true
    eureka.instance.ip-address=true

    启动类:

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableDiscoveryClient
    @ComponentScan(basePackages = {"com.example.demo.controller"})
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    

    这里我们设置了扫描controller包下面的java文件,我的demo中contorller如下:

    其中UserController放置在controller这个包下,还有一个作为测试的Contrller放置在启动类平级目录(你也可以随便放一个,我们只是做后期实验的)

    我们的UserController

    package com.example.demo.controller;
    
    import com.netflix.appinfo.InstanceInfo;
    import com.netflix.discovery.DiscoveryClient;
    import com.netflix.discovery.EurekaClient;
    import com.netflix.discovery.converters.Auto;
    import com.netflix.discovery.shared.Applications;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    
    @RestController
    @RequestMapping("user")
    public class UserController {
    //    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    
    //    @Autowired
    //    private IUserService userService;
    
    //    @GetMapping("getUser")
    //    public List<UserEntity> getUser() {
    //        UserEntity user = new UserEntity();
    //        return userService.getUser();
    //    }
        @Autowired
        private EurekaClient eurekaClients;
    
    //    @Autowired
    //    private DiscoveryClient discoveryClient;
    
        @GetMapping("getUser")
        public String getUser() {
            //todo 得到eureka server的服务实例
            InstanceInfo info=eurekaClients.getNextServerFromEureka("Eureka-client",false);
    //        return info.getHomePageUrl();
            return "hello one";
        }
    
    
    }
    
    

    我们的Controller:

    package com.example.demo;
    
    import com.netflix.appinfo.InstanceInfo;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("user")
    public class Controller {
        @GetMapping("getUser2")
        public String getUser() {
            return "hello tow....";
        }
    }
    

    然后启动。

    我们可以看到如下界面:

    这里client已经注册进来了,然后我们可以访问一下http://localhost:8084/user/getUser

    访问没问题。

    访问http://localhost:8084/user/getUser2,报错,因为我们启动类没有扫描其他的包。

    最后一步:Application Client(Service Consumer):服务调用方,通过Eureka Server获取服务实例,并调用Application Service

    也就是我们的EurekaCaller:

    直接使用Eureka Client还是比较麻烦的,幸运的是,RestTemplate整合了EurekaClient,Ribbon为我们提供了多样的负载均衡的功能,为我们提供了很多便利,我们所需要做的就是在Spring中注册一个RestTemplate,并且添加@LoadBalanced 注解。

    加入Ribbon的原因是服务调用者不关心服务提供者有多少个服务实例,它只关注它要调用这个服务ID,因而可能需要一定的负载均衡。

    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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.RC1</spring-cloud.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-rest</artifactId>
            </dependency>
            <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>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </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>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
        <repositories>
            <repository>
                <id>spring-milestones</id>
                <name>Spring Milestones</name>
                <url>https://repo.spring.io/milestone</url>
            </repository>
        </repositories>
    
    </project>
    

    application配置文件:

    spring.application.name=Eureka_caller
    server.port=8086
    eureka.client.serviceUrl.defaultZone=http://user:123456@localhost:8083/eureka,http://user:123456@localhost:8082/eureka
    

    启动类一样扫描controller:

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication
    @ComponentScan({"com.example.demo.controller"})
    @EnableEurekaClient
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }
    
    

    我们这里的controller开始通过Rest客户端映射调用注册的Eureka_client。

    package com.example.demo.controller;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @Configuration
    public class Controller {
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    
        @GetMapping("getUser/routine")
        public String routine() {
            RestTemplate restTemplate = getRestTemplate();
            String json = restTemplate.getForObject("http://Eureka-client/user/getUser", String.class);
            return json;
        }
    
        @GetMapping("getUser/routine2")
        public String routine2() {
            RestTemplate restTemplate = getRestTemplate();
            String json = restTemplate.getForObject("http://Eureka-client/user/getUser2", String.class);
            return json;
        }
    }
    

    restTemplate.getForObject方法请求特定的服务url,注意里面使用的Eureka-client正是我们刚才在服务提供者客户端项目中配置的服务名称,它已经被注册到Eureka服务上。

    然后我们启动,访问http://localhost:8086/getUser/routine

    我们可以看到内容和访问http://localhost:8084/user/getUser一样,但是依旧访问http://localhost:8086/getUser/routine2访问不到,其实要想访问到很简单,在EurekaClient扫描中带上Conrtoller所在的包就可以了!

    OK,全文结束,接下来我们讲解,如何充分利用ribbon来动态调用服务消费者。

  • 相关阅读:
    Powerful Bash-style command line editing for cmd.exe
    VBA Code for Word Navigation Pane 【failed】 view-showheading-method-word
    network lab simulator
    Global Git ignore
    hosts 持续更新
    TC Hangs when using quick search extended on win10 (1703)
    mybatis缓存机制
    web网上书店总结(jsp+servlet)
    Spring AOP之多切面运行顺序
    C语言实现蛇形矩阵
  • 原文地址:https://www.cnblogs.com/asd529735325/p/10216013.html
Copyright © 2011-2022 走看看