一、Spring Cloud简介
Spring Cloud是基于SpringBoot的,为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。
二、创建服务注册中心
在这里,我们需要用的的组件上Spring Cloud Netflix的Eureka ,eureka是一个服务注册和发现模块。
Eureka:
- 是纯正的 servlet 应用,需构建成war包部署
- 使用了 Jersey 框架实现自身的 RESTful HTTP接口
- peer之间的同步与服务的注册全部通过 HTTP 协议实现
- 定时任务(发送心跳、定时清理过期服务、节点同步等)通过 JDK 自带的 Timer 实现
- 内存缓存使用Google的guava包实现
2.1 首先创建一个maven主工程。
2.2 然后创建2个model工程:一个model工程作为服务注册中心,即Eureka Server,另一个作为Eureka Client
创建过程:
- 右键工程->创建model-> 选择spring initialir 如下图:
- 点击“Next”,输入对应的名称,如下图:
- 点击“Next”,选择“Cloud Discovery”,然后选择“Eureka Server”,如下图:
- 点击“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将会尝试保护其服务注 册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)
解决方法:
-
- Eureka Server端:配置关闭自我保护,并按需配置Eureka Server清理无效节点的时间间隔。
- eureka.server.enable-self-preservation # 设为false,关闭自我保护
- eureka.server.eviction-interval-timer-in-ms # 清理间隔(单位毫秒,默认是60*1000)
-
- Eureka Client端:配置开启健康检查,并按需配置续约更新时间和到期时间
- eureka.client.healthcheck.enabled # 开启健康检查(需要spring-boot-starter-actuator依赖)
- eureka.instance.lease-renewal-interval-in-seconds # 续约更新时间间隔(默认30秒)
- 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高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!