一.微服务简介
1.什么是微服务?
微服务(MicroService)的概念最早是在2014年由Martin Fowler和James Lewis共同提出,他们定义了微服务是由单一应用程序构成的小服务,拥有自己的进程与轻量化处理,服务依业务功能设计(微服务一个业务一个项目),以全自动方式部署,与其他服务使用HTTP API通讯(每个项目否是一个标准的web项目,不再像之前RPC项目分为provider和consumer).同时,服务会使用最小规模的集中管理(例如Docker)技术,服务可以用不同的编程语言与数据库等
提取出的核心点:
1.微服务是框架
2.微服务中项目都称为服务
3.微服务拆分颗粒度为业务
4.微服务中服务和服务之间使用HTTP协议通信
5.微服务和Docker结合使用更方便
6.微服务是分布式架构的一种
2.为什么使用微服务?
2.1单体应用特点
大部分的开发者都开发过单体应用,无论是传统的Servlet+JSP,还是SSM,还是现在的SpringBoot,它们都是繁体应用,Nemo长期陪伴我们的单体应用又什么弊端?我们是mainline了什么问题,导致我们要抛弃单体应用转向微服务架构>主要原因如下:
a)部署成本高(无论是修改1行代码,还是10行代码,都要全量替换)
b)改动影响大,风险高(不论代码改动多少,成本都相同)
c)因为成本高,风险高,所以导致部署频率低无法款速交付客户需求)
d)无法满足快速扩容,弹性伸缩,无法适应云环境特性等问题
2.2微服务特点
微服务架构的特点:针对特定服务发布,影响小,风险小,成本低;频繁发布版本,快速交付需求;第成本扩容,弹性伸缩,适应云环境等特点
为服务架构与现在企业中敏捷开发思想是匹配的,核心都是强调希望项目快速更新迭代(当项目需要快速更新迭代时微服务架构就特别适合)(这就是为什么使用微服务)
我们知道一个朴素的理念,没有任何事物是完美的,任何东西都有两面型,有得必有失,那么在选择微服务在解决了快速响应和弹性伸缩的问题同时,它有给我们带来了什么问题?简单总结如下(微服务架构的缺点):
分布式系统的复杂性
部署,测试和监控的成本问题
分布式事务和CAP的相关问题
分布式中问服务架构相对于单体架构还需要处理很多事情.例如:分布式事务,团队合作等问题都需要明确的提前设计好
3.应用程序架构变迁图
无论是SOA架构,RPC架构还是微服务架构统称为分布式架构
3.1RPC架构和SOA架构和微服务架构的区别?
SOA架构:核心消息总线(Message bus).消息总线过于笨重在目前项目中已经很少使用了
RPC架构:主要有被调用的远程服务器(Provider)和调用的服务器(Consumer),把所有数据库操作都封装发哦了Provider.一个单体拆分成多个,之间使用HTTP通信,每个项目又拆分成两个(Provider和Consumer),之间使用Dubbo协议通信.mapper和service写到provider中,service和controller写到consumer中.
微服务服务加购:每个业务是一个项目.业务之间通信使用HTTP协议通信.不再对一个业务(模块)项目进行拆分成Provider和Consumer了.mapper和service和controller都写道一个项目中
3.2目前市场上微服务架构的常用实现框架
实现框架:Spring Cloud
Spring Cloud里面目前包含三体体系:
Spring Cloud Netflix:学习这个.目前市场上使用最多的
Spring Cloud Alibaba:基于Dubbo实现的
Spring 自己的:为了摆脱受Netflix公司限制,所有功能都自己又逐渐推出一套
二.Spring Cloud简介
Spring Cloud是Spring旗下的一个顶级项目.它没有具体内容,单里面包含了很多二级子项目,Spring Cloud就是这些二级子项目的统称
Spring Cloud包含了很多二级子项目,每个二级子项目都有对应的功能,所以Spring Cloud整体包含的功能是比较强大
我们主要学习的是Spring Cloud Netflix相关框架
强调:Spring Cloud是完全基于Spring Boot的.官方文档中就没有XML配置版本
1.Netflix简介
Netflix(Nasdaq NFLX)成立于1997年,是一家在线影片租赁提供商,主要提供Netflix超大数量的DVD并免费递送,总部位于美国加利福尼亚
Spring Cloud集成时会把Netflix的软件进行打包成一个依赖,我们项目依赖了对应的jar,可以直接使用这个软甲,免去了软件安装的过程(这也是Spring Cloud非常大的优点)
三.Spring Cloud和Dubbo的对比
Spring Cloud和Dubbo(Spring Cloud Alibaba)都是微服务开发框架.不是新的技术就一定是好的技术.Dubbo优势在于开发简单,效率高.Spring Cloud优势在于工能全面且可靠性高
1.Spring Cloud下是哪个阵营对比
四.Spring Cloud版本号说明
1.常见版本号说明
开发中,使用的框架爱版本,最好是RELEASE版本或Final版本
常见版本号格式为:x.y.z.stage
x-数字格式主版本号,当功能模块有较大更新或者整体架构发生变化时,主版本号会更新
y-数字格式次版本号.此版本表示只是局部的一些变动
z-数字格式修正版本号,一般是bug的修复或者是小的变动
stage-希腊字母版本号,也称为阶段版本号.用于标注当前版本的软件处于哪个开发阶段.常用的阶段版本包括:BASE,ALPHA,BATE,RELEASE/FINAL
BASE-设计阶段.只有相应的设计没有具体的功能实现
ALPHA-软件的初级版本.存在较多的bug
BATE-表示相对ALPHA有了很大的进步.消除了严重的bug,还存在一些潜在的bug
RELEASE.FINAL-该版本表示最终版,即正式发布版本
2.Spring Cloud版本号说明
Spring Cloud是一个包含若干子框架的框架集合体,是一个完整的微服务框架体系,如果使用场景版本号来进行标记,容易混淆主框架版本和子框架版本标记.所以Spring Cloud使用一种全新的版本号来对框架进行版本标记,而框架的版本标记大多还是使用常用版本号标记的
Spring Cloud版本格式如:版本号命名.stage
版本号命名:Srping Cloud主框架版本号使用英国伦敦地铁站名称来进行标记的,并根据地铁站名称的首字母的英文自然升序排列来识别版本的递增.如:Angle,Brixton,Camden,Dalston,Edgware,Finchley,Greenwith,Hoxton等.后续版本提升会继续根据首字母升序排列
stage:阶段版本号.常用的阶段版本包括:BUILD-XXX[ANSPSHOT].GA.PRE(M1,M2等),RC,SR
BUILD-XXX[SNAPSHOT]-开发版本,一般是开发团队内部使用
GA-稳定版,内部开发到一定阶段了,各个模块集成后,经过全面测试发现没有问题,可对外发布了.这个时候叫GA(General Availability).基本上可以使用了.没有严重的bug问题,但是有未测出的bug隐患.不推荐商业使用
PRE-里程碑版,由于GA还不属于公开发行版,里面还有些功能不完善或者bug,于是就有了milestone(里程碑版).milestone版主要修复了一些bug.一个GA后,一般会有多个里程碑版.例如:M1,M2,M3.不推荐商业使用
RC-候选发布版,从BUILD后到GA在到M基本上系统就算定型了,这个时候系统就进入Release Candidate(候选发布版).该阶段的软件类似于最终发行前的一个观察期,该期间只对一些发现的等级高的bug进行修复.发布RC1 RC2等版本.可以考虑RC版本
SR-真实发布版,公开真实发布.真实发布版一般也有多个发布,例如SR1 SR2 SR3等,一般是用来修改大bug或者优化.最好使用SR版本
要注意:Spring Cloud是基于Spring Boot,不同的Spring Cloud要使用不同的Spring Boot版本.使用Spring Cloud H版本一定使用的是2.2.x不能使用2.3.x版本,如果使用2.3.x可能出现问题
附:Spring Data的版本命名也是和Spring Cloud一样的,Spring Data版本使用字母命名,里面子项目使用数字命名.因为Spring Data和Spring Cloud都是一系列框架的统称
五.Eureka简介
1.Eureka是什么
Eureka是由Netflix公司推出的服务注册和发现工具.现已被Spring Cloud集成,提供了开箱即用的支持(支持在项目中直接集成,会计使用)
2.Eureka角色
Eureka中分为两个角色:Eureka Server(Eureka服务)和Eureka Client(Eureka客户端)
无论是服务端还是客户端其本质都是一个Java项目,在Spring Cloud中主要通过启动类上添加@EnableEurekaServer和@EnableEurekaClient(可以省略)来区分当前应用程序是服务端还是客户端
Eureka Server可以理解成之前我们讲解的Zookeeper注册中心,只是现在使用的是Java项目实现的(Spring Cloud内嵌Eureka)
Eureka Client可以理解成所有需要注册到Eureka Server中的项目.为什么需要向注册中心呢?因为注册后别人才能通过注册中心获取到项目信息和项目所在服务器信息,通过这些信息调用这个项目.Spring Cloud中每个项目调用的信息都存储在了注册中心(Eureka)
注意:在这里,Spring Cloud中没有Provider和Consumer说法.如果A项目访问B项目,称A项目为Application Client,称B项目为Application Service.同时可能存在C访问A的情况,这是C项目是Aplication Client,A项目时Application Service.发现A项目又是Application Service又是Application Client,主要看针对哪个业务场景.无论是Application Service还是Application Client都是Eureka Client.
六.Eureka和Zookeeper对比(面试)
在Spring Cloud中可以使用Eureka作为注册中心.但是也可以通过配置的方式使用Zookeeper作为配置中心,既然都支持,就需要知道两者的区别
1.CAP理论(分布式一致性定理)
著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性),A(可用性)和P(分区容错性).由于分区容错性是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡.在此Zookeeper保证的是CP,而Eureka则是AP
C(一致性):在分布式系统中,是否立即达到数据同步的效果(平时多说的强一致性).在分布式系统一定最终会一致的.如果请求时,整个分布式系统同步后才返回结果,叫做强一致性(满足一致性).如果先返回结果,在一定时间后才实现一致性就叫做弱一致性
A(可用性):在分布式系统中,其中一些节点出现问题,整个整体是否还可用
P(分区容错性):在分布式系统中,是否可以在有限的时间内达到数据一致的效果,如果因为网络等问题最终没有达到一致性,这是称为出现分区错误
2.Zookeeper保证CP
在Zookeeper集群中,Zookeeper的数据保证的是一致性的.当leader出现问题时,整个Zookeeper不可用,需要花费30~120s来进行重新选择leader,当leader选举成功以后才能进行访问整个Zookeeper集群
通过这点也可以看出Zookeeper是强一致性的,集群所有节点必须能通信,才能用集群,虽然这样集群数据安全了,但是可用性大大降低了.而作为注册中心来说可用性是很重要的
3.Eureka保证AP
Eureka发现了Zookeeper的问题,所以它舍弃了Zookeeper中强一致性,而保证了可用性.在Eureka集群中所有的节点都是保存完整的信息的,当Eureka Client向Eureka中注册信息时,如果发现节点不可用,会自动切换到另一台Eureka Server,也就是说整个集群中即使只有一个Eureka可用,那么整个集群也是可用的
同时Eureka的自我保护机制也是实现可用性非常重要的体现
4.Zookeeper和Eureka对比(最完整的对比)
七.第一个Eureka Server
搭建Eureka Server时就相当于在安装Eureka软件(在Spring Cloud学习的一种全新方式,替换了之前需要安装对应软件的问题)
1.导入依赖
添加Spring Boot依赖和Spring Cloud集成的Eureka Server依赖.所有依赖的版本都是最新版
<parent>
<groupId>org.springframework.boot</groupdId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</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-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
2.编写配置文件
在application.yml中添加一下内容,不添加会报错
此处要求tomcat端口和Eureka Server的端口是相同的.Eureka Server默认端口是8761所以此处配置为8761,如果此处希望配置为8082等非8761端口,需要打开注释
eureka:
client:
# 因为当前项目为服务,不需要向服务注册自己,默认为true
register-with-eureka: false
# 因为当前为非集群版eureka,所以不需要同步其他节点数据
fetch-registry: false
# 当server.port配置不是8761时需要配置内容
# service-url:
# defaultZone: http://localhost:${server.port}/eureka/
server:
port: 8761
3.在启动类中添加注解
在启动类中添加@EnableEurekaServer注解,表示当前项目为Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class MyApplication{
public static void main(String[] args){
SpringApplication.run(MyApplication.class,args);
}
}
4.访问
在浏览器地址栏输入:http://localhost:8761/
八.Eureka服务管理平台介绍
1.Eureka Server服务管理平台访问预览
2.System Status
系统状态展示
3.DS Replicas
注册中心集群列表
4.Instances currently registered with Eureka
已在注册中心注册的服务列表
5.General Info
当前注册中心相关信息展示
6.当前注册中心实例化信息展示
九.第一个Eureka Client
Eureka Client可以向Eureka Server中注册自己
1.导入依赖
注意依赖换成了Eureka客户端依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<dependencyMenement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyMenement>
<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>
2.编写配置文件
在配置文件中添加配置
1.此处端口就是为了和其他项目不冲突而定的一个端口
2.spring.application.name为注册到eureka server后的名字.名字中不能使用下划线,苟泽可能出现无法注册的问题
3.如果Eureka Server配置的Server.port不是8761需要打开下面的注释,并且把url中端口号改成Eureka server中defaultZone配置的端口号.如果Eureka Server的端口号是8761,注释部分就可以省略
# 此处应该定义名称,否则注册到Server后的名字为UNKUOWN
spring:
application:
name:eureka-client
# eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost;8761/eureka/
3.编写启动类
启动类上的注解@EnableEurekaClient是可以省略的,平时不编写
@SpringBootApplication
public class EurekaClientApplication{
public static void main(String[] args){
SpringApplication.run(EurekaClientApplication.class,args);
}
}
4.观察结果
通过Eureka Server的可视化界面观察Eureka Client是否注册中心.如果注册成功会在页面中显示注册的client信息.
Application:配置文件中定义的应用程序名称
Status:UO表示正在执行,root客户端所在服务器的主机名,eureka-client定义应用程序名称,如果是8080端口省略,如果不是会显示在后面
十.Eureka集群实现原理
1.官方原理图
2.解释说明
所有Eureka Server通过Replicate进行数同步.无论Eureka Client向那个Eureka Server中注册信息,最终所有Eureka Server中都会存储注册的信息.这些信息都缓存到Eureka Server的本地.每个Eureka Server中同步后的数据都是完全相同的
Eureka Server向Eureka Server注册信息的时候我们称它为Application Service,当获取注册信息时称为Application Client,由于可能出现某个Eureka Client即需要注册服务,又需要获取其他服务,所以很多Eureka Client既是Application Service又是Application Client.
Eureka Client启动后,每个30秒向Eureka Server发送一次心跳,证明自己的可用,可通过
修改心跳的间隔时间.当Eureka Server超过90秒没有收到提供者的心跳后,会认为这个提供者已经宕机,销毁实例.可以通过
修改时间.
如果从新启动Eureka Server,会销毁所有实例
3.自我保护机制
Eureka中有一种自我保护机制.当15分钟内超过85%的Eureka Client都没有正常的心跳包时,Eureka认为Server和Client之间出现了网络问题.这个时候将不在因为没有收到心跳而销毁实例.Eureka Client依然可以访问Server,但是Server不会把内容同步到其他Server中.当网络稳定后,Server会把注册的信息同步到其他Server中.
在Eureka中自我保护机制默认为开启的:
4.关闭自我保护
eureka:
server:
# 关闭自我保护
enable-self-preservation: false
# eviction-interval-timer-in-ms: 10000
十一:Eureka高可用集群搭建
最终效果:
编写一个项目通过不同的配置文件加载不同参数
最后把集群部署到服务器上,集群设定有两个Eureka Server安装到不同的服务器上
1.添加依赖
在集群中依赖和单机版依赖是完全相同的
为了后面打包发布到服务器中,所以同时也导入了Spring Boot打包插件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<dependencyMenement>
<dependencies>
<dependency>
<groupId>org.springframe.cloud</groupId>
<artifatId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyMenement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifatId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</aritfactId>
</plugin>
</plugins>
</build>
2.创建配置文件
Eureka集群可以使用Spring Boot多配置文件实现.集群中创建几个Eureka Server就编写几个配置文件
Eureka集群是通过主机名相互访问的(不是通过IP相互访问)
spring:
application:
name: eureka1
server:
port: 8761
eureka:
instance:
# 和配置文件的applicaiont-xxx.yml相同
hostname: eurekaserver1
client:
service-url:
defaultZone: http://eurekaserver2:8761/eureka/
spring:
application:
name: eureka2
server:
port: 8761
eureka:
instance:
# 和配置文件的application-xx.yml相同
hostname: eurekaserver2
client:
service-url:
defaultZone: http://eurekaserver1:8761/eureka/
3.编写启动器
@SpringBootApplication
@EnableEurekaServer
public class EurekaClusterApplication{
public static void main(String[] args){
SpringApplication.run(EurekaClusterApplication.class,args);
}
}
4.打包
使用IDEA中MAVEN的命令进行打包
打包后在项目的target中出现打包后的jar
5.配置域名解析
修改Linux服务器中/etc/hosts文件.每行前面的ip是jar所在服务器的ip,后面的名称是项目中配置的hostname值
192.168.232.132 eurekaserver1
192.168.232.132 eurekaserver2
6.使用命令运行
把eureka1-1.0-SNAPSHOT.jar上传到LINUX服务器中.使用命令运行java -jar -Dspring.profiles.active=配置文件变量名 打包后jar包名称
java -jar -DSPRING.PROFILES.ACTIVE=EUREKASERVER1 EUREKA1-1.0-snapSHOT.jar
如果角色每次编写命令不方便可以编写SHELL脚本文件.在jar包所在文件夹中新建startup.sh文件.编写内容后授权
# !/bin/bash
cd dirname $0
CUR_SHELL_DIR=pwd
CUR_SHELL_NAME=basename ${BASH_SOURCE}
jar_name="项目jar包名称"
JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME
#JAVA_NEM_OPTS="-server -Xms1024m -Xms1024m -XX:PermSize=128m"
JAVA_MEM_OPTS=""
SPRING_PROFILES_ACTIV="-dSPRING.PRIFILES.ACTIVE=配置文件变量名称"
#SPRING_PROFILES_ACTIVE=""
LOG_DIR=$CUR_SHELL_DIR/logs
LOG_PATH=$LOG_DIR/eureka-server.log
echo_help(){
echo -e "syntax:sh $CUR_SHELL_NAME start|stop"
}
if[-z$1];then
echo_help
exit 1
fi
if[!-d "$LOG_DIR"];then
mkdir "$LOG_DIR"
fi
if[!-d"$LOG_DIR"];then
mkdir "$LOG_DIR"
fi
if[!-f "$LOG_PATH"];then
touch "$LOG_DIR"
fi
if ["$1"=="start"];then
# check server
PIDS=ps --no-heading -C java -f --width 1000|grep $ JAR_NAME | awk{print$2}
if[-n "$PIDS"];then
echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
exit 1
fi
echo "sTARTING THE $JAR_NAME..."
# start
nohup java $JAVA_MENOPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH>>$LOG_PATH 2>&1 &
count=0
while [$COUNT -lt 1];do
sleep 1
COUNT=ps --no-heading -C java -f --width 1000|grep "$JAR_NAME" | awk {print $2}| wc -l
if[$COUNT -gt 0];then
break
fi
done
PIDS=ps --no-heading -C java -f --width 1000|grep "$JAR_NAME" | awk {print $2}
echo "${JAR_NAME} Started and the PID is ${PIDS}."
echo "You can check the log file in ${LOG_PATH} for details."
else if["$1"=="stop"];then
PIDS=ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk {print $2}
if[-z "$pids"];then
echo "ERROR:The $JAR_NAME does not started!"
exit 1
fi
echo -e "Stopping the $JAR_NAME..."
for PID in $PIDS;do
kill $PID>/dev/null 2>&1
done
COUNT=0
while [$COUNT -lt 1];do
sleep 1
COUNT=1
for PID in $PIDS ;do
PID_EXIST=ps --no-heading -p $PID
if[-n "$PID_EXIST"];then
COUNT=0
break
fi
done
done
echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
else
echo_help
exit 1
fi
7.测试集群效果
7.1修改windows的域名解析
修改C:\Windows\System32\drivers\etc\hosts文件
192.168.232.132 eurekaserver1
192.168.232.132 eurekaserver2
7.2向集群中注册Eureka Client
修改上面编写的第一个Eureka Client项目的配置文件
写在defaultZone中优先向第一个URL注册自己,如果不可用才向第二个注册自己
eureka:
client:
service-url:
defaultZone:
http://eurekaserver1:8761/.http://eurekaserver2:8761/eureka/
十二.Eureka优雅关机
注意:Actuator和Eureka没有任何关系.放在这除了实现Eureka关机的效果以外,更重要是给同学们讲解Actuator的用法
可以借助Spring Boot提供的Actuator(监视器,监控中心)实现Eureka的优雅关机
Spring Cloud基于Spring Boot,Actuator关闭Spring Boot项目,SpringBoot项目都关闭了,Eureka Server项目也关闭了
spring-cloud-starter-netflix-eureka-server默认依赖了Actuator,就不需要导入额外包.正常是需要导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在配置文件中开启shutdown功能即可
manament:
endpoints:
#所有功能默认开启
enabled-by-default: true
# 显示所有哦已启用功能
web:
exposure:
include: '*'
Acturtor中所有工鞥呢只提供了post方式
使用postman发送POST请求
http://localhost:8761/actuator/shutdown