读书心得
综合书中提到的微服务相对于单块架构的优势,多是围绕【微】展开的,正是因为每个服务小又相对独立,带来了技术选型、弹性伸缩等方面的灵活性。书中的实践篇提到的构建微服务的几个步骤,基本可映射到当前我们自己微服务的持续交付流程。“微”让持续交付流水线快速反馈成为可能,所以更应该在流水线的构建上考虑效率,保持快速、有效、精确的反馈。书中提到的微服务带来的一些问题与挑战,结合目前参与组件开发的一些直观感受,认为有一些从developer角度值得关注与改进的问题:
- 微服务之间的相互依赖导致的启动时序问题。服务启动时往往有一些初始化的操作,涉及访问其他微服务的接口、访问公共服务等,如果所依赖的公共组件或者服务尚未启动完成,需要通过重试、检查所依赖的服务的可用性等手段来保证初始化成功(提供统一的可用性检查工具方法或接口?一键部署时是否能支持顺序编排,先确保一部分基础组件优先部署?)
- 同外部资源的交互增多,测试用例复杂度增高。UT涉及大量的mock(可以开发一些易用性工具,使mock更方便、更规范);组件测试,除了个别被测组件,可能需要mock外部组件的行为(比如会开发一些模拟器模拟外部组件的行为,但也会增加额外的维护负担)
- 微服务之间的边界和职责是否清晰…
读书笔记
单块架构面临的挑战
三层架构解决了系统间调用复杂、职责不清的问题,也有效降低了层与层之间的依赖关系
三层架构:
- 表示层:用户看见、听见、输入、交互的部分
- 业务逻辑层:根据用户输入的信息,进行逻辑计算或者业务处理的部分
- 数据访问层:关注应用程序如何有效地将数据存储到数据库、文件系统或者其他存储介质中
三层架构将应用在逻辑上分成了三层,但不是物理上的分层。经历编译、打包、部署后,还在一个机器的同一个进程中,为单块架构应用。优势:易于开发、易于测试、易于部署、易于水平伸缩。面临的挑战:
- 维护成本增加
- 持续交付周期长
- 技术选型成本高
- 可扩展性差,垂直扩展:通俗来说等于升级服务器;水平扩展:相当于增加服务器,集群
- 构建全功能团队难
微服务架构
微服务架构是一种架构模式,提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务独立进程,服务间采用轻量级通信机制(REST)。每个服务围绕具体业务进行构建,可以被独立地部署到生产环境。
多微才算微?团队觉得合适 + 两个前提:
- 业务独立性,领域模型、业务行为…
- 团队自主性
敏捷、精益、持续交付以及DevOps是微服务诞生的催化剂,Docker的出现有效解决了微服务的环境搭建、部署、运维成本高的问题。
微服务优势明显:独立性、单一职责、技术多样性;实施需要考虑的因素:
- 分布式系统复杂度:性能(跨进程、跨网络),可靠性(远程调用、单点),异步,数据一致性,工具
- 运维成本:配置、部署、监控与告警、日志收集,每个服务都要独立配置
- 部署自动化
- DevOps与组织架构
- 服务间的依赖测试
- 服务间的依赖管理
微服务实践涉及的流程
- 场景分析、任务拆分
- 框架选型、代码实现;代码提交涉及的检查:编译检查、UT、UT覆盖率、静态检查、复杂度检查、代码规范性检查
- 构建、运行、发布镜像,关注一些验证:集成测试、性能测试等
- 基础设施自动化、镜像的自动化部署
- 持续交付流水线构建
- 部署在不同节点上时,要考虑日志聚合,进一步考虑日志便于查找关键字、告警设置等(如:Splunk)
- 微服务健康状态监控与告警(如:Nagios、pagerDuty)
微服务有效实施探讨
持续交付
持续交付是软件系统的构建、部署、测试、审核、发布过程的一种自动化实现,其中的核心是部署流水线,因为可将这几个环节有效地连接起来。核心:小、频、快
每个微服务都是独立、可部署的单元,所以应该对应独立的持续交付流水线。
轻量级通信机制
轻量级:语言无关、平台无关
RPC: 远程过程调用的框架会定义一组代理存根(Stub和Skeleton),分别存在于客户端与服务端环境中,为客户端与服务端应用程序提供透明的调用和响应机制。弊端:
- 耦合度高:依赖于编程语言或特定平台,限制了客户端和服务端采用的技术
- 灵活性差:任何一方发生变更,都需要修改相应对端,来保持代理存根的一致性
REST(表述性状态转移): 以资源为核心、以HTTP为操作方式的,与语言无关、平台无关的服务间的通信机制。由于HTTP本身的无状态性,能够有效保持服务/应用的无状态性,利于将来的水平伸缩。四个关键部分:
- 资源:实体,服务器端需要处理的具体信息,一段文本、图片、数据库表等
- 表述:对资源在某个特定时刻的状态的描述。在进行信息交换时,可以有多种表现形式,如文本可以用TXT,也可以用HTML、XML、JSON、二进制;图片可以JPG、PNG。表述应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对“表述”的描述
- 状态转移:客户端能够通过资源的表述,实现操作资源的目的。HTTP是无状态协议,客户端想要操作资源,必须通过某种手段,让服务器端发生状态的转移,而这种转移是建立在资源的表述之上的,通常将其称为表述层状态转移
- 统一接口:GET、POST、DELETE、PUT,操作资源
需要考虑:
- 如何标准化资源结构
- 如何有效处理相关资源的链接(用户资源的JSON中应该能够自解释资源的关联关系)
- 性能,基于HTTP,并不是低时延通信的最好选择
HAL: 轻量级超文本应用描述协议,实现基于REST,有效解决REST中资源结构标准化和如何有效定义资源链接的问题。与REST不同的是,在每个资源中,HAL又将其分成了三个标准部分:
- 状态:资源本身的固有属性
- 链接:与当前资源相关的一组资源的链接的集合,链接名称、目标URI、访问URI的参数
- 子资源:描述在当前资源内部,其嵌套资源的定义
消息队列: 节点之间异步通信的实现方式。核心部分:
- 持久性:消息可能被保存在内存中、写入到磁盘中、提交到数据库
- 排队标准:FIFO
- 安全策略:决定哪些接收者能够访问或者获取消息
- 清理策略:为处理过的消息提供清理策略,保障消息的有效清理机制
- 处理通知:提供某种通知机制,帮助消息发布者知道何时部分或全部接收者收到了消息
消息队列优缺点:
- 服务间解耦
- 异步通信
- 消息的持久化以及恢复支持
- 实现复杂度增加
- 平台或者协议依赖
- 维护成本高
后台任务处理系统: 任务、队列、执行器、定时器
测试
单元测试: 验证服务内部业务状态的变化以及业务的处理逻辑
被测单元 | 功能 | 测试内容 |
---|---|---|
业务模型 | 对业务领域实体的抽象 | 验证数据变化或状态变化 |
业务逻辑 | 对业务行为的抽象。基于业务模型,实现核心业务价值 | 验证被测单元如何同依赖部分协作,完成核心业务价值 |
模型存储 | 对业务数据的存储以及获取 | 验证能否有效存储业务模型,或者从不同存储媒介获取数据并转换成业务模型 |
资源定义 | 业务模型的对外表现形式 | 验证能否基于业务模型,构建出期望的资源定义 |
网关集成 | 负责与其他服务间的协作 | 验证从其他服务获取数据后的校验,解析以及错误处理 |
集成测试: 将不同的单元按照期望组合起来,对其接口进行正确性检验的测试工作,三个基本关注点:
- 将多个单元组合起来后,能否达到预期的功能要求
- 当一个单元的功能发生变化,是否影响相关联部分的功能
- 当一个单元的功能出现错误,是否会放大到整个系统
关注的是服务同外部资源的交互行为是否正确
被测单元 | 测试内容 |
---|---|
网关集成 | 关注同其他服务的交互,包括:协议处理、错误后异常处理(缺少HTTP头、参数不正确)、网络超时、网络故障 |
模型存储 | 关注同外部数据存储媒介的交互,包括:数据库&云存储&云系统、异常处理、连接超时、数据持久性 |
基于消费者驱动的契约测试: 因集成测试的弊端(运行效率低、结果不稳定、反馈周期慢),诉诸于契约测试。契约测试是针对服务接口进行的测试,验证契约提供者提供的契约是否满足消费者的期望。不需要深入地去测试服务的轻微,只需要测服务的输入输出包含了必须的属性,响应的等待时间以及吞吐量。优势:
- 从价值实现的角度定义契约
- 隔离消费者和提供者的测试
组件测试: 对组件提供的功能进行正确性检测的测试工作。模拟外部依赖 or 设置好外部依赖环境
端到端测试: 从用户使用系统的角度出发,对系统的行为进行正确性验证的测试。