[聚合文章] 微服务设计-note

软件架构 2017-12-27 18 阅读

最近在做交易系统的重构, 整体学习了下 微服务的相关理念. 看了一本书, 微服务设计-豆瓣链接 .

作者相关信息: Sam Newman . 个人网站地址: sam newman ThoughtWorks技术专家.

以下是具体的笔记内容:

1章 微服务

微服务定义

Martin的 单一职责原则

把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离开来
  • 单一职责原则

  • 根据业务的边界来确定服务的边界.

  • 经验: 一个微服务应该两周可以完全重写.
  • 足够小即可, 不要过小.

自治性

服务之间均通过网络调用进行通信,从而加强了服务之间的隔离性,避免紧耦合。

微服务的好处

  • 技术异构性
  • 弹性
  • 扩展性.
  • 简化部署和发布
    • 两次发布之间的差异越大. 出错的可能性越大
  • 与组织架构相匹配
  • 可组合性
  • 对可替代性的优化

2章 演化架构师

软件系统是演化出来的

  • 对于我们创造的大多数产品来说,交付到客户手里之后,还是要响应客户的变更需求,而不是简单地交给客户一个一成不变的软件包
  • 软件架构师更像城市规划师. 而不是建筑师.
  • 架构师应该像城市规划师那样专注在大方向上,只在很有限的情况下参与到非 常具体的细节实现中来
  • 担心服务之间的交互,而不需要过于关注各个服务内部发生的事

一个原则性的方法

实践和原则的对应关系

  • 实践, 原则. 原则最好不要超过10个.
  • 原则基本是很少变的. 而实践随着时间迁移, 会不断进行改变.

创建代码服务模板

当开发人员想要实现一个新服务时,所有实现核心属性的那些代码都应该是现 成的。 一些推荐的代码服务模板:

技术债

  • 往往因为一些业务的紧急需要而快速上线一些特性, 而忽略了技术的规则和原则. 积累的这些债务, 总一天是是要偿还的.

集中治理和领导

  • 架构师的部分职责是治理
  • 治理通过评估干系人的需求、当前情况及下一步的可能性来确保企业目标的达成,通过排优先级和做决策来设定方向。对于已经达成一致的方向和目标进行监督

通过微服务系统建设团队 - 全生命周期

微服务架 构中存在多个自治的代码库,每个代码库都有着自己独立的生命周期,这就给更多人提供了对单个服务负责的机会,而当这些人在单个服务上面得到足够锻炼之后,就可以给他们 更多的责任,从而帮助他们逐步达成自己的职业目标.

建设团队

  • 对于技术领导人来说,更重要的事情是 帮助你的队友成长 ,帮助他们 理解这个愿景 , 并保证他们可以积极地参与到愿景的实现和调整中来
  • 单独的服务, 全生命周期负责. 更加的锻炼成员.

3章 如何构建微服务

核心原则:松耦合 高内聚

  • 能够独立修改及部署单个服务而不需要修改系统的其他部分
  • 如果你要 改变某个行为的话,最好能够只在一个地方进行修改,然后就可以尽快地发布

服务边界

避免过早划分

尽量根据业务领域划分服务, 而不是技术层面.

  • 洋葱架构. 将一个系统按照技术层面, 划分为多层. 会导致多个系统联动进行频繁的更改.

5章 集成

共享数据的问题

  • 外部系统可以看到内部实现细节
  • 消费方与特定的技术绑定到了一起

编排VS协同

  • 编排: 有一个中心节点控制了所有的任务
  • 协同: 分布式的. 每一个模块通过订阅来独自处理任务.
    • 用异步方式有利于协同方案的实施,从而大大减少服务间 的耦合,这恰恰就是我们为了能独立发布服务而追求的特性

RPC的一些技术评价

RMI. thrift 通过生成客户端代码虽然带来了一些编写的快速性. 但是会有很多潜在的问题:

  • 技术耦合
  • 本地调用和远程调用并不相同.

异步协作模式

  • 优点: 能很好的进行解耦.
  • 缺点: 带来了一定的复杂度.

响应式扩展

提供了RxJava的响应式能力.

DRY原则与微服务

在微服务内部不要违反 DRY,但在跨服务的情况下可以适当违反 DRY。

版本管理

尽可能的延迟接口的改变. 如何尽可能的延迟版本管理问题.

鲁棒性原则

