SpringCloud微服务实战---服务的注册和发现(Eureka)

一、Spring Cloud简介

Spring Cloud是基于SpringBoot的,为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。

二、创建服务注册中心

在这里,我们需要用的的组件上Spring Cloud Netflix的Eureka ,eureka是一个服务注册和发现模块。

Eureka:

  1. 是纯正的 servlet 应用,需构建成war包部署
  2. 使用了 Jersey 框架实现自身的 RESTful HTTP接口
  3. peer之间的同步与服务的注册全部通过 HTTP 协议实现
  4. 定时任务(发送心跳、定时清理过期服务、节点同步等)通过 JDK 自带的 Timer 实现
  5. 内存缓存使用Google的guava包实现

2.1 首先创建一个maven主工程。

2.2 然后创建2个model工程:一个model工程作为服务注册中心,即Eureka Server,另一个作为Eureka Client

创建过程:

  1. 右键工程->创建model-> 选择spring initialir 如下图:

图像

  1. 点击“Next”,输入对应的名称,如下图:

  1. 点击“Next”,选择“Cloud Discovery”,然后选择“Eureka Server”,如下图:

  1. 点击“Next”,选择保存路径,最后点击“Finish”

创建完后的工程的pom.xml文件如下(maven创建的包结构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>springcloud-zureka</artifactId>
        <groupId>com.spring.cloud.zureka</groupId>
        <version>0.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>springcloud-zureka-server</artifactId>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <testSource>${java.version}</testSource>
                    <testTarget>${java.version}</testTarget>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.3 启动一个服务注册中心

只需要一个注解@EnableEurekaServer,这个注解需要在springboot工程的启动application类上加:

/**
 * [@Author](https://my.oschina.net/arthor) lixinhao
 * @Description
 * [@Date](https://my.oschina.net/u/2504391) 2018/4/13 17:25
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

2.4 appication.yml配置

eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成),在默认情况下erureka server也是一个eureka client ,必须要指定一个 server。eureka server的配置文件appication.yml:

#配置eureka端口,端口一定要独立
server:
  port: 8761

eureka:
  instance:
    #配置主机名
    hostname: localhost
  client:
    #配置服务注册中心是否以自己为客户端进行注册(配置false)
    registerWithEureka: false
    #是否取得注册信息(配置false)
    fetchRegistry: false
    serviceUrl:
      #配置eureka服务地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明自己是一个eureka server

2.5 日志配置

创建配置文件bootstrap.yml:

#日志
logging:
  config: classpath:logback-spring.xml
  path: E:/log/@pom.artifactId@

创建配置文件logback-spring.xml:

<!--
    1、scan:当此属性设置为 true 时,配置文件如果发生改变,将会被重新加载,默认值为 true
    2、scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当 scan 为 true 时,此属性生效。默认的时间间隔为1分钟
    3、debug:当此属性设置为 true 时,将打印出 logback 内部日志信息,实时查看 logback 运行状态。默认值为 false 。
 -->
<configuration scan="true" scanPeriod="10 seconds" debug="false">
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <!-- 开启后可以通过jmx动态控制日志级别(springboot Admin的功能) -->
    <!--<jmxConfigurator/>-->


    <!--appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略。-->
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--
           <encoder> 表示对日志进行编码:
               %d{HH: mm:ss.SSS}——日志输出时间
               %thread——输出日志的进程名字,这在Web应用以及异步任务处理中很有用
               %-5level——日志级别,并且使用5个字符靠左对齐
               %logger{36}——日志输出者的名字
               %msg——日志消息
               %n——平台的换行符
        -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{50} : %msg%n</pattern>
            <!--<charset>UTF-8</charset>-->
        </encoder>

        <!--ThresholdFilter为系统定义的拦截器,例如我们用ThresholdFilter来过滤掉ERROR级别以下的日志不输出到文件中。如果不用记得注释掉,不然你控制台会发现没日志~-->
        <!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,所以我们使用下面的策略,可以避免输出 Error 的日志-->

        <!--<filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
        <!--过滤 Error-->
        <!--<level>ERROR</level>-->
        <!--匹配到就禁止-->
        <!--<onMatch>DENY</onMatch>-->
        <!--没有匹配到就允许-->
        <!--<onMismatch>ACCEPT</onMismatch>-->
        <!--</filter>-->

    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志名称:
                如果没有File 属性,那么只会使用FileNamePattern的文件路径规则,
                如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。 -->
        <File>${LOG_PATH}/info.log</File>
        <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
            <fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}-%i.log</fileNamePattern>
            <!--日志文件最大的大小-->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
            <!--<totalSizeCap>1GB</totalSizeCap>-->
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!--日志输出编码格式化-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{50} : %msg%n</pattern>
            <!--<charset>UTF-8</charset>-->
        </encoder>
    </appender>

    <!--RollingFileAppender 用于切分文件日志:-->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <File>${LOG_PATH}/error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}-%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>2</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{50} : %msg%n</pattern>
            <!--<charset>UTF-8</charset>-->
        </encoder>
    </appender>

    <!--
        1、root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        2、level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
    -->
    <root level="info">
        <!--可以包含零个或多个元素,标识这个appender将会添加到这个loger-->
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

2.6 查看界面信息

eureka server 是有界面的,启动工程,打开浏览器访问:http://localhost:8761 ,界面如下:

No instances available 没有服务被发现,接下来创建服务

三、创建一个服务提供者 (eureka client)

当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka server 从每个client实例接收心跳消息。 如果心跳超时,则通常将该实例从注册server中删除。

创建过程同server类似,创建完pom.xml如下:

<?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>springcloud-zureka</artifactId>
        <groupId>com.spring.cloud.zureka</groupId>
        <version>0.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>springcloud-zureka-client</artifactId>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <testSource>${java.version}</testSource>
                    <testTarget>${java.version}</testTarget>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

通过注解@EnableEurekaClient 表明自己是一个eureka client.

/**
 * @Author lixinhao
 * @Description
 * @Date 2018/4/13 17:25
 */
@EnableEurekaClient
@SpringBootApplication
@RestController
public class EurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }

    @Value("${server.port}")
    String port;

    @RequestMapping("/hi")
    public String home(@RequestParam String name) {
        return "hi "+name+",i am from port:" +port;
    }
}

