目录
1.系统架构演变
1.1. 集中式架构
1.2.垂直拆分
1.3.分布式服务
1.4.服务治理(SOA)
1.5.微服务
微服务结构图 :
微服务的特点:
微服务和SOA比较:
2.远程调用方式
服务间远程调用方式有哪些?
2.1.认识RPC
2.2.认识HTTP
2.3.如何选择?
3.Spring Cloud简介
3.1.简介
3.2.版本
4.微服务场景模拟
4.1. 创建父工程
4.2.服务提供者
4.2.1.创建Module
4.2.2.编写配置文件
4.2.3.编写代码
4.2.4. 启动并测试
4.3.服务调用者
4.3.1.创建工程consumer-demo
4.3.2.编写代码
4.3.3.启动测试:
5.4.上述有哪些问题
6.Eureka注册中心
6.1.Eureka简介
6.2.原理图
6.3.入门案例
6.3.2. 服务注册
6.3.3. 服务发现
6.4.Eureka详解
6.4.1.基础架构
6.4.2.搭建高可用的Eureka Server
1.系统架构演变
随着互联网的发展,网站应用的规模不断扩大,需求的激增,随之而来的是技术上的压力。系统架构也因此不断的演进、升级、迭代。从单一应用,到垂直拆分,到分布式服务,到SOA
,以及现在火热的微服务架构。
1.1. 集中式架构
当网站流量很小时,只需要一个应用,将所有的功能都部署在一起,以减少部署节点和成本。
优点: 系统开发速度快 维护成本低 适用于并发要求较低的系统 缺点: 代码耦合度高,后期维护困难 无法针对不同模块进行优化 无法水平扩展 单点容错率低,并发能力差1.2.垂直拆分 当访问量逐渐增大,单一应用无法满足需求,此时为了应对更高的并发和业务需求,我们根据业务功能对系统进行拆分
优点: 系统拆分实现了流量分担,解决了并发问题 可以针对不同模块进行优化 方便水平扩展,负载均衡,容错率提高 缺点: 系统间相互独立,会有很多重复开发工作,影响开发效率1.3.分布式服务
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式调用是关键。
优点:
将基础服务进行了抽取,系统间相互调用,提高了代码复用和开发效率
缺点:
系统间耦合度变高,调用关系错综复杂,难以维护
1.4.服务治理(SOA)
SOA
(
Service Oriented Architecture
)面向服务的架构:它是一种设计方法,其中包含多个服务, 服务之间通过相互依赖最终提供一系列的功能。一个服务通常以独立的形式存在于操作系统进程中。各个服务之间通过网络调用。
SOA 缺点:每个供应商提供的 ESB 产品有偏差,自身实现较为复杂;应用服务粒度较大, ESB 集成整合所有服务和协议、数据转换使得运维、测试部署困难。所有服务都通过一个通路通信,直接降低了通信速度。
1.5.微服务
微服务架构是使用一套小服务来开发单个应用的方式或途径,每个服务基于单一业务能力构建,运行在自己的进程 中,并使用轻量级机制通信,通常是HTTP API
,并能够通过自动化部署机制来独立部署。这些服务可以使用不同的 编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。
微服务结构图 :
微服务的特点:
单一职责:微服务中每一个服务都对应唯一的业务能力,做到单一职责
面向服务:面向服务是说每个服务都要对外暴露服务接口
API
。并不关心服务的技术实现,做到与平台和语言无关,也不限定用什么技术实现,只要提供REST
的接口即可。
自治:自治是说服务间互相独立,互不干扰
团队独立:每个服务都是一个独立的开发团队。
技术独立:因为是面向服务,提供
REST
接口,使用什么技术没有别人干涉
前后端分离:采用前后端分离开发,提供统一
REST
接口,后端不再为
PC
、移动段开发不同接口
数据库分离:每个服务都使用自己的数据源
微服务和SOA比较:
微服务的特点:
单一职责:微服务中每一个服务都对应唯一的业务能力,做到单一职责
面向服务:面向服务是说每个服务都要对外暴露服务接口
API
。并不关心服务的技术实现,做到与平台和语言无关,也不限定用什么技术实现,只要提供REST
的接口即可。
自治:自治是说服务间互相独立,互不干扰
团队独立:每个服务都是一个独立的开发团队。
技术独立:因为是面向服务,提供
REST
接口,使用什么技术没有别人干涉
前后端分离:采用前后端分离开发,提供统一
REST
接口,后端不再为
PC
、移动段开发不同接口
数据库分离:每个服务都使用自己的数据源
微服务和SOA比较:
2.远程调用方式
服务间远程调用方式有哪些?
无论是微服务还是
SOA
,都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢?
常见的远程调用方式有以下几种:
RPC:
Remote Procedure Call
远程过程调用,类似的还有
RMI
。自定义数据格式,基于原生
TCP
通信,速度快,效率高。早期的Web Service
,现在热门的
Dubbo
,都是
RPC
的典型。
HTTP
:
HTTP
其实是一种网络传输协议,基于
TCP
,规定了数据传输的格式。现在客户端浏览器与服务端通信 基本都是采用HTTP
协议。也可以用来进行远程服务调用。缺点是消息封装臃肿。
现在热门的
REST
风格,就可以通过
HTTP
协议来实现。
2.1.认识RPC
RPC
,即
Remote Procedure Call
(远程过程调用),
是一个计算机通信协议
。 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。说得通俗一点就是:
A计算机提供一个服务,B计算机可以像调用本地服务那样调用A计算机的服务,调用过程通过动态代理隐藏实现细节
。
RPC调用流程图:
2.2.认识HTTP
HTTP
其实是一种网络传输协议,基于
TCP
,工作在应用层,规定了数据传输的格式。现在客户端浏览器与服务端通 信基本都是采用HTTP
协议,也可以用来进行远程服务调用。
缺点是消息封装臃肿,优势是对服务的提供和调用方 没有任何技术限定,自由灵活,更符合微服务理念。
现在热门的REST
风格,就可以通过
HTTP
协议来实现。
2.1.认识RPC
RPC
,即
Remote Procedure Call
(远程过程调用),
是一个计算机通信协议
。 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。说得通俗一点就是:
A计算机提供一个服务,B计算机可以像调用本地服务那样调用A计算机的服务,调用过程通过动态代理隐藏实现细节
。
RPC调用流程图:
2.2.认识HTTP
HTTP
其实是一种网络传输协议,基于
TCP
,工作在应用层,规定了数据传输的格式。现在客户端浏览器与服务端通 信基本都是采用HTTP
协议,也可以用来进行远程服务调用。
缺点是消息封装臃肿,优势是对服务的提供和调用方 没有任何技术限定,自由灵活,更符合微服务理念。
现在热门的REST
风格,就可以通过
HTTP
协议来实现。
2.3.如何选择? RPC 的机制是根据语言的 API ( language API )来定义的,而不是根据基于网络的应用来定义的。如果你们公司全部采用Java 技术栈,那么使用 Dubbo 作为微服务架构是一个不错的选择。 相反,如果公司的技术栈多样化(产品用java和c等实现),而且你更青睐 Spring 家族,那么 Spring Cloud 搭建微服务是不二之选。会选择Spring Cloud套件,因此会使用 HTTP 方式来实现服务间调用,它可以实现语言无关和平台无关。
3.Spring Cloud简介
为什么要学习Spring Cloud
在项目开发中随着业务越来越多,导致功能之间耦合性高、开发效率低、系统运行缓慢难以维护、不稳定。微服务架构可以解决这些问题,而Spring Cloud 是微服务架构最流行的实现3.1.简介
Spring Cloud是Spring旗下的项目之一,官网地址:http://projects.spring.io/spring-cloud/
Spring 最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。 Spring Cloud 也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括: Netflflix Eureka:注册中心 [juˈriːkə] Zuul :服务网关 现在使用gateway Ribbon:负载均衡 [ˈrɪbən] Feign:服务调用 [feɪn] Hystrix :熔断器 以上只是其中一部分,架构图: 简单介绍spring cloud的调用流程 一个调用请求,先经过网关进来,然后通过 Ribbon负载均衡选择一个服务,如果服务要调用其它服务可以使用Feign服务调用组件,所有的服务都注册在Eureka服务注册中心,服务的配置可以通过Config Server然后在Git上统一配置管理。3.2.版本 Spring Cloud 的版本命名比较特殊,因为它不是一个组件,而是许多组件的集合,它的命名是以 A 到 Z 为首字母的一 些单词组成( 其实是伦敦地铁站的名字 )
Spring Clound 和Spring Boot版本对应关系
4.微服务场景模拟
4.1. 创建父工程
微服务中需要同时创建多个项目,先创建一个父工程,后续的工程都以这个工程为父,使用Maven的聚合和继承。统一管理子工程的版本和配置。
先创建个空项目cbw-springcloud
pom.xml
4.0.0
org.example
cbw-springcloud
1.0-SNAPSHOT
user-service
consumer-demo
pom
org.springframework.boot
spring-boot-starter-parent
2.1.2.RELEASE
11
Greenwich.SR1
2.1.5
5.1.46
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
tk.mybatis
mapper-spring-boot-starter
${mapper.starter.version}
mysql
mysql-connector-java
${mysql.version}
org.projectlombok
lombok
org.springframework.boot
spring-boot-maven-plugin
注意:
spring clound
和
spring boot
的版本对应
greenwich
版本
clound
对应
spring boot 2.1.x
注意:注意聚合父工程
pom
这里已经对大部分要用到的依赖的版本进行了 管理,方便后续使用
注意: spring clound 和 spring boot 的版本对应 greenwich 版本 clound 对应 spring boot 2.1.x 注意:注意聚合父工程4.0.0 org.example cbw-springcloud1.0-SNAPSHOT user-service consumer-demo pom org.springframework.boot spring-boot-starter-parent2.1.2.RELEASE 11 Greenwich.SR1 2.1.5 5.1.46 org.springframework.cloud spring-cloud-dependencies${spring-cloud.version} pom import tk.mybatis mapper-spring-boot-starter${mapper.starter.version} mysql mysql-connector-java${mysql.version} org.projectlombok lombokorg.springframework.boot spring-boot-maven-plugin
4.2.服务提供者
我们新建一个项目(module),对外提供查询用户的服务。
4.2.1.创建Module
选中cbw
-springclound
,创建子工程:user-service
pom.xml
文件
cbw-springcloud
org.example
1.0-SNAPSHOT
4.0.0
user-service
org.springframework.boot
spring-boot-starter-web
tk.mybatis
mapper-spring-boot-starter
mysql
mysql-connector-java
项目结构
项目结构cbw-springcloud org.example 1.0-SNAPSHOT 4.0.0 user-serviceorg.springframework.boot spring-boot-starter-webtk.mybatis mapper-spring-boot-startermysql mysql-connector-java
4.2.2.编写配置文件 application.yml 属性文件 , 这里我们采用了 yaml 语法,而不是properties:
导入springcloud.sql脚本
; ; ; ; ; ; CREATE DATAbase `springcloud` ; USE `springcloud`; DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_name` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, `age` int(11) DEFAULT NULL, `sex` int(11) DEFAULT NULL, `birthday` date DEFAULT NULL, `created` date DEFAULT NULL, `updated` date DEFAULT NULL, `note` varchar(2000) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; insert into `tb_user`(`id`,`user_name`,`password`,`name`,`age`,`sex`,`birthday`,`created`,`updated`,`note`) values (1,'zhangsan','1','张三a',18,1,'2019-02-27','2019-02-27','2019-02-27','在学习Java...'), (2,'lisi','1','李四ab',18,1,'2019-02-27','2019-02-27','2019-02-27','在学习Java...'), (3,'wangwu','1','王五abc',18,1,'2019-02-27','2019-02-27','2019-02-27','在学习Java...'), (4,'fanbingbing','1','范冰冰aa',18,2,'2019-02-27','2019-02-27','2019-02-27','在学习Java...'), (5,'guodegang','1','郭德纲bb',18,1,'2019-02-27','2019-02-27','2019-02-27','在学习Java...'), (6,NULL,NULL,'周星驰cc',18,NULL,'2020-06-01','2020-06-01',NULL,NULL), (7,'kaikeba',NULL,'开课吧',NULL,NULL,NULL,NULL,NULL,NULL); ; ; ; ;
4.2.3.编写代码 启动类
实体类
UserMapper
UserService
controller 对外提供 REST 风格 web 服务,根据 id 查询用户完成上述代码后的项目结构
4.2.4. 启动并测试 启动项目,访问 http://localhost:9091/user/1
4.3.服务调用者
4.3.1.创建工程consumer-demo
与上面类似,需要注意的是,我们调用
user-service
的功能,因此不需要
Mybatis
相关依赖了
pom
:
cbw-springcloud
org.example
1.0-SNAPSHOT
4.0.0
consumer-demo
org.springframework.boot
spring-boot-starter-web
4.3.2.编写代码
启动器:
Spring
提供了一个
RestTemplate
模板工具类,对基于
HTTP的客户端进行了封装,并且实现了对象
与json的序列化和反序列化,非常方便
。RestTemplate
并没有限定
HTTP
的客户端类型,而是进行了抽象,目前常用的
3
种都有支持:
HTTPClient
OkHTTP
JDK
原生的
URLConnection
(默认的)
实体类
cbw-springcloud org.example 1.0-SNAPSHOT 4.0.0 consumer-demoorg.springframework.boot spring-boot-starter-web
4.3.2.编写代码 启动器:
controller
4.3.3.启动测试: 因为我们没有配置端口,那么默认就是 8080 ,我们访问: http://localhost:8080/consumer/1
一个简单的远程服务调用案例就实现了。
5.4.上述有哪些问题
简单回顾一下,刚才我们写了什么:
user-service :对外提供了查询用户的接口 consumer-demo :通过 RestTemplate 访问 http://locahost:9091/user/ {id} 接口,查询用户数据存在什么问题?
在 consumer 中,我们把 url 地址硬编码到了代码中,不方便后期维护 consumer 需要记忆 user-service 的地址,如果出现变更,可能得不到通知,地址将失效 consumer 不清楚 user-service 的状态,服务宕机也不知道 user-service 只有 1 台服务,不具备高可用性 即便 user-service 形成集群, consumer 还需自己实现负载均衡 其实上面说的问题,概括一下就是分布式服务必然要面临的问题: 服务管理 如何自动注册和发现 如何实现状态监管 如何实现动态路由 服务如何实现负载均衡 服务如何解决容灾问题 服务如何实现统一配置 以上的问题,我们都将在 SpringCloud 中得到答案。6.Eureka注册中心
6.1.Eureka简介
问题分析
在刚才的案例中,user-service对外提供服务,需要对外暴露自己的地址。而consumer(调用者)需要记录服务提供者的地址。将来地址出现变更,还需要及时更新。这在服务较少的时候并不觉得有什么,但是在现在日益复杂的互联网环境,一个项目肯定会拆分出十几,甚至数十个微服务。此时如果还人为管理地址,不仅开发困难,将来测试、发布上线都会非常麻烦,这与DevOps的思想是背道而驰的。
网约车 这就好比是网约车出现以前,人们出门叫车只能叫出租车。一些私家车想做出租却没有资格,被称为黑车。而很多人想要约车,但是无奈出租车太少,不方便。私家车很多却不敢拦,而且满大街的车,谁知道哪个才是愿意载人的。一个想要,一个愿意给,就是缺少引子,缺乏管理啊。 此时滴滴这样的网约车平台出现了,所有想载客的私家车全部到滴滴注册,记录你的车型(服务类型),身份信息 (联系方式)。这样提供服务的私家车,在滴滴那里都能找到,一目了然。 此时要叫车的人,只需要打开 APP ,输入你的目的地,选择车型(服务类型),滴滴自动安排一个符合需求的车到你面前,为你服务,完美! Eureka做什么? Eureka 就好比是滴滴,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后 Eureka 会把符合你需求的服务告诉你。 同时,服务提供方与 Eureka 之间通过 “ 心跳 ” 机制进行监控,当某个服务提供方出现问题, Eureka 自然会把它从服务列表中剔除。 这就 实现了服务的自动注册、发现、状态监控6.2.原理图 基本架构:
Eureka :就是服务注册中心(可以是一个集群),对外暴露自己的地址 提供者:启动后向 Eureka 注册自己信息(地址,提供什么服务) 消费者:向 Eureka 订阅服务, Eureka 会将对应服务的所有提供者地址列表发送给消费者,并且定期更新 心跳 ( 续约 ) :提供者定期通过 HTTP 方式向 Eureka 刷新自己的状态 工作原理图解析
0.服务提供者实例化服务
1.服务提供者将服务注册到eureka注册中心
2.eureka中记录服务的信息包括url等
3.服务调用者定期从注册中心中拉取服务列表
4.服务调用者基于负载均衡算法从服务列表中选择一个服务地址调用服务
5.服务调用者定期向注册中心发送心跳机制(ping-pong)
6.注册中心检查哪些没有定期发送心跳续约的服务(宕机),将其在一定时间内剔除出服务列表。
6.3.入门案例
Eureka
是服务注册中心,只做服务注册;自身并不提供服务也不消费服务。可以搭建
Web
工程使用
Eureka
,可以使用Spring Boot
方式搭建。
1. pom.xml
cbw-springcloud
org.example
1.0-SNAPSHOT
4.0.0
eureka-server
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.
编写启动类:
3. 编写配置:
4. 启动服务,并访问: http://127.0.0.1:10086/ 出现eureka的web平台即说明eureka已经搭建成功。 报错 Caused by: java.lang.ClassNotFoundException: javax.xml.bind.ValidationException异常
问题分析:
JAXB API是java EE 的API,因此在java SE 9.0 中不再包含这个 Jar 包。java 9 中引入了模块的概念,默认情况下,Java SE中将不再包含java EE 的Jar包
而在 java 6/7 / 8 时关于这个API 都是捆绑在一起的.
解决方案:
引入下面依赖即可
jaxb-api maven地址:http://mvnrepository.com/artifact/javax.xml.bind/jaxb-api
jaxb-impl maven地址:http://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl
jaxb-core maven地址:http://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core
activation maven地址:http://mvnrepository.com/artifact/javax.activation/activation
javax.xml.bind jaxb-api2.3.0 com.sun.xml.bind jaxb-impl2.3.0 com.sun.xml.bind jaxb-core2.3.0 javax.activation activation1.1.1
6.3.2. 服务注册 在服务提供工程 user-service 上添加 Eureka 客户端依赖;自动将服务注册到 EurekaServer 服务地址列表。
1. 添加 Eureka 客户端依赖 2. 在启动类上开启 Eureka 客户端发现功能 通过添加 @EnableDiscoveryClient 来开启 Eureka 客户端功能 3. 编写配置注意: 这里我们添加了 spring.application.name 属性来指定应用名称,将来会作为应用的 id 使用。 不用指定 register-with-eureka 和 fetch-registry ,因为默认是 true 4.重启项目,访问 Eureka 监控页面 查看 发现 user-service 服务已经注册成功了
6.3.3. 服务发现 在服务消费工程 consumer-demo 上添加 Eureka 客户端依赖;可以使用工具类 DiscoveryClient 根据服务名称获取对应的服务地址列表。
1)添加依赖:
2)在启动类添加开启Eureka客户端发现的注解
3)修改配置:
4)修改代码,用DiscoveryClient类的方法,根据服务名称,获取服务实例:
服务地址不需要写死了。
启动user-service服务、eureka服务和consumer-service服务,发送请求调用服务consumer-service,服务consumer-service获取eureka中的指定的服务url来调用user-service服务生成的URL:
6.4.Eureka详解
讲解Eureka的原理及配置。
6.4.1.基础架构 Eureka 架构中的三个核心角色:
服务注册中心
Eureka 的服务端应用, 提供服务注册和发现功能 ,就是刚刚我们建立的 eureka-server 服务提供者 提供服务的应用 ,可以是 Spring Boot 应用,也可以是其它任意技术实现,只要对外提供的是 REST 风格服务即可。本例中就是我们实现的user-service 服务消费者 消费应用从注册中心获取服务列表,从而得知每个服务方的信息 ,知道去哪里调用服务方。本例中就是我们实现的consumer-demo6.4.2.高可用的Eureka Server Eureka Server 即服务的注册中心,在刚才的案例中,我们只有一个 EurekaServer ,事实上 EurekaServer 也可以是 一个集群,形成高可用的Eureka 中心 。
Eureka Server 是一个 web 应用,可以启动多个实例(配置不同端口)保证 Eureka Server 的高可用 服务同步 多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。 因此,无论客户端访问到Eureka Server 集群中的任意一个节点,都可以获取到完整的服务列表信息。 如果有三个 Eureka ,则每一个 EurekaServer 都需要注册到其它几个 Eureka 服务中。 例如:有三个分别为 10086 、 10087 、 10088 ,则:10086要注册到10087和10088上
10087要注册到10086和10088上
10088 要注册到 10086 和 10087 上 搭建高可用的EurekaServer 我们假设要搭建两条 EurekaServer 的集群,端口分别为: 10086 和 100871 )我们修改原来的 EurekaServer 配置:



