单体架构随着业务体量的增大,应用会变得越发复杂,即便内部模块设计的非常清晰,但也会造成可靠性降低,服务启动慢,单模块无法水平扩展,扩展性差等一系列问题,此时我们需要对其进行拆分。但是从模块直接应用内调用变更成服务之前的调用势必会照成新问题,如测试的依赖,部署的复杂度,通信的时延,如何去有效解决这些问题呢,微服务架构由此而生。
¶微服务概览
¶SOA
SOA(Service Oriented Architecture)面向服务的架构,是对单体应用的一种设计优化。在SOA架构中,服务被拆分成多个服务, 服务之间通过相互依赖或者通过通信机制,来完成相互通信的,最终提供一系列的功能。
¶ESB
ESB(Enterprise Service Bus)企业服务总线,像一根管道,用来连接各个节点,让不同的服务互联互通。ESB是一种在松散耦合的服务和应用之间标准的集成方式。ESB是在SOA架构中实现服务间智能化集成与管理的中介。
¶微服务
微服务是SOA 的最佳实践,微服务架构更强调的一个是业务需要彻底的组件化和服务化,保证了服务的单一职责。微服务是去中心化的,去掉ESB企业总线,实现真正的组件化。同时微服务支持持续集成和持续交付,实现轻松部署。
¶微服务优点
- 逻辑清晰
由于微服务的单一职责。微服务的业务明确,在逻辑上变得清晰而简单,从而提升微服务的可维护性,当对一个微服务进行修改时,能够更容易分析到这个修改到底会产生什么影响,从而通过完备的测试保证修改质量。
-
简化部署
在一个单块系统中,只要修改了一行代码,就需要对整个系统进行重新的构建、测试,然后将整个系统进行部署。而微服务则可以对一个微服务进行部署,可以更频繁的去更改我们的软件,通过很低的集成成本,快速的发布新的功能。
-
可扩展
采用微服务的系统相对单块系统可以针对单一业务模块进行横向扩展,具备更好的可扩展性。
-
灵活组合
在微服务架构中,可以通过组合已有的微服务以达到功能重用的目的。
-
技术异构
在一个大型系统中,不同的功能具有不同的特点,并且不同的团队可能具备不同的技术能力。因为微服务间松耦合,不同的微服务可以选择不同的技术栈进行开发。
-
高可靠
微服务间独立部署,一个微服务的异常不会导致其它微服务同时异常。通过隔离、融断等技术可以避免极大的提升微服务的可靠性。
-
去中心化
每个服务独享自身的数据存储设施(缓存,数据库等),不像传统应用共享一个缓存和数据库,这样有利于服务的独立性,隔离相关干扰。
¶为服务缺点
-
复杂度高
微服务间通过REST、RPC等形式交互,必须要写代码来处理消息传递中速度过慢或者服务不可用等局部失效问题。同时微服务间的事务性操作变复杂。因为不同的微服务采用了不同的数据库,将无法利用数据库本身的事务机制保证一致性,需要引入二阶段提交等技术。
-
运维复杂
在采用微服务架构时,系统由多个独立运行的微服务构成,需要一个设计良好的监控系统对各个微服务的运行状态进行监控。运维人员需要对系统有细致的了解才对够更好的运维系统。
-
影响性能
服务间网络通信也会对性能产生影响。
-
测试难度大
基于微服务架构的应用测试也会变得繁琐,需要对其他服务mock,甚至照成代码侵入。
¶微服务设计
¶微服务划分
微服务架构时遇到的第一个问题就是如何划分服务的边界。在实际项目中通常会采用两种不同的方式划分服务边界,即通过业务职能(Business Capability)或是 DDD 的限界上下文(Bounded Context)。
- Business Capability
由公司内部不同部门提供的职能。例如客户服务部门提供客户服务的职能,财务部门提供财务相关的职能。
- Bounded Context
限界上下文是 DDD 中用来划分不同业务边界的元素,这里业务边界的含义是“解决不同业务问题”的问题域和对应的解决方案域,为了解决某种类型的业务问题,贴近领域知识,也就是业务。
¶API Gateway
微服务架构中,一个大型应用被拆分成多个小服务,如果对外直接暴露了一批微服务,会出现以下问题:
- 客户端到微服务直接通信,强耦合。
- 需要多次请求,客户端聚合数据,工作量巨大,延迟高。
- 统一逻辑无法收敛,比如安全认证、流量控制。
- 面向“端”的API 适配,耦合到了内部服务。
- 所有微服务对外暴露,引发安全问题。
API网关则作为统一的协议出口,连接内部微服务,可统一做切面任务,避免每个微服务自己开发,提升效率,使系统更加标准化,隐藏系统架构实现的细节,更好地实现鉴权,提高系统的安全性。
¶BFF
在微服务架构中,每一个服务遵循单一职责,提供更加细粒度的接口,业务变得很清晰,但一个需求可能会伴随多个微服务的调用,就回出现聚合裁剪的情况。在复杂的多终端的场景下,往往伴随着App客户端需要开发大量的聚合裁剪的逻辑,客户端很重且重复劳动。和服务端耦合变高,一点改动,照成频繁发版本。 如果能让多终端都能最高效最快捷的完成面向用户场景的 高效研发,最好是提供统一的面向某一个业务场景的接口。这种逻辑当然不能实现在某一个微服务下,因此我们可以在 微服务和,网关层加入BFF(Backend For Frontend,指为前端应用开发的后端服务),从而解决这类问题。
¶API网关选型
¶服务调用
在微服务架构中,通常存在多个服务之间的远程调用的需求。目前主流的远程调用技术有基于 HTTP 的 RESTful 接口和基于 TCP 的 RPC 协议。以上两种都属于同步通信,还有基于队列模式的异步通信。
¶HTTP
HTTP本身就是一种网络传输协议,基于TCP,但是在这之上做了修改,规定了网络传输的请求格式、响应格式、资源定位和操作的方式等。现在客户端浏览器与服务端通信基本都是采用Http协议。当然也可以用来进行远程服务调用。现在热门的Rest风格,就是通过http协议来实现。Http格式更标准,更通用,但消息会更臃肿,性能更差。
¶RPC
RPC—Remote Produce Call(远程过程调用),主要是通过自定义通信规则,自定义数据格式来实现通信。数据在网路中传输需要进行序列化,所以还需要约定统一的序列化的方式。这种通信形式可以降低通信过程中的交互数据传输内容大小,从而提高通信数据传输效率。现有的RPC框架一般是基于原生TCP协议通信。
¶注册中心
在微服务架构中,服务之间需要进行通信,一般就是服务将接口暴露,然后其他的服务通过ip 直接进行请求,当水平扩展时,有需要手动将服务的ip 写入到调用方配置中。在 k8s下,服务ip动态分配也会让这种方式难以维持。
当然,我们可以在服务上层加入nginx做反向代理,暴露统一的域名,但是也在服务调用之间增加了一层, 并未达到区中心化的目的。因此我们需要引入注册中心。
注册中心具备一下功能:
-
**服务注册:**服务提供方向注册中心进行注册,注册时提供的信息主要包括服务提供方IP、端口以及上下文等服务路由信息。
-
**服务发现:**服务发现主要实现服务消费方可以通过注册中心寻找到服务提供方的调用路由信息。
-
**健康检测:**服务健康检测的目的是为了确保注册到注册中心的服务节点是可以被正常调用的,避免坏死无效节点导致的调用资源浪费等问题。注册中心在检测到节点异常后可以对服务节点进行及时剔除。
-
高可用:注册中心需保证服务的可用性,CAP
-
负载均衡:微服务多实例下保证网络请求被均摊到不同的机器上, 避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况。
¶注册中心选型
¶链路追踪
在微服务架构下,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控等等。单纯的理解链路追踪,就是指一次任务的开始到结束,期间调用的所有系统及耗时(时间跨度)都可以完整记录下来。
链路跟踪主要功能:
-
故障快速定位:可以通过调用链结合业务日志快速定位错误信息。
-
链路性能可视化:各个阶段链路耗时、服务依赖关系可以通过可视化界面展现出来。
-
链路分析:通过分析链路耗时、服务依赖关系可以得到用户的行为路径,汇总分析应用在很多业务场景。
¶链路追踪选型
¶配置中心
通常服务的配置都是跟随服务代码的近代配置。这种做法虽然简单,但如果参数需要修改,就非常的不灵活,甚至需要重启运行中的项目才能生效。配置未能集中管理,也缺乏统一标准,同时配置缺乏安全审计和版本控制功能。
一个合格的配置中心需要满足一下功能:
-
对配置项的读取和修改提供简单易用的API和操作界面
-
添加新配置要够简单、直接、方便
-
支持不同管理员对配置的修改的不同权限,以把控风险
-
可以查看配置修改的历史记录,以便回滚
-
不同部署环境相互隔离,互不影响
¶配置中心选型
参考