在配置文件中注明自己的服务注册中心的地址,application.yml配置文件如下:

eureka:
  client:
    serviceUrl:
      #配置eureka服务地址,链接注册中心地址
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8762
spring:
  application:
    #在注册中心显示的“Application”名称
    name: "@pom.artifactId@"

注:spring.application.name中使用了@pom.artifactId@,在YML文件中需要加上单引号或者双引号,否则无法获取值

需要指明spring.application.name,这个很重要,这在以后的服务与服务之间相互调用一般都是根据这个name 。 启动工程,打开http://localhost:8761 ,即eureka server 的网址:

你会发现一个服务已经注册在服务中了,服务名为springcloud-zureka-client,端口为:8762

四、Eureka的自我保护模式

如果在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.

产生原因:

Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否 低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在 生产环境上通常是由于网 络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提 示这个警告。保护模式主要用于一组客户端和Eureka Server之间存在网络分 区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注 册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)

解决方法:

    1. Eureka Server端:配置关闭自我保护,并按需配置Eureka Server清理无效节点的时间间隔。
  1. eureka.server.enable-self-preservation # 设为false,关闭自我保护
  2. eureka.server.eviction-interval-timer-in-ms # 清理间隔(单位毫秒,默认是60*1000)
    1. Eureka Client端:配置开启健康检查,并按需配置续约更新时间和到期时间
  1. eureka.client.healthcheck.enabled # 开启健康检查(需要spring-boot-starter-actuator依赖)
  2. eureka.instance.lease-renewal-interval-in-seconds # 续约更新时间间隔(默认30秒)
  3. eureka.instance.lease-expiration-duration-in-seconds # 续约到期时间(默认90秒)

生产环境建议采用默认配置,服务停止到注册中心清除实例之间有一些计算什么的。

如果你现在在JAVA这条路上挣扎,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,7个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,q群号为:779792048

注:加群要求

1、具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值