客户端尽可能灵活地消费服务响应这一点符合 Postel 法则(也叫作鲁棒性原则,https:// tools.ietf.org/html/rfc761)。该法则认为,系统中的每个模块都应该“宽进严出”,即对自己 发送的东西要严格,对接收的东西则要宽容。

不同版本共存

通过在接口Url中增加版本号, 可以提供多个版本号共存的方法.

单独的API接口层

BFF(Backends For Frontends,为前端服务的后端)。它允许团队在专 注于给定 UI 的同时,也会处理与之相关的服务端组件。

为不同的客户端聚合API接口进行单独的API聚合层.

如何决定是否使用商业软件还是自己开发

对于一般规模的组织来说,如果某个软件非常特殊,并且它是你的战略性资产的话,那就 自己构建;如果不是这么特别的话,那就购买

小结

  • 无论如何避免数据库集成
  • 理解REST和RPC之间的取舍,但总是使用REST作为请求/响应模式的起点 • 相比编排,优先选择协同
  • 避免破坏性修改、理解Postel法则、使用容错性读取器
  • 将用户界面视为一个组合层

5章 切分单个服务

关键是接缝

在《修改代码的艺术》这本书中,Michael Feathers定义了接缝的概念,从接缝处可以抽取出相对独立的一部分代码,对这部分代码进行修改不会影响系统的其他部分。识别出接缝,不仅仅能够清理代码库,更重要的是,这些被识别出的接缝可以成为服务的边界。

分解单块系统

服务拆分之后, 可能会导致单个表的事物变为如何确保多个系统的多个事物一致性, 解决办法?

  • 再试一次 . 最终一致性**。相对于使用事务来保证系统处于一致的状态,最 终一致性可以接受系统在未来的某个时间达到一致.
  • 补偿事物. 定位问题困难.
  • 分布式事物. 利用比较复杂的技术, 来确保不同进程的事物一致性.

报表服务

周期性的同步事物数据库到相应的NoSQL中, 提供相应的报表服务.

修改的代价

做小的、增量修改的各种原因,但其中一个关键的好处 是,能够理解做出的那些改变会造成什么影响. 切分成微小的服务. 然后处理相应的逻辑.

根本原因

  • 第一件需要理解的事情是,服务一定会慢慢变大,直至大到需要拆分.系统的架构随着时间的推移增量地进行变化。 关键是要在拆分这件事情变得太过昂贵之前 , 意识到你需要做这个拆分。(注释: 如果直到发生了重大事故才明白需要拆分, 太晚了!)
  • 软件的一个衡量因素-复杂度. 如果一个系统不进行可以的维护和refactor. 其复杂度, 必然是无限上升的.

6章 部署

CI(持续集成)

Fabric

https://www.cnblogs.com/holbrook/archive/2012/03/05/2380398.html

7章 测试

测试分类

测试微服务架构的系统跟测试独立系统的区别,很大程度上在于各种类型的自动化 测试。因此,我们将集中精力在自动化测试上面

测试金字塔模型

越往上的端到端测试需要花费的时间越多. 端到端的测试更多的是业务测试, QA关注较多. 单元测试, Unit Test 更多的是RD自己应该关注的, 提高系统的稳定性.

单元测试

单元测试更多是帮助RD来降低错误率的, 自动化的单元测试. 谁的代码, 谁来写单元测试.

打桩,是指为被测服务的请求创建一些有着预设响应的打桩服务.

脆弱的测试

  • 在测试中的服务数量越多,测试就会越脆弱,不确定性也就越强. 可能后期就会导致, 我们放弃Unit Test. 这在我们的工程项目中, 一次又一次的发生了.
  • 单元测试容易成为, Diane Vaughn 所说的异常正常化(the normalization of deviance)的受害者.
  • 如何解决? Martin Fowler的建议: “Eradicating Non-Determinism in Tests”( https://martinfowler.com/articles/nonDeterminism.html ). 发现脆弱的测试时应该立刻记录下来,当不能立即修复时,需要把它们从测试套件中移除,然后就可以不受打扰地安心修复它们

部署后再测试

  • 蓝绿部署.
    • 你需要能够切换生产流量到不同的主机(或主机 集群)上。切换可以通过改变 DNS 条目,或更改负载均衡的配置
    • 使用蓝 / 绿部署可以降低风险,也让你有能力在遇到问题时尽快恢复

蓝绿部署示意图:

  • 金丝雀发布
    • 金丝雀发布是指通过将部分生产流量引流到新部署的系统,来验证系统是否按预期执
    • 金丝雀发布与蓝 / 绿发布的不同之处在于,新旧版本共存的时间更长,而且经常会调整流量

平均修复时间胜过平均故障间隔时间. MTBF VS MTTR

  • 有一个问题需要注意: 不论测试是多么全面, 线上的bug还是不可避免发生 . 关键是, 能否在故障的快速的时候 , 尽快恢复.
  • 平均故障间隔时间(Mean Time Between Failures,MTBF) 和平均修复时间(Mean Time To Repair,MTTR)之间的权衡优化。
  • 减少修复时间的技术可以简单到尽快回滚加上良好的监控(在第 8 章我们将讨论),类似 蓝 / 绿部署。
  • MTTR: https://en.wikipedia.org/wiki/Mean_time_to_repair
  • https://en.wikipedia.org/wiki/Fault_tolerance

性能测试

  • 将系统拆分为较小的微服务 后,跨网络边界调用的次数明显增加了 . 需要定期的进行系统的压力测试, 不断发现系统的bottlenect
  • 性能测试需要与系统性能的监控同时进行.

推荐 《敏捷软件测试》, 关于测试有更多详细的介绍.

8章 监控

日志, 更多的日志

通过ELK日志聚合系统, 聚合更多的日志, 到一起.

多指标跟踪

使用Graphite, 进行简单的指标聚合. 美团内部, 提供了太多的数据指标聚合系统, 背后的核心都是 打点上报 到时间序列数据库.

关联表示 UUID

使用相应的关联方法. 多个上下游系统, 使用UUID. 然后相互携带. 统一聚合到 日志中心. 底层依赖ELK技术栈. 然后统一收集日志.

另外, 监控级联的风险, 使用 hystrix组件.

总结

  • 最低限度要跟踪请求响应时间。做好之后,可以开始跟踪错误率及应用程序级的指标。
  • 最低限度要跟踪所有下游服务的健康状态,包括下游调用的响应时间,最好能够跟踪错误率。一些像 Hystrix 这样的库,可以在这方面提供帮助。
  • 标准化如何收集指标以及存储指标。
  • 如果可能的话,以标准的格式将日志记录到一个标准的位置。如果每个服务各自使用不同的方式,聚合会非常痛苦!
  • 聚合CPU之类的主机指标.
  • 查看单台主机的情况.
  • 通过单个查询工具对日志进行聚合和存储.
  • 聚合关联UUID.

10章 康威定律和系统设计

康威定律

任何组织在设计一套系统(广义概念上的系统)时,所交付的设计方案在结构上 都与该组织的沟通结构保持一致
  • 松耦合组织 VS 紧耦合组织
    • 商业组织的系统耦合非常紧密.
    • amazon 的两个披萨团队. 一个团队应该达到两个披萨不够吃.

相关链接:

服务所有权

所有 权延伸到服务的方方面面,从应用程序的需求、构建、部署到运维。它把决定权交给最合适的人,赋予团队更多的权力和自治,也使 其对工作更负责. Eat your dog food!

  • 成员轮换
    成员时不时地在这些团队之间轮换,但往往长时间留在这个业务线,以确保团队成员可以更好地建立业务线的领域知识
  • 如何构建高并发.安全.稳定 的交易系统.

“不管一开始看起来什么样,它永远是人的问题。” 
            ——杰拉尔德 • 温伯格,咨询第二定律

11章 规模化微服务

故障无处不在

https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing . 分布式计算的谬论:

  • 网络是可靠的.
  • 延时为0
  • 带宽是无限制的
  • 网络是安全的
  • 拓扑是不会变的
  • 只有一个管理员
  • 传输成本为0
  • 网络是是均匀的.
    针对谬误, 软件设计和开发过程中, 需要做一些降级去处理这些问题, 拥抱这些故障.

系统指标

  • 响应时间
  • 可用性
  • 数据持久性

功能降级

从业务角度来思考, 我们该如何对不同的系统优雅的降级使用.

架构性安全措施

有一些模式,组合起来被称为架构性安全措施,它们可以确保如果事情真的出错了,不会引起严重的 级联影响 .

如何来解决下游服务的不可用, 导致一个依赖服务拖垮我们整个服务, 耗尽对外的http线程池?

反脆弱性在netflix中的使用

反脆弱性在netflix上的使用

  • Netflix通过引发故障来确保其系统的容错性
  • 谷歌通过 DiRt. 灾难恢复测试来测试系统.
  • Netflix chaos monkey. 随机停掉服务器. 制造混乱

  • 正确设置超时时间.

    • 设置默认超时时间, 防止超长时间等待.
  • 实现仓壁隔离不同线程池
    • 实现不同业务的线程池隔离. 推荐 netflix的hystrix解决方案.
  • 实现断路器
    • 当对下游资源的请求发生一定数量的失败后,断路器会打开
    • 断路器模式 断路器
  • 隔离
    • 一个服务越依赖于另一个,另一个服务的健康将越能影响其正常工作的能力.

幂等

- 多次执行操作和一次执行操作幂等. 退款就应该是这样. 重复支付失败. 
- 如何进行隔离? 如何隔离?

负载均衡

  • 是把所有的微服务实例都 放在一个独立的 VLAN 里。VLAN 是一个虚拟局域网,所有的外部请求只能通过一个路由 器访问内部。在这个例子中,这个路由器也就是 SSL 终端负载均衡器。VLAN 外部跟微服 务通信的唯一方式是通过 HTTPS,而内部的所有通信都是通过 HTTP. 内部的负载均衡. nginx只用来进行SSL加密通信.

重新设计

你的设计应该“考虑 10 倍容量的增长,但超过 100 倍容量时就要重写 了”。在某些时刻,你需要做一些相当激进的事情,以支持负载容量增加到下一个级别。 参考: Challenges in Building Large-Scale Information Retrieval Systems

扩展数据库

  • 服务可用性 VS 数据持久性. 不同的概念.
  • 扩展读取.
    • 读从库. 可能会有数据一致性问题. CAP原理
    • 读缓存.
  • 扩展写
    • Hash -> 分片. mysql. 分库分表. 缓解压力
    • 问题. 如何进行跨分片的查询. 同步到NOSQL进行查询.
    • 内存计算.聚合返回 / 替代的读数据库包含所有数据. ES.
    • mongdb . cassandra. 替换的选择. NOSQL数据库.
  • CQRS. (command-query responsibility segregation).
    • 将查询和修改状态的请求命令进行隔离.
    • CQRS的说明和解释 Martin Fowler: CQRS

使用缓存

  • 客户端缓存

    • 可以减少客户端调用次数
    • 无法使全部消费者同时发生变化
  • 服务端缓存

    • 一切对客户端都是不透明的,它们不需要关心任何事情。缓存在服务 器外围或服务器限界内时,很容易了解一些类似数据是否失效这样的事情,还可以跟踪 和优化缓存命中率.
  • 代理服务器缓存

    • 不需要每次查询.
  • HTTP缓存

    • cache-control. 控制是否需要缓存该时间.
    • expires头部, 失效时间.
    • Etag. 可以发送缓存内容的最新版本号.
  • 为写试用缓存

    • 后写式缓存(writebehind) - 批量处理操作.
      • 如果你使用后写式(writebehind)缓存,可以先写入本地缓存中,并在之后的 某个时刻将缓存中的数据写入下游的、可能更规范化的数据源中
      • write-back
      • cache写机制
  • 防止缓存突然全部失效

    保护源服务 - 后台重建缓存
  • 保持简单

    缓存越多,就越难评估任何数据的新鲜程度

CAP原理

在分布式系统中有三方面需要彼 此权衡:一致性(consistency)、可用性(availability)和分区容忍性(partition tolerance)。 具体地说,这个定理告诉我们最多只能保证三个中的两个。

  • 需要根据你的业务来具体判断, 你的系统需求属性. 比如: 我们的系统作为一个整体,不需要全部是 AP 或 CP 的.

服务发现

  • 动态服务机制

    • zookeeper. 树形的结构, 可以增加新的节点. 复杂的选举机制,来确保可用性.Zookeeper 的核心是提供了一个用于存储信息的分层命名空间

    • Consul. Consul 提供的杀手级特性之一是,它实际上提供了现成的 DNS 服务器. 网址: http://www.consul.io/ . 项目github地址: https://github.com/hashicorp/consul

    • Eureka. netflix提供的服务发现功能.Netflix 的开源系统 Eureka( https://github.com/Netflix/eureka )

文档服务

API文档服务解决方案: Swagger. 用动态的接口来展示文档.

12章 - 总结

坚持反脆弱性信条

心中持有反脆弱的信条,预期在任何地方都会发生故障,这说明我们正走在正确 的路上.

  • 设置 超时
  • 使用 仓壁和断路器

实现微服务体系化

  • 围绕业务概念建模
  • 接收自动化文化
    • 接受自动化测试工作
  • 隐藏内部实现细节
    • 隐藏数据库
  • 一切都去中心化
  • 可独立部署
    • 蓝绿部署. 灰度部署, 经历一个完整的高峰期.
    • 金丝雀部署技术. 区分部署和发布.
  • 隔离失败
    • 断路器
    • 仓壁模式
  • 高度可观察
    • 通过语义监控
    • 聚合日志和数据

ChangeLog

12/19/17 完成11章节和12章节笔记.

12/27/17 完成全部章节笔记

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。