Spring Cloud / Alibaba 微服务架构实战—张勤一
微服务架构思想
不要浮于表面,学习并不是死记硬背,先去认识、再去理解、再到精通。这个过程肯定需要大量的时间,不要急于求成,慢慢来!
在做任何一件事之前,先从全局的角度分析这件事的可行性、难度、可能会遇到的问题等,直白的说,就是让自己心里有底。千万不要等到事情做到一半,发现还有各种各样无法解决的难题,最后造成 delay 甚至是延期交付
目标:
- 直面微服务落地中的各种问题,制定解决方案
- 深究微服务工程架构设计,提高代码复用性
- 落地企业级开发实战,透视微服务思想
收获:
- 掌握微服务开发框架及企业级常用组件的集成与应用
- 掌握微服务工程架构设计原则、业务拆分思想
- 具备制定和实施微服务工程解决方案的能力
方法:
- 不要着急编码,先搞清楚原则与套路
- 主动思考,提出更好的解决方案
- 学以致用,站在巨人肩膀前行
使用 SpringCloud 框架,Alibaba 套件
微服务简介
微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制通常用HTTP资源API。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术
特性:
- 每个微服务可独立运行在自己的进程(Tomcat)里
- 一系列独立运行的微服务共同构建起整个系统
- 每个服务为独立的业务开发,一个微服务只关注某个特定的功能,例如订单管理、用户管理等
- 可使用不同的语言与数据存储技术
- 微服务之间通过轻量的通信机制进行通信,例如通过REST API进行调用
- 全自动的部署机制
优点:
- 单个服务更易于开发、维护
- 单个微服务启动较快
- 局部修改容易部署
- 技术栈不受限
- 按需伸缩
缺点:
- 运维要求高
- 分布式固有的复杂性
- 重复劳动
应用场景:
- 大型、复杂的项目
- 有快速迭代的需求
- 访问压力比较大
微服务架构遵循的原则:
- 微服务架构能够带来的收益
- 合理、正确的将单体应用迁移到微服务
- 单个的微服务,可以选择一门你擅长的语言去开发,扩展性强
- 对于整个应用而言,代码不再耦合,不会出现大量的冲突
- 微服务可以重用,应用发布时间可控性更强
- 通过故障隔离,让错误在微服务中降级,不会影响到整个应用(或其他服务)
建议的最佳实践
- 职责独立:毎个微服务只做自己功能范围內的事,微服务之间的依赖链不要过长,建议单个微服务的依赖链路不要超过3
- 使用熔断器实现快速的故障容错和线程隔离,例如 Hystrⅸ、Sentinel
- 通过网关代理微服务请求,网关是微服务架构对外暴露的唯一入口
- 确保微服务 API 变更后能够向后兼容
微服务的路径和方向:
- 微服务是很多模块、组件共同组成,要针对每一个组件系统性的学习(要分清主次,不要想着面面俱到)
- 理清楚业务,要知道你在做什么;要对整体的脉络有个清晰的认知,而不是自己做的那一块事
- 深入实践,只有真正去写、去做,才知道自己哪里比较薄弱
- 针对于单个技术点的学习,可以简单写一些小的 demo,验证、学习这些知识点的特性和使用方法
- 将所学习的单个知识点应用到整体的业务实践,构建微服务系统,完成基本的业务逻辑
- 不断的优化、重构、调整,丰富其业务功能的同时,更要增强其对外服务的能力
区分开单体服务与 Maven 多模块管理的工程
使用 Maven 多模块管理的方式去构建整个工程
hefery-mall-project
mall-common
pom.xml
mall-data
pom.xml
mall-service
pom.xml
mall-web
pom.xml
pom.xml
hefery-mall-project
仍然是单体工程,并不是微服务,类似于 common
、data
只是这个单体工程的模块。它们最终都会打包到一个jar
中去部署、执行
服务架构的演进
单体应用架构
- 特点:将所有功能都部署在一起,以减少部署节点和成本
- 优点:项目架构简单;开发、部署、上线非常简单,前期开发成本低、周期短,小型项目首选
- 缺点:对于大型项目不易开发、拓展和维护,代码耦合严重、牵一发而动全身
垂直应用架构
- 特点:将原来的一个应用拆成互不相干的几个应用,以提升效率,模块一套(数据库、Tomcat……)部署
- 优点:
- 项目架构简单;前期开发成本低、周期短,小型项目首选;服务、部署独立,水平扩展容易;不同的项目可以采用不同的技术
- 系统拆分实现了流量分担,解决了高并发问题,而且可以针对不同模块进行优化和水平扩展
- 一个系统的问题不会影响到其他系统,提高容错率
- 缺点:
- 对于大型项目不易开发、拓展和维护;系统性能拓展只能通过拓展集群节点,成本高,有瓶颈;搭建复杂,服务之间关系错综复杂
- 系统之间相互独立, 无法进行相互调用,会有重复的开发任务
分布式架构
- 定义:分布式架构就是多个子系统互相协作才能完成整个业务流程,系统之间需要进行通信。集群就是同一个工程部署到多台服务器上
- 特点:分布式、可重用、扩展灵活、松耦合
- 优点:
- 可以根据需求通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用
- 抽取公共的功能为服务,提高开发效率,应用之间交互不可避免,将核心业务抽取出来,转变为通用独立的业务服务,实现业务逻辑的快速复用
- 对不同的服务进行集群化部署解决系统压力,基于ESB/DUBBO减少系统耦合
- 缺点:
- 抽取服务的粒度较大
- 服务提供方与调用方接口耦合度较高
SOA架构
SOA(Service-Oriented Architecture,面向服务的架构),着重中央管理
- 优点:使用注册中心解决了服务间调用关系的自动调节
- 缺点:
- 服务间会有依赖关系,一旦某个环节出错会影响较大( 服务雪崩 )
- 服务关心复杂,运维、测试部署困难
微服务架构
- 特点:
- 将众多单体应用根据业务拆分为各个功能模块,每个模块单独运行在自己的容器,使用轻量级机制(RESTful)进行通讯
- 业务需要彻底的组件化和服务化,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成
- 优点:通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降
- 缺点:微服务过多,服务治理成本高,不利于系统维护;分布式系统开发的技术成本高(容错、分布式事务等)
SpringCloud演进
发展历程 | 中心 | 功能 |
---|---|---|
Spring | Bean | IOC、AOP |
Spring Boot | Application | 自动配置、监控 |
Spring Cloud | Service | 服务注册与发现、微服务调用与负载均衡 |
学习、搞明白 IOC 和 AOP
学习 SpringBoot 的各种特性
找一些简单的项目、工程练手(业务不重要,学习其用法、思路和架构)
在工作实践中提升(把你所学的应用于生产,就是最大的进步)
微服务核心概念
CAP原理
分布式系统的最大难点:各个节点的状态如何同步。CAP定理是这方面的基本定理
CAP原理 | 中文释义 | 说明 |
---|---|---|
Consistency | 一致性 | 多节点数据同步 |
Availability | 可用性 | 部署多节点集群,保持服务可用(在集群部分节点故障后,集群整体还能响应客户端的读写请求) |
Partition tolerance | 分区容忍性 | 可以将数据存到多个地方,某个节点的故障并不影响整个系统的运行 |
在分布式系统中,只可同时满足二点,分区容忍性和可用性是最基本的需求,所以最当关注的就是AP,通过补偿的机制寻求数据的一致性
CAP | 说明 | 样例 |
---|---|---|
CA | 放弃分区容错性,加强一致性和可用性 | 传统的关系型数据库 |
AP | 放弃强一致性,追求分区容错性和可用性,可短暂允许数据不一致 | 分布式系统设计(Eureka)、NoSQL |
CP | 放弃可用性,追求一致性和分区容错性 | Consul,网络问题会直接让整个系统不可用 |
主要Q&A
微服务拆分与编写
微服务拆分方法
DDD
领域驱动设计(Domain Driven Design, DDD),软件架构设计方法,它并不定义软件开发过程(DevOps)
理解:DDD利用面向对象的特性,以业务为核心驱动,而不是传统的数据库/表驱动开发
概念
- 领域:就是业务。对功能需求的划分,大的领域下面还有许多小的子领域 大的领域(电商领域)-子领域(商品、订单、账户、物流)
- 领域建模:
- 分析领域模型,推演实体(domain)、值对象(dto)、领域服务(service)
- 找出聚合边界(降低服务耦合)
- 为聚合配备存储仓库(数据持久化)
- 实践DDD,并不断推倒和重构
- 单一职责:order
- 通用划分:common。最重要的,要搞清楚哪些代码和配置是各个模块通用的,注意边界
康威定律
面向对象(by name.-状态/ by verb.-行为)
业务依赖
什么是『合理的』微服务呢?与『不合理』的评价标准是什么呢?
微服务拆分粒度
- 良好地满足业务
- 增量迭代
- 运维幸福
- 持续进化
服务治理—如何管理微服务
服务治理相关概念
- 服务提供者服务的被调用方(即:为其他微服务提供接口的微服务)
- 服务消费者服务的调用方(即:调用其他微服务接口的微服务)
- 服务治理:服务自动化管理,用于实现各个微服务的自动化注册与发现
- 服务注册:服务实例将自身服务信息注册到注册中心。这部分服务信息包括服务所在主机IP和提供服务的Port,以及暴露服务自身状态以及访问协议等信息
- 服务发现:服务实例请求注册中心获取所依赖服务信息。服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务
- 服务剔除:服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用
服务治理注册中心
注册中心 | 开发语言 | CAP | 一致性算法 | 服务健康检查 | 对外暴露接口 | 描述 |
---|---|---|---|---|---|---|
Eureka | Java | AP | 无 | 可配支持 | HTTP | Spring Cloud Netflix,主要做服务注册和发现 |
Nacos | Java | AP | Raft | 支持 | HTTP | Eureka+Config |
Consul | Go | CP | Raft | 支持 | HTTP/DNS | 服务化系统提供服务注册发现和配置管理功能 |
Zookeeper | Java | CP | Paxos | 支持 | 客户端 | 解决分布式应用中经常遇到的==数据管理==问题 |
注册中心作用:
- 服务发现
- 服务注册/反注册:保存服务提供者和服务调用者的信息
- 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
- 服务路由(可选):具有筛选整合服务提供者的能力
- 服务配置
- 配置订阅:服务提供者和服务调用者订阅微服务相关的配置
- 配置下发:主动将配置推送给服务提供者和服务调用者
- 健康检测
- 检测服务提供者的健康情况
服务调用—微服务间如何通讯
服务调用概念
- 服务调用:基于HTTP的RESTful接口、基于TCP的RPC协议
- 服务提供者:服务的被调用方(为其他微服务提供接口的微服务)
- 服务消费者:服务的调用方(调用其他微服务接口的微服务)
服务调用方式
远程调用:序列化(json、xml、thrift、text、bytes等) + 通信协议(RESTful接口、RPC协议)
基于HTTP的RESTful接口
REST(Representational State Transfer)架构,使用 RestTemplate
-
资源(Resources),网络上的一个具体信息,用URI(统一资源定位符)指向,每种资源对应一个URI。要获取这个资源,访问它的URI即可
- 表现层(Representation),资源具体呈现出来的形式——后缀名(URI应该只代表资源的位置,不代表它的形式)
- 状态转化(State Transfer),GET用来获取资源,POST用来新建资源(也可用于更新资源),PUT用来更新资源,DELETE用来删除资源
-
客户端和服务器之间,传递这种资源(URI)的某种表现层
- 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"
HTTP | RestTemplate方法 |
---|---|
GET | T getForObject(String url, Class<T> responseType, Object... ) |
ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... ) | |
POST | URI postForLocation(String url, @Nullable Object request, Object... ) |
T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... ) | |
PUT | void put(String url, @Nullable Object request, Object... ) |
DELETE | void delete(String url, Object... ) |
HEAD | HttpHeaders headForHeaders(String url, Object... ) |
OPTIONS | Set<HttpMethod> optionsForAllow(String url, Object... ) |
ANY | ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... ) |
T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) |
基于TCP的RPC协议
RPC实现微服务通信的核心思想
- 全局注册表:将RPC支持的所有方法都注册进去
- 通过将Java对象进行编码(IDL,json,xml等等)+方法名传递(TCP/IP协议)到目标服务器实现微服务通信
优缺点:
- 目前市面上最流行的RPC框架有:gRPC、Thrift、Dubbo,有较多选择
- 性速度快、并发性能高
- 实现复杂(相对Rest 而言),需要做的工作与维护上更多(例如:Server的地址一般存储于Zookeeper上,就需要引入和维护ZK)
RPC(Remote Procedure Call),进程间的通信方式(Socket),允许像调用本地服务一样调用远程服务
- 主要目标就是让远程服务调用更简单、透明
- 屏蔽底层的传输方式(TCP/UDP)、序列化方式(XML/JSON/二进制)和通信细节
- 开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程
比较项 | RESTful | RPC |
---|---|---|
通讯协议 | HTTP | TCP/UDP |
协议性能 | 略低 | 较高 |
灵活度 | 高 | 低 |
架构应用 | 微服务架构 | SOA架构 |
Message
通过 Kafka、RocketMQ 等消息队列实现消息的发布与订阅(消费)
可以实现“削峰填谷”,缓冲机制实现数据、任务处理
最大的缺点是只能够做到最终一致性,而不能做到实时一致性。当然,这也是看业务需求
负载均衡—确保应用程序的高可用性
负载均衡概念
负载均衡:高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性
场景分类:
- 服务端:先发送请求到负载均衡服务器或者软件,然后通过负载均衡算法,在多个服务器之间选择一个进行访 问;即在服务器端再进行负载均衡算法分配
- 客户端:客户端会有服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器进行访问,这 是客户端负载均衡;即在客户端就进行负载均衡算法分配
负载均衡组件
负载均衡组件 | 描述 | 客户端/服务器端 |
---|---|---|
Ribbon | 客户端 | |
Ngnix | 使用 Nginx 的反向代理和负载均衡可实现对API服务器的负载均衡及高可用 | 服务端 |
服务容错—出现问题,系统如何自处理
服务容错概念
服务容错:一个请求经常调用几个服务,如果某个服务不可用,极有可能造成一连串服务不可用
核心思想:不被外界环境影响、不被上游请求压垮、不被下游请求拖垮
熔断:在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施
服务容错组件
容错组件 | 描述 |
---|---|
Hystrix | 用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性 |
Sentinel | 以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性 |
服务网关—客户端怎么访问
服务网关概念
服务网关:将所有 API 调用统一接入到 API 网关,由网关统一接入和输出
基本功能:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力
随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:
- 客户端需要调用不同的 URL 地址,增加难度
- 再一定的场景下,存在跨域请求的问题
- 每个微服务都需要进行单独的身份认证
服务网关组件
服务网关组件 | 描述 |
---|---|
Gateway | 内置了很多实用的功能,例如转发、监控、限流等,设计优雅,容易扩展 |
Zuul | Netflix开源的网关,无法动态配置;依赖组件较多,处理 HTTP请求依赖Web容器,性能不如Nginx |
链路追踪—出现问题,应该如何排查错误
链路追踪概念
链路追踪:对一次请求涉及的多条服务链路进行日志记录和性能监控
链路追踪组件
Sleuth:Spring Cloud提供的分布式系统中链路追踪解决方案
Zipkin:分布式的跟踪系统,收集服务定时数据,解决微服务中的延迟问题(数据收集、存储、查找和展现)