一、搭建一个微服务框架所需要哪些技术(spring-cloud)
搭建一个微服务框架所需要哪些技术:
1、Eureka用于服务的注册于发现
2、Feign支持服务的调用以及均衡负载
3、Hystrix处理服务的熔断防止故障扩散
4、Spring Cloud Config服务集群配置中心
5、Spring Cloud zuul提供负载均衡、反向代理、权限认证的一个API gateway
二、要搞定微服务架构,先搞定RPC框架
一、需求缘起
服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图:
服务A是欧洲团队提供服务,欧洲团队的技术背景是Java,可以用Java实现服务;
服务B是美洲团队提供服务,可以用C++实现服务;
服务C是中国团队提供服务,可以用Go实现服务;
服务的上游调用方,按照接口、协议即可完成对远端服务的调用。
但实际上,99.9%的公司的团队规模有限,技术团队人数也有限,基本是使用同一套技术体系来调用和提供服务的:
这样的话,如果没有统一的服务框架,RPC框架,各个团队的服务提供方就需要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理、状态机等“业务之外”的重复技术劳动,造成整体的低效。所以,统一RPC框架把上述“业务之外”的技术劳动统一处理,是服务化首要解决的问题。
在达成【“使用统一的RPC框架”是正确的道路】这个一致的前提下,本文期望用简单通俗的言语简述一下一个通用RPC框架的技术点与实现。
二、RPC背景与过程
什么是RPC(Remote Procedure Call Protocol),远程过程调用?
先来看下什么是本地函数调用,当我们写下:
int result = Add(1, 2);
这段代码的时候,我们知道,我们传入了1,2两个入参数,调用了本地代码段中的一个Add函数,得到了result出参。此时,传入数据,传出数据,代码段在同一个进程空间里,这是本地函数调用。
那有没有办法,我们能够调用一个跨进程(所以叫“远程”,典型的,这个进程部署在另一台服务器上)的函数呢?
最容易想到的,两个进程约定一个协议格式,使用Socket通信,来传输【入参】【调用哪个函数】【出参】。
假设请求报文协议是一个11字节的字节流:
(1)前3个字节填入函数名
(2)中间4个字节填入第一个参数
(3)末尾4个字节填入第二个参数
同时可以设计响应报文协议是一个4字节的字节流:
即处理结果。
调用方的代码可能变为:
request = MakePacket(“add”, 1, 2);
SendRequest_ToService_B(request);
response = RecieveRespnse_FromService_B();
int result = unMakePacket(respnse);
简单解释一下:
(1)讲传入参数变为字节流
(2)将字节流发给服务B
(3)从服务B接受返回字节流
(4)将返回字节流变为传出参数
服务方的代码可能变为:
request = RecieveRequest();
args/function = unMakePacket(request);
result = Add(1, 2);
response = MakePacket(result);
SendResponse(response);
这个过程也很好理解:
(1)服务端收到字节流
(2)将字节流转为函数名与参数
(3)本地调用函数得到结果
(4)将结果转变为字节流
(5)将字节流发送给调用方
这个过程用一张图描述如上,调用方与服务方的处理步骤都是非常清晰的。这个过程存在最大的问题是什么呢?
回答:调用方太麻烦了,每次都要关注很多底层细节
(1)入参到字节流的转化,即序列化应用层协议细节
(2)socket发送,即网络传输协议细节
(3)socket接受
(4)字节流到出参的转化,即反序列化应用层协议细节
能不能调用层不关注这个细节呢?
回答:可以,RPC框架就是解决这个问题的,它能够让调用方“像调用本地函数一样调用远端的函数(服务)”。
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
三、RPC框架职责
通过上面的讨论,RPC框架要向调用方屏蔽各种复杂性,要向服务提供方也屏蔽各类复杂性:
(1)调用方感觉就像调用本地函数一样
(2)服务提供方感觉就像实现一个本地函数一样来实现服务
所以整个RPC框架又分为client部分与server部分,负责把整个非(1)(2)的各类复杂性屏蔽,这些复杂性就是RPC框架的职责。
再细化一些,client端又包含:序列化、反序列化、连接池管理、负载均衡、故障转移、队列管理,超时管理、异步管理等等等等职责。
server端包含:服务端组件、服务端收发包队列、io线程、工作线程、序列化反序列化、上下文管理器、超时管理、异步回调等等等等职责。
however,因为篇幅有限,这些细节不做深入展开
三、微服务架构设计
微服务
软件架构是一个包含各种组织的系统组织,这些组件包括 Web服务器, 应用服务器, 数据库,存储, 通讯层), 它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。
Conway’s law: Organizations which design systems[...] are constrained to produce designs which are copies of the communication structures of these organizations.
(设计系统的组织,其产生的设计和架构等价于组织间的沟通结构。)
Monolithic架构
Monolithic比较适合小项目,优点是:
开发简单直接,集中式管理, 基本不会重复开发
功能都在本地,没有分布式的管理开销和调用开销。它的缺点也非常明显,特别对于互联网公司来说(不一一列举了):
开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
代码维护难:代码功能耦合在一起,新人不知道何从下手
部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
扩展性不够:无法满足高并发情况下的业务需求
微服务架构
微服务是指开发一个单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通讯机制,可以部署在单个或多个服务器上。微服务也指一种种松耦合的、有一定的有界上下文的面向服务架构。也就是说,如果每个服务都要同时修改,那么它们就不是微服务,因为它们紧耦合在一起;如果你需要掌握一个服务太多的上下文场景使用条件,那么它就是一个有上下文边界的服务,这个定义来自DDD领域驱动设计。
相对于单体架构和SOA,它的主要特点是组件化、松耦合、自治、去中心化,体现在以下几个方面:
一组小的服务
服务粒度要小,而每个服务是针对一个单一职责的业务能力的封装,专注做好一件事情。独立部署运行和扩展
每个服务能够独立被部署并运行在一个进程内。这种运行和部署方式能够赋予系统灵活的代码组织方式和发布节奏,使得快速交付和应对变化成为可能。独立开发和演化
技术选型灵活,不受遗留系统技术约束。合适的业务问题选择合适的技术可以独立演化。服务与服务之间采取与语言无关的API进行集成。相对单体架构,微服务架构是更面向业务创新的一种架构模式。独立团队和自治
团队对服务的整个生命周期负责,工作在独立的上下文中,自己决策自己治理,而不需要统一的指挥中心。团队和团队之间通过松散的社区部落进行衔接。
我们可以看到整个微服务的思想就如我们现在面对信息爆炸、知识爆炸是一样的:通过解耦我们所做的事情,分而治之以减少不必要的损耗,使得整个复杂的系统和组织能够快速的应对变化。
我们为什么采用微服务呢?
"让我们的系统尽可能快地响应变化" - Rebecca Parson
让我们的系统尽可能快地去响应变化。其实几十年来我们一直在尝试解决这个问题。如果一定要在前面加个限制的话,那就是低成本的快速响应变化。上世纪90年代Kent Beck提出要拥抱变化,在同期出现了诸多轻量级开发方法(诸如 XP、Scrum);2001年敏捷宣言诞生,之后又出现了精益、看板等新的管理方式。如果说,这些是为了尽快的响应变化,在软件开发流程和实践方面提出的解决方案,那么微服务架构就是在软件技术和架构层面提出的应对之道。
Autonomous
A Microservice is a unit of functionality; it provides an API for a set of capabilities oriented around a business domain or common utility
Isolated
A Microservice is a unit of deployment; it can be modified, tested and deployed as a unit without impacting other areas of a solution
Elastic
A Microservice is stateless; it can be horizontally scaled up and down as needed
Resilient
A Microservice is designed for failure; it is fault tolerant and highly available
Responsive
A Microservice responds to requests in a reasonable amount of time
Intelligent
The intelligence in a system is found in the Microservice endpoints not ‘on the wire’
Message Oriented
Microservices rely on HTTP or a lightweight message bus to establish a boundary between components; this ensures loose coupling, isolation, location transparency, and provides the means to delegate errors as messages
Programmable
Microservices provide API’s for access by developers and administrators
Composable
Applications are composed from multiple Microservices
Automated
The lifecycle of a Microservice is managed through automation that includes development, build, test, staging, production and distribution
服务之间如何通信
一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。RESTful和RPC的比较也是一个很有意 思的话题。一般REST基于HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要 求,只要封装了HTTP的SDK就能调用,所以相对使用的广一些。RPC也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个 的开发规范和统一的服务框架时,他的开发效率优势更明显些。就看各自的技术积累实际条件,自己的选择了。而异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能 保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要 实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验);最后就是必须引入一个独立的broker,如 果公司内部没有技术积累,对broker分布式管理也是一个很大的挑战。
微服务优点
- 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求。
- 微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。
- 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
- 微服务能使用不同的语言开发。
- 微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, bamboo 。
- 一个团队的新成员能够更快投入生产。
- 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
- 微服务允许你利用融合最新技术。
- 微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。
- 微服务能够即时被要求扩展。
- 微服务能部署中低端配置的服务器上。
- 易于和第三方集成。
- 每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。
微服务架构的缺点
- 微服务架构可能带来过多的操作。
- 需要DevOps技巧 (http://en.wikipedia.org/wiki/DevOps).
- 可能双倍的努力。
- 分布式系统可能复杂难以管理。
- 因为分布部署跟踪问题难。
- 当服务数量增加,管理复杂性增加。
需要考虑的问题
- 单个微服务代码量小,易修改和维护。但是,系统复杂度的总量是不变的,每个服务代码少了,但服务的个数肯定就多了。就跟拼图游戏一样,切的越碎,越难拼出整幅图。一个系统被拆分成零碎的微服务,最后要集成为一个完整的系统,其复杂度肯定比大块的功能集成要高很多。
- 单个微服务数据独立,可独立部署和运行。虽然微服务本身是可以独立部署和运行的,但仍然避免不了业务上的你来我往,这就涉及到要对外通信,当微服务的数量达到一定量级的时候,如何提供一个高效的集群通信机制成为一个问题。
- 单个微服务拥有自己的进程,进程本身就可以动态的启停,为无缝升级的打好了基础,但谁来启动和停止进程,什么时机,选择在哪台设备上做这件事情才是无缝升级的关键。这个能力并不是微服务本身提供的,而是需要背后强大的版本管理和部署能力。
- 多个相同的微服务可以做负载均衡,提高性能和可靠性。正是因为相同微服务可以有多个不同实例,让服务按需动态伸缩成为可能,在高峰期可以启动更多的相同的微服务实例为更多用户服务,以此提高响应速度。同时这种机制也提供了高可靠性,在某个微服务故障后,其他相同的微服务可以接替其工作,对外表现为某个设备故障后业务不中断。同样的道理,微服务本身是不会去关心系统负载的,那么什么时候应该启动更多的微服务,多个微服务的流量应该如何调度和分发,这背后也有一套复杂的负载监控和均衡的系统在起作用。
- 微服务可以独立部署和对外提供服务,微服务的业务上线和下线是动态的,当一个新的微服务上线时,用户是如何访问到这种新的服务?这就需要有一个统一的入口,新的服务可以动态的注册到这个入口上,用户每次访问时可以从这个入口拿到系统所有服务的访问地址。这个统一的系统入口并不是微服务本身的一部分,所以这种能力需要系统单独提供。
- 还有一些企业级关注的系统问题,比如,安全策略如何集中管理?系统故障如何快速审计和跟踪到具体服务?整个系统状态如何监控?服务之间的依赖关系如何管理?等等这些问题都不是单个微服务考虑的范畴,而需要有一个系统性的考虑和设计,让每个微服务都能够按照系统性的要求和约束提供对应的安全性,可靠性,可维护性的能力。
API为什么很重要
•服务价值的精华体现
•可靠、可用、可读
•只有一次机会
实现一个API网关作为所有客户端的唯一入口。API网关有两种方式来处理请求。有些请求被简单地代理/路由到合适的服务上,其他的请求被转给到一组服务。
相比于提供普适的API,API网关根据不同的客户端开放不同的API。比如,Netflix API网关运行着客户端特定的适配器代码,会向客户端提供最适合其需求的API。
API网关也可以实现安全性,比如验证客户端是否被授权进行某请求。
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
设计要素
•Version
•RequstID
•Auth&Signature
•RateLimit
•Docs
•ErrorCode&Message
微服务治理
•按需伸缩
–部署与监控运维成本
•独立部署
–机器数量与部署成本
•业务独立
–服务依赖、治理,版本管理、事务处理
•技术多样性
–环境部署成本、约定成本
•运行状态治理
–监控、限流、SLA、LB、日志分析
•服务注册与发现
•部署
–快速、复制、扩容
–单机开发
•调用
–安全、容错、服务降级、调用延时
服务容错
当企业微服务化以后,服务之间会有错综复杂的依赖关系,例如,一个前端请求一般会依赖于多个后端服务,技术上称为1 -> N扇出. 在实际生产环境中,服务往往不是百分百可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一后端一旦发生延迟,可能在数秒内导致所有应用资源(线程,队列等)被耗尽,造成所谓的雪崩效应(Cascading Failure),严重时可致整个网站瘫痪。
服务依赖
服务框架
- 服务注册、发现、负载均衡和健康检查,假定采用进程内LB方案,那么服务自注册一般统一做在服务器端框架中,健康检查逻辑由具体业务服务定制,框架层提供调用健康检查逻辑的机制,服务发现和负载均衡则集成在服务客户端框架中。
- 监控日志,框架一方面要记录重要的框架层日志、metrics和调用链数据,还要将日志、metrics等接口暴露出来,让业务层能根据需要记录业务日志数据。在运行环境中,所有日志数据一般集中落地到企业后台日志系统,做进一步分析和处理。
- REST/RPC和序列化,框架层要支持将业务逻辑以HTTP/REST或者RPC方式暴露出来,HTTP/REST是当前主流API暴露方式,在性能要求高的场合则可采用Binary/RPC方式。针对当前多样化的设备类型(浏览器、普通PC、无线设备等),框架层要支持可定制的序列化机制,例如,对浏览器,框架支持输出Ajax友好的JSON消息格式,而对无线设备上的Native App,框架支持输出性能高的Binary消息格式。
- 配置,除了支持普通配置文件方式的配置,框架层还可集成动态运行时配置,能够在运行时针对不同环境动态调整服务的参数和配置。
- 限流和容错,框架集成限流容错组件,能够在运行时自动限流和容错,保护服务,如果进一步和动态配置相结合,还可以实现动态限流和熔断。
- 管理接口,框架集成管理接口,一方面可以在线查看框架和服务内部状态,同时还可以动态调整内部状态,对调试、监控和管理能提供快速反馈。Spring Boot微框架的Actuator模块就是一个强大的管理接口。
- 统一错误处理,对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。
- 安全,安全和访问控制逻辑可以在框架层统一进行封装,可做成插件形式,具体业务服务根据需要加载相关安全插件。
- 文档自动生成,文档的书写和同步一直是一个痛点,框架层如果能支持文档的自动生成和同步,会给使用API的开发和测试人员带来极大便利。Swagger是一种流行Restful API的文档方案。
微服务系统底座
一个完整的微服务系统,它的底座最少要包含以下功能:
日志和审计,主要是日志的汇总,分类和查询
监控和告警,主要是监控每个服务的状态,必要时产生告警
消息总线,轻量级的MQ或HTTP
注册发现
负载均衡
部署和升级
事件调度机制
资源管理,如:底层的虚拟机,物理机和网络管理
以下功能不是最小集的一部分,但也属于底座功能:
认证和鉴权
微服务统一代码框架,支持多种编程语言
统一服务构建和打包
统一服务测试
微服务CI/CD流水线
服务依赖关系管理
统一问题跟踪调试框架,俗称调用链
灰度发布
蓝绿部署
容器(Docker)与微服务
•容器够小
–解决微服务对机器数量的诉求
•容器独立
–解决多语言问题
•开发环境与生产环境相同
–单机开发、提升效率
•容器效率高
–省钱
•代码/image一体化
–可复用管理系统
•容器的横向与纵向扩容
–可复制
–可动态调节CPU与内存
容器(Docker)与微服务
•Image管理
•系统安全管理
•授权管理
•系统成熟度
•社区成熟度
开发方式影响
随着持续交付概念推广以及Docker容器普及,微服务将这两种理念和技术结合起来,形成新的微服务+API + 平台的开发模式,提出了容器化微服务的持续交付概念。
下图传统Monolithic的DevOps开发队伍方式:
这种整体型架构要求产品队伍横跨产品管理 Dev开发 QA DBA 以及系统运营管理,而微服务架构引入以后,如下图:
微服务促进了DevOps方式的重组,将一个大臃肿的整体产品开发队伍切分为根据不同微服务的划分的产品队伍,以及一个大的整体的平台队伍负责运营管理,两者之间通过API交互,做到了松耦合隔绝。
- 首先需要考虑构建DevOps能力,这是保证微服务架构在持续交付和应对复杂运维问题的动力之源;
- 其次保持服务持续演进,使之能够快速、低成本地被拆分和合并,以快速响应业务的变化;
- 同时要保持团队和架构对齐。微服务貌似是技术层面的变革,但它对团队结构和组织文化有很强的要求和影响。识别和构建匹配架构的团队是解决问题的另一大支柱。
- 最后,打造持续改进的自组织文化是实施微服务的关键基石。只有持续改进,持续学习和反馈,持续打造这样一个文化氛围和团队,微服务架构才能持续发展下去,保持新鲜的生命力,从而实现我们的初衷。
微服务的实施是有一定的先决条件:基础的运维能力(如监控、快速配置、快速部署)需提前构建,否则就会陷入如我们般被动的局面。推荐采用基础设施及代码的实践,通过代码来描述计算和网络基础设施的方法,使得图案度i可以快速安全的搭建和处理由新的配置代替的服务器,服务器之间可以拥有更高的一致性,降低了在“我的环境工作,而你的环境不工作”的可能,也是为后续的发布策略和运维提供更好的支撑。
由于Docker引入,不同的微服务可以使用不同的技术架构,比如Node.js Java Ruby Python等等,这些单个的服务都可以独立完成交付生命周期,如下:
微服务案例
Netflix的微服务架构如下,着重全球分发 高可扩展性和可用性:
Twitter的微服务架构,注重高效的可扩展的数据中心:
四、轻量级微服务架构及最佳部署
一、微服务将变得轻量级
架构需要由人去设计,这些人被称为架构师。或许很多人并未授予架构师的头衔,但自己却从事着架构的工作。我们认为,架构这项工作永远都需要由人去完成,可能短期内都无法由机器来取代。如果我们不理解什么是架构,或者对架构师的职责感到疑惑,那么很难让架构这项工作有效地落地。我们将在本节重新认识架构,并重新定义架构师的职责。此外,架构演进是一个曲折的过程,但我们却不难看出架构的发展规律,甚至还能推测出架构将来的发展趋势。我们相信,微服务一定不是架构的终点,它或许只是架构从重量级转型为轻量级的桥梁,我们正是设计并建造这座桥梁的工程师。
现在我们从架构与架构师的角度开始出发,开启轻量级微服务的架构探险之旅。
1. 架构与架构师
可能绝大多数的程序员都想成为一名优秀的架构师,每天都能从事技术架构的相关工作,编点框架代码,画点架构图,写点PPT,帅气地站在讲台上给程序员们进行技术培训。大家普遍认为,架构师的代码比别人写得少,但是工资却比别人拿得多,架构师是技术团队中技术最牛的人,别人搞不定的技术问题,在架构师眼中都是小菜一碟。
这样的人真的是架构师吗?
我们认为,他们不是架构师,而是技术专家。其实架构师与技术专家有着本质的区别,从他们所关注的技术方向来看,架构师更偏向技术广度,而技术专家更偏向技术深度,如图1-1所示。
图1-1 架构师与技术专家的区别
换句话说,架构师需要有较强的综合能力,他们需要接触的技术领域较广,但他们所掌握的技术专业能力却没有技术专家那么深。如果我们想成为一名架构师,那么就不应该把所有的精力都投入在某个技术领域上,而是要学会分散自己所关注的层面,做到在众多技术领域上都要有一定的深度。
架构师除了需要具备在技术上所需的“硬技能”,还需要不断完善自己的“软技能”,比如沟通、组织、学习等技能。有时候软技能可能比硬技能更加重要,甚至软技能还会影响自己的职业发展。如果没有较好的软技能,架构师将无法将自己所设计的架构顺利地移交到程序员们手中,并指导他们将其真正落地。架构师正是通过他们所具备的综合能力来带领技术团队,解决不断出现的技术挑战。
架构师的职责是什么?
我们的回答是:制定规范 + 指导落地。
架构师根据业务需求所制定的合理且可落地的技术规范,我们将这样的规范称为架构。
将架构工作做好犹如我们用两条腿走路一样,左腿迈出去表示“制定规范”,右腿跟上来表示“指导落地”,如图1-2所示。
图1-2 架构师的职责
如果左腿迈出去,右腿没跟上来,那不是架构师,可能是需要拄拐的人。然而,我们身边却有一些这样的不合格的架构师,他们只懂得制定规范,却忽略了指导落地。如果架构无法落地,那么就无法称为架构了。
此外,还有一些架构师认为,架构只是技术层面上的问题,自己设计的架构应该用到市面上最为流行的新技术,比如别人公司在用微服务,那么自己公司也要用起来。如果将架构工作脱离于业务需求,我们认为这不是做架构,而是玩技术。脱离业务来设计架构是对架构的不尊重。微服务是一种应用系统架构,需要架构师围绕业务进行设计。
但是,我们绝不要为了微服务而去微服务。
从事微服务架构工作的架构师,相比传统架构的架构师而言,所要求的技能更加全面。他们不仅仅是系统架构师,也是业务分析师,他们的责任重大且挑战艰巨。
从大的方向来看,微服务架构师需要具备以下基本职责。
(1)分析业务需求并切分微服务边界。
(2)定义架构规范与文档标准。
(3)确保微服务架构顺利落地。
(4)改善微服务架构并提高开发效率。
职责与挑战往往是无法分离的,微服务架构师必须面对并克服这些挑战。
(1)架构需要适应不断变化的业务需求。
(2)架构具备稳定性、扩展性、安全性、容错性等。
(3)使技术团队深刻理解微服务思想。
(4)展现微服务架构的价值。
我们认为,传统架构师转型为微服务架构首先需要做到的是深刻理解业务,而不是表面上了解需求。业务和需求其实是两码事,业务的背后反映了客户的刚需,而需求往往是产品经理根据业务刚需所指定的解决方案。作为微服务架构师,我们需要透过需求的表象去理解业务的本质。其次需要做到的是不断优化架构,让架构变得更加简单,更加轻量级。我们要将昨天最好的表现,当成今天最低的要求,只有在技术上不断要求自己,才能让架构变得更好。
2. 架构演进过程
话说天下大势,分久必合,合久必分,对于架构演进过程而言,也符合这个规律。
最早的应用程序实际上是没有任何架构的,因为那时业务比较简单,没有架构也许是合理的,如图1-3所示。
图1-3 没有架构
但随着业务不断复杂起来,我们意识到架构可以做到水平分层,比如表现层、逻辑层、数据层等,我们可在不同的层上实现每一层所关注的内容,我们称其为“关注点分离”。但此时的架构更像是一块“铁板”,每一层的无法进行分离,因此我们也将这样的架构称为“单块架构”,如图1-4所示。
从此架构发生了更为复杂的变化,层次结构越来越深,而且不再局限于水平方向上的分层,实际上越来越多的应用程序围绕着不同的业务需求来实现,此时出现了“垂直分层架构”,每个垂直应用中实际上都是一个独立的子系统,它们共同组成了整个应用系统。然而,这些子系统一般可以部署在不同的服务器上,这些服务器可以分布在不同的地域中,我们也称其为“分布式架构”,如图1-5所示。
图1-4 水平分层架构(单块架构)
图1-5 垂直分层架构(分布式架构)
业务并没有停止发展的脚步,架构的演变也是如此。分布式应用之间的调用越来越多,整个系统的复杂度急剧上升,人们希望找到一种途径来降低分布式应用之间的耦合。此时出现了面向服务架构(SOA),人们希望SOA能成为解决分布式应用系统复杂性的“银弹”,然而事实却事与愿违。应用的复杂性不仅没有得到解决,反而还让架构变得更加复杂,同时也形成了大量的SOA商业产品,这些现象让人们更加恐惧SOA,将它视为复杂和昂贵的代名词,如图1-6所示。
随着互联网行业不断发展,用户对产品的体验要求越来越高,前端的价值逐渐被凸显出来,此时出现了“前后端分离”的趋势,前端工程师专心在界面展现与数据渲染上,后端工程师关注在业务逻辑与数据结构上,前后端只需通过REST API进行交互,工作分工更加明确,开发效率更加高效,如图1-7所示。
图1-6 面向服务架构(SOA)
图1-7 前后端分离架构
似乎很长时间都未出现任何技术能与当年的SOA相提并论,除了微服务架构。微服务的概念在2014年首次被提出以来,近几年一直是应用架构领域的核心话题。但人们往往还是容易想到当年的SOA,认为微服务与SOA有着相同的目的,只是实现细节不太一样罢了,如图1-8所示。
图1-8 微服务架构
微服务与SOA到底有何区别?
我们认为,微服务是SOA的一种落地方案。
SOA是一种面向服务的架构思想,微服务也同样推崇这种思想。微服务是将一个大型的单块架构,拆分为多个细粒度服务的架构。微服务更加考验我们的是,深入理解业务并合理地对服务边界进行切分。微服务的概念相比SOA更容易落地的原因不是概念上的创新,而是技术上的突破,尤其是容器与自动化运维技术的普及与应用。
我们始终相信,微服务并不是架构发展的终点,也许是新架构时代的起点。
3. 微服务架构发展趋势
微服务架构所涉及的范围相当广泛,我们不妨从多个角度来推测微服务架构的发展趋势。
从微服务开发角度来看,我们认为微服务的开发框架将变得更加多样化。
开发人员可使用更加适合的开发框架来完成微服务业务实现,而不再拘泥于某一种编程语言,只需确保对外提供统一的API接口方式即可。甚至可将查询与修改操作相分离,查询操作可以用一种更加轻量级的编程语言来实现,而修改操作会涉及事务,一般需要借助开发框架的事务特性来保证。
我们坚信,微服务必将坚持走轻量级技术路线。
究竟什么是轻量级?
我们认为,轻量级必须包含三个特征:易用、快速、稳定。
我们希望微服务架构中所涉及的技术都能够快速上手,运行时不占用过多的系统资源且性能突出,而且能够长期稳定地运行。
从微服务部署角度来看,我们认为微服务的部署过程将变得更加自动化。
部署微服务不再通过手工的方式去完成,因为这样既低效又容易出错,我们更加倾向于使用软件工具将其自动完成。要实现自动化部署这个目标,我们往往无法一步到位,最合理的方式是“先让它跑起来,再让它跑得快”。也就是说,早期的自动化部署方案也许不够完备,或多或少会存在一些人工参与的情况,其实这些都再正常不过了,但我们需要不断优化,努力通过自动化技术来取代重复性的人工操作。
最后想说的是,自动化虽好,但不要为了自动化而去自动化,或许有些环节通过手工处理才是最有效的方式。
二、微服务架构前期准备
搭建微服务架构绝不是一件轻松的事情,我们不仅要对微服务概念有着深刻的理解,还要研究大量的技术工具,并掌握它们的优缺点,最终需要结合技术团队对技术的了解程度,选择最为合适的技术选型。这些纯技术的技术工具只是微服务的基础设施,我们还需要在此基础设施上围绕真实的业务场景,对微服务边界进行合理地切分。我们将在本节介绍微服务的冰山模型,大家将从这座冰山中看到微服务架构的全貌,随后我们将深入冰山之下的世界,去探索微服务基础设施的八大中心,最后我们还会介绍一些关于切分微服务边界的原则和技巧。
我们现在就从微服务冰山模型开始吧,这座冰山似乎比我们想象中的要大很多。
1. 认识微服务架构冰山模型
有些人认为,使用了Spring Boot开发框架就是拥有了微服务,其实这样的认识是不正确的。Spring Boot只是一款微服务的开发框架,而且仅能用于Java应用程序中,毫无疑问,它只是微服务的冰山一角。此外,我们建议大家结合自身的业务场景,选择更为合适的编程语言以及开发框架来实现微服务,而不要拘泥于一种编程语言。
还有一些人认为,用上了Docker就进入了微服务时代,其实这样的认识也是不正确的。Docker只是一种封装微服务应用程序的容器化技术,它改变了应用程序的交付方式,也加速了微服务架构的落地速度。可以肯定地说,如果没有Docker容器技术,或许今天我们无法听到微服务的概念。
如果将微服务架构中所涉及的技术栈比喻为一座冰山的话,那么冰山之上最显而易见的部分就是微服务的开发框架与容器技术了,Spring Boot与Docker都属于冰山之上的技术。
冰山之下到底有哪些技术呢?
我们认为冰山之下的技术是整个微服务架构的基石,它们构成了整个微服务架构的基础设施。比如我们在上册中学习的ZooKeeper服务注册表、Node.js服务网关、Jenkins持续部署系统等,它们都属于冰山之下的部分。
我们可通过一幅图来描绘微服务架构这座冰山,如图1-9所示。
图1-9 微服务架构冰山模型
由于服务注册表集中管理了微服务相关的服务配置,因此我们也将它称为“注册中心”;由于服务网关是前端应用程序的唯一入口,因此我们也将其称为“调用中心”;同样,我们也将持续部署系统称为“部署中心”。这些中心都汇集在微服务冰山模型之下,除此之外,还有其他功能的中心,这些中心共同构成了微服务的基础设施。
2. 冰山下的微服务基础设施
冰山下的微服务基础设施,实际包括了八大中心。
(1)注册中心:用于注册微服务相关配置信息的中心,我们选用ZooKeeper实现。
(2)调用中心:用于提供给前端调用的统一入口,我们选用Node.js实现。
(3)部署中心:用于编译并打包微服务源码并将其部署到Docker引擎中,我们选用Jenkins实现。
(4)日志中心:用于收集并管理微服务应用程序中产生的日志,第2章中将详细介绍。
(5)监控中心:用于监控微服务的实时运行状况,第3章中将详细介绍。
(6)追踪中心:用于最终微服务的调用轨迹,第3章中将详细介绍。
(7)消息中心:用于解耦微服务之间的调用关系,第5章中将详细介绍。
(8)配置中心:用于管理微服务应用程序所需的配置参数,第7章中将详细介绍。
也许大家看到以上八大中心后会产生一些疑惑:很多人说微服务是去中心化的,为何我们还要提供这些中心呢?
我们认为,中心分为两类:一类是含有业务意义的中心;另一类是不含业务意义的中心(只是技术层面的中心)。
在微服务架构中我们应该去除的是含有业务意义的中心,而不是去除技术层面上的广义中心。比如,我们所设计的调用中心内部是不可能带有任何业务流程的,它只是一个纯技术层面的框架。对于其他中心也是如此,绝对不含有任何的业务,否则我们就应该将其去除。
3. 根据业务切分微服务边界
凡是学习过微服务的人都知道,我们需要根据业务来切分微服务边界。道理可能大家都懂,但或许仍然不知道应该怎么去做。例如,切分微服务边界有哪些关键性步骤,以及包含哪些重要性原则?
经过大量的微服务实践,我们总结了以下五个步骤,可帮助大家有效地切分微服务边界。
- 第一步:梳理业务流程。
在切分微服务之前,我们要做的第一件事情就是梳理业务流程。不妨找业务专家咨询,通过与他们沟通从而了解真实的业务流程,并将其绘制成流程图。对于过于复杂的业务流程,我们也可单独绘制流程图,并增加相关的流程说明。当然也能提供相应的状态图,用于说明业务流程中所涉及状态的变化过程。
花再多时间去分析业务流程都不过分,现在所花的每一分钟都是相当值得的。
- 第二步:抽取公共服务。
在业务流程中与业务不太相关的部分,我们可考虑将其剥离出来,并形成公共服务。例如,邮件发送、文件上传、其他第三方接口等。每种公共服务都对应一个微服务,每个微服务都有相关API,每个API都有自己的输入与输出。这些API一定要形成文档,以便其他服务调用。
一般情况下,抽取的公共服务都不太会变化,我们一定要想办法将不变的东西从可变的世界中抽取出来。
- 第三步:定义业务服务。
当公共服务抽取完毕后,业务流程中剩下来的部分就是业务服务了。建议刚开始实施微服务时,不要将业务服务的边界切得太细,可以考虑先“大切几块”,但需要确保每个服务之间尽量不要有依赖关系。换句话说,每个服务都是独立的,虽然此时服务的块头可能比较大。
我们先确保这些大块头服务可以运行在微服务基础设施上,再不断将它们进行细化,拆解为更小的服务。
- 第四步:设计数据模型。
深入到每个业务服务中,我们首先要做的是定义它底层所涉及的数据模型,也称为“领域模型”。此时会涉及数据库表结构设计,以及数据模型与关系设计。在数据层面上的设计是至关重要的,如果该部分设计得不到位,将增加后期实现微服务的成本。
数据模型的设计同样也需要进行文档化,这些文档将指导后端工程师顺利地完成微服务实现。
- 第五步:定义服务接口。
底层的数据模型设计完毕后,我们将视角转换到顶层的服务接口上。服务接口实际上就是一组API,这些API需做到职责单一,而且需要通过名称就能识别出它的业务含义。建议确保每个API的命名是全局唯一的,也建议每个API都有各自的版本号,版本号可以用自增长的方式来体现。
服务接口也需要进行文档化,这些文档一般由后端工程师编写,并提供给前端与测试工程师阅读。
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
三、轻量级微服务架构图
作为一名微服务架构师,我们不仅需要深入理解业务,并能准确地划分服务边界,而且还需要深入理解微服务,并能合理地选择技术选型。我们认为,微服务架构实际上分为两大部分,其中一部分对应部署阶段,另一部分对应运行阶段。这两部分包含了大量的技术工具,我们需要结合多方面因素来考虑,选择最为合适的技术选型来搭建微服务架构,并确保它能保持轻量级。
本节将着眼于微服务的部署与运行两大阶段,通过图文方式来描述轻量级微服务架构。
1. 轻量级微服务部署架构
当开发人员完成了微服务的细节实现后,首先要做的是确保自己所写代码的可用性,他们往往会借助单元测试工具来保证这一环节不出问题。当他们将源码提交并推送到代码仓库后,此时部署中心将从代码仓库中获取源码,并执行编译与打包操作。
不仅如此,部署中心还需从配置中心获取对应运行环境的配置参数,并生成相应的配置文件,并将这些配置文件与应用程序一同复制到Docker镜像中,最后还需将此镜像上传到镜像仓库,以便后续可从镜像仓库中下载指定的镜像,从而运行相应的Docker容器。
此外,部署中心还可扫描源码并自动生成API文档站点,以便其他技术人员可随时从文档站点中查看最新部署服务所包含的API文档。当然,我们还可以对所需完成的微服务仅提供简单的代码实现,这样就能将微服务文档的输出时间尽可能提前,以便其他技术人员能够更早地了解到微服务的相关API信息,随后再去完成更加细节的代码实现,这是我们推荐的工作方法。
当Docker镜像上传到镜像仓库后,部署中心可在不同的运行环境下根据特定的镜像来启动相应的Docker容器。为了便于描述,我们将该容器称为“服务容器”,它包含了承载微服务的应用程序及其配置文件。
当服务容器启动后,会自动将其配置信息写入注册中心,与此同时,部署中心也会连接到注册中心,并设置服务的版本号,以便于在后续调用服务时可根据版本号来识别当前可用的服务。
我们可将以上过程绘制为一幅架构图,如图1-10所示。
图1-10 轻量级微服务部署架构
可见,在微服务部署阶段中,部署中心是其中的主角,它支配其他组件,使服务可以成功部署,我们需要确保它的稳定性。
2. 轻量级微服务运行架构
当用户通过浏览器或移动端访问应用系统时,请求首先将进入服务网关,因为它是所有请求调用的中心,我们也将其称为“调用中心”。它虽然是不带任何业务的中心,但我们需要确保它所做的事情足够少,让它不会成为整个应用系统的调用瓶颈。
随后调用中心将连接注册中心,并通过服务名称从注册中心中获取服务所在的IP地址与端口号(即服务地址),该过程称为“服务发现”,进而调用中心可根据服务地址以反向代理的方式来调用具体的服务容器,该过程称为“服务调用”。
在服务容器中可能会触发一些事件,这些事件将以消息的方式写入消息中心,以便其他服务可监听消息中心并从中获取相应的消息。该方案可解决服务之间的耦合问题,同时能将同步调用转为异步调用,提高整个应用系统的吞吐率。
在服务容器运行时会产生大量的日志,我们可将这些日志统一写入日志中心,并能在日志中心所提供的控制台上查询具体的日志信息。此外,日志中心也能帮助我们快速地定位并分析系统出现的异常状况。
为了观察服务容器是否运行正常,我们可借助监控中心所输出的图形化数据来判断。监控中心将不断地收集服务容器中的运行状态,包括CPU、内存、硬盘、网络,以及应用程序的JVM内存使用情况。
由于微服务很难切得干净,服务之间难免会出现少量的调用关系,我们可将每次调用所产生的相关信息写入追踪中心,并通过追踪中心提供的图形化界面来查看服务之间的调用轨迹以及所产生的调用延时,从而可分析出服务调用所产生的性能瓶颈。
我们可将以上过程绘制为一幅架构图,如图1-11所示。
图1-11 轻量级微服务运行架构
可见,在微服务运行阶段中,调用中心是其中的主角,注册中心作为它的数据来源,服务容器作为它的调用目标,它需要具备良好的高性能与高可用等特性。
3. 轻量级微服务全局架构
我们用一张图将轻量级微服务的部署架构与运行架构进行整合,它就是轻量级微服务架构的全貌,如图1-12所示。
图1-12 轻量级微服务全局架构
图1-12所示的架构图中包括12个组件,其中的代码仓库、部署中心、注册中心、镜像仓库、调用中心、服务容器这6个组件已在上册中进行描述,剩下的配置中心、文档站点、消息中心、日志中心、监控中心、追踪中心这6个组件将在下册后续章节中深入探索。
四、总结
本章从宏观上描述了轻量级微服务架构,为后续探险历程提供了明确的蓝图。首先我们从架构与架构师开始讲起,简单回顾了架构演进的过程与微服务的发展趋势,我们认为,微服务的出现是必然的,而且它将朝着轻量级方向发展。随后我们探讨了在搭建微服务架构之前需要准备的工作,也认识了微服务架构的“冰山模型”,本书将重点集中在冰山之下的微服务基础设施中,此外还介绍了切分微服务边界的方法和技巧,我们认为,合理地切分微服务边界是微服务架构师的职责之一。最后我们从部署与运行两个角度来观察微服务架构,并以一幅架构全景图来结束本章,随后的章节将围绕这张架构图的相关部分进行展开,我们会选择最为合适的技术选型来搭建这款轻量级微服务架构。