kl800.com省心范文网

浅谈微服务基建的逻辑——ThoughtWorks洞见

浅谈微服务基建的逻辑——ThoughtWorks 洞见

本篇文章主要目的是面向初接触微服务的朋友简单介绍微服务基础建设 所需要的各个模块以及缘由。 起点 首 先 ,我 们 得 有 一 个 “ 服 务 ” 。根 据 定 义 ,我 们 可 以 把 每 个 服 务 实 例 都 视 作 一 个 黑 盒 。这 个 盒 子 有 着 明 确 的 输 入 点 和 输 出 点 ,并 且( 理 想 情 况 下 )仅 通 过这些输入和输出点和外界产生关联。每个服务实例会拥有专属的网络地址、 独 立 的 计 算 资 源 ,并 且 独 立 部 署 。客 户 端 通 过 访 问 服 务 实 例 的 地 址 来 调 用 服 务 API 。 不 同 服 务 也 可 以 相 互 调 用 。

配置管理器:统一管理配置 在 微 服 务 体 系 中 ,每 个 服 务 都 独 立 部 署 和 运 行 ,团 队 可 以 根 据 需 要 自 行 选 择 增 加 和 减 少 计 算 资 源 。一 个 服 务 可 能 会 跑 多 个 实 例 ,每 个 服 务 实 例 都 会 需 要 做 配 置 。为 了 方 便 统 一 调 整 配 置 ,我 们 可 以 把 配 置 中 心 化 ,每 个 服 务 实 例 都 去 找 配 置 管 理 器 ( Configuration Manager ) 拿 配 置 。 当 配 置 更 新 的 时 候 , 我 们也可以让服务实例再去拿新的配置。

服务名册:解耦主机地址 这 也 引 出 了 一 个 问 题 : 网 络 地 址 ( 比 如 IP ) 很 容 易 因 为 扩 容 、 维 护 而 变 动,调用者难以实时获知可用的地址。 鉴 于 此 ,我 们 可 以 把 网 络 地 址 抽 象 成 不 容 易 变 动 的 概 念 ,比 如 给 每 个 服 务 一 个 固 定 的 名 字 。 互 联 网 使 用 DNS 来 解 决 这 个 问 题 , 对 应 到 微 服 务 基 建 里 面 就 是 服 务 名 册 ( Service Registry ) 。 每个服务实例在运行期间,都会以心跳的形式向服务名册发送注册信息, 包 括 服 务 的 ID 、 访 问 地 址 以 及 健 康 状 况 。 这 样 , 需 要 访 问 服 务 的 时 候 , 客 户 端 就 可 以 先 问 服 务 名 册 拿 可 用 的 实 例 地 址 ,然 后 再 访 问 实 例 来 调 用 服 务 。除 了 更 好 地 定 位 实 例 地 址 ,服 务 名 册 还 可 以 在 某 些 实 例 下 线 、维 护 或 升 级 的 时 候 把其临时从名册中去掉,让服务不断线。 服务之间的调用也是如此,先找名册拿网络地址,再进行调用。

API 网 关 : 入 口 和 路 由 找 名 册 要 地 址 ,然 后 调 用 服 务 API ,这 些 是 每 个 客 户 端 都 会 去 做 的 琐 事 , 我们完全可以把这些事情抽象、 集中, 把 服 务 的 API 整 合 到 一 个 大 的 中 心 点 , 然 后 把 要 地 址 和 调 用 服 务 API 这 样 的 细 节 封 装 起 来 ,所 有 客 户 端 都 只 跟 这 个 中心点对话,不再直接访问单个服务。 从 结 构 上 看 ,这 个 中 心 点 把 整 个 架 构 划 分 成 了 内 外 两 部 分 ,内 部 是 所 有 的 服 务 ,客 户 端 则 在 外 部 ,中 心 点 站 在 中 间 。它 作 为 内 外 的 唯 一 通 道 ,被 顺 理 成 章 地 命 名 作 “ API 网 关 ” ( API Gateway ) , 有 时 候 也 被 称 做 “ 边 缘 服 务 ” ( Edge Service ) 。 API 网 关 作 为 唯 一 出 入 口 , 又 占 据 了 最 前 沿 的 有 利 位 置 , 所 以 有 时 还 会 承载别的公共功能,比如我们马上会提到的鉴权。

鉴权服务:身份和权限问题 顺着这个架构继续开发,我们会遇到新的问题:不方便的鉴权。 鉴 权 ( Auth ) 包 括 了 两 个 部 分 : 身 份 认 证 ( Authentication ) 和 权 限 验 证( Authorization )。身 份 认 证 关 心 的 是 “ 你 是 谁 ” ,权 限 验 证 关 心 的 是 “ 你 能不能做某件事”。 身份和权限都是高度中心化的概念。 对 于 一 个 系 统 来 说 ,用 户 的 身 份 必 须 是 统 一 的 。不 能 说 这 个 用 户 在 做 这 个 事 情 的 时 候 是 张 三 ,做 那 个 事 情 的 时 候 是 李 四 。此 外 ,用 户 的 认 证 状 态 也 应 该 是 统 一 的 。不 能 说 用 户 访 问 这 个 服 务 的 时 候 是 已 登 录 认 证 ,访 问 另 一 个 服 务 时 又是未登录状态。所以,只能有一个身份认证方。 权 限 稍 微 复 杂 一 点 。和 身 份 不 同 ,权 限 通 常 分 成 两 种 类 别 :功 能 权 限 和 数 据 权 限 。这 样 的 划 分 对 应 了 现 实 世 界 中 常 见 的 权 限 模 式 :你 的 角 色 决 定 了 你 的 职 能 ,而 职 能 范 围 通 常 由 附 加 条 件 来 限 制 。比 如 ,你 是 一 个 法 官 ,对 案 件 有 裁 决权,但是你是 A 区的法官,只能判 A 区的案子。再比如,某个快餐门店 的经理有权看员工的详细资料,但是只能看自己门店的员工资料。

两种权限都由全局的规则来确定, 而不掌握在执行部门。 比如, 谁来判案, 取决于法律, 而不取决于法院。 谁能查看谁的资料, 也不由资料保管部门决定, 而由规章制度决定。 在 现 实 的 情 况 中 ,组 织 可 能 会 有 专 门 的 审 核 部 门 来 验 证 权 限 ,但 对 那 些 不 是 特 别 敏 感 的 权 限 ,企 业 会 让 各 个 部 门 自 行 验 证 。不 过 不 管 谁 来 执 行 验 证 ,都 必 须 拿 着 同 一 份 规 章 制 度 ,不 能 各 说 各 话 。这 份 制 度 必 须 由 中 心 机 构 来 统 一 制 定、维护。也就是说,权限的管理也应该中心化。 明 确 鉴 权 中 心 化 之 后 ,我 们 就 可 以 开 发 一 个 公 用 的 鉴 权 服 务 ,执 行 身 份 认 证和权限验证。下一个问题是:谁来发起鉴权? 所有服务的调用都要求调用者明确自己的身份, 所以自然身份认证越靠前 越 好 。作 为 出 入 口 的 API 网 关 自 然 是 发 起 身 份 认 证 的 不 二 之 选 。权 限 验 证 则 稍 微 复 杂 ,完 全 值 得 另 起 一 文 详 述 。此 处 我 们 暂 时 假 定 权 限 验 证 也 由 API 网 关来发起。

消息中介:异步和通知

开 发 继 续 进 行 ,一 切 风 平 浪 静 ,技 术 上 暂 时 没 有 什 么 问 题 。不 过 ,业 务 上 有一个问题需要解决。 比 如 ,我 们 做 一 个 在 线 商 城 ,要 求 在 订 单 成 功 创 建 的 一 刻 ,仓 库 就 要 启 动 备 货 和 发 货 的 流 程 。问 题 是 ,订 单 和 仓 储 是 两 个 服 务 ,不 同 团 队 在 负 责 ,而 且 从 关 注 点 来 说 ,订 单 服 务 并 不 关 心 仓 储 相 关 的 问 题 ,所 以 订 单 服 务 不 可 能 在 创 建 订 单 的 时 候 去 主 动 通 知 仓 储 服 务 。仓 储 服 务 只 能 定 时 轮 询 订 单 服 务 ,看 看 有 没有新的订单。这不仅麻烦,而且实时性不够。 仔 细 想 想 ,我 们 会 发 现 这 种 需 求 很 常 见 ,信 息 的 产 生 者 并 不 知 道( 也 不 关 心 )谁 会 对 信 息 产 生 兴 趣 。比 如 我 们 可 能 会 有 一 个 监 控 服 务 需 要 实 时 展 示 产 品 销 量 ,有 一 个 BI 服 务 需 要 获 取 客 户 购 买 产 品 的 信 息 来 做 分 析 ,等 等 。既 然 这 是 一 个 常 见 需 求 ,我 们 不 妨 把 它 模 式 化 ,形 成 一 个 机 制 :信 息 产 生 者 把 通 知 发 出来,收到通知的人再确定是否需要采取行动。 这 就 意 味 着 我 们 需 要 再 引 入 一 个 中 心 化 的 公 共 服 务 :消 息 中 介( Message Broker ) 。 当 某 个 事 件 发 生 的 时 候 ( 比 如 用 户 激 活 成 功 、 订 单 创 建 成 功 ) , 服 务 可 以 朝 消 息 队 列 发 一 条 消 息 。而 其 他 服 务 可 以 订 阅 这 些 消 息 ,并 针 对 这 些 消息做出反应。 比如,仓储服务可以订阅订单创建成功的消息。这样,订单成功创建后, 订单服务将这个消息发到消息中介,消息中介通知仓储服务,仓储服务一看, 就问订单服务要新的订单信息,最后,启动出库流程。

消 息 中 介 除 了 能 广 播 事 件 之 外 ,还 能 做 异 步 调 用 。把 同 步 的 调 用 转 化 成 异 步 的 回 调 。针 对 调 用 时 间 长 和 不 要 求 实 时 结 果 的 调 用 ,可 以 增 加 性 能 ,提 升 体 验。 前置后端:优化前端开发 走 到 这 里 ,其 实 体 系 已 经 比 较 完 备 。现 在 的 问 题 是 ,如 何 让 微 服 务 基 建 结 构和研发团队常见的结构更好地对应起来。 这要求我们从康威定律的角度来看 待整个基建的设计。 在围绕用户和价值的软件研发流程中, 我们常用用户历程和用户故事来捕 捉 和 跟 踪 价 值 的 实 现 。一 个 用 户 故 事 通 常 会 包 含 一 个 有 明 确 边 界 、明 确 验 收 标 准和明确价值的业务步骤。 问 题 在 于 ,支 撑 一 个 故 事 有 前 后 两 端 的 研 发 工 作 ,二 者 是 不 同 步 的 。前 端 由业务流程和设计来驱动, 希望按顺序产出; 后端则由业务资源和建模来驱动, 希望按模块来产出。

比 如 说 ,前 端 常 常 会 因 为 设 计 的 原 因 调 整 自 己 需 要 的 字 段 ,而 后 端 从 建 模 的 角 度 并 没 有 这 个 需 要 ,也 没 有 动 力 频 繁 地 去 跟 随 前 端 的 调 整 ,使 得 前 端 不 得 不在不稳定的网络条件下传输多余的信息,占用了宝贵的网络带宽。 此外,前端呈现某个业务步骤的时候,有两种信息不属于当前必备信息, 但 常 常 需 要 和 必 要 信 息 一 起 展 示 。一 种 是 状 态 信 息 ,比 如 当 前 的 登 录 状 态 和 用 户 名 ,短 消 息 的 数 量 等 等 。一 种 是 垂 直 相 关 的 信 息 ,比 如 在 展 示 文 章 的 时 候 顺 便展示一下相关的文章。 这就要求前端在调用主服务的同时还要再调用多个不同的服务。 且不说这 些 服 务 有 可 能 会 有 调 用 超 时 、出 错 的 可 能 ,仅 仅 是 多 出 来 一 堆 异 步 请 求 ,就 已 经足够让前端效率降低一大截了。 在微服务体系下,这些问题更加严重,因为现在不仅仅是前后端的差别, 不 同 服 务 还 由 不 同 团 队 负 责 。这 些 团 队 的 诉 求 和 日 程 不 一 ,很 难 做 到 前 端 所 需 要的快速响应。 这些问题和麻烦可能会催生一个“缓冲带”, 比如后端出专人来负责对接 前 端 的 需 要 ,或 者 前 端 派 驻 一 个 人 到 后 端 来 谈 需 求 。按 康 威 定 律 ,这 种 沟 通 体 系,久而久之,很容易以软件的形式沉淀下来,形成一个专属的中间层。 要调和前后端的不同步是不可能的, 而这种中间层是自然催生的解决方案, 可以保留。新的问题是,它的职责是什么?应该把它放在哪?应该由谁来维 护? 分 析 下 来 ,其 责 任 有 二 。第 一 是 解 耦 前 后 端 的 工 作 ,降 低 相 互 的 影 响 。前 端 需 要 的 东 西 可 以 写 在 中 间 层 里 ,让 它 频 繁 变 化 也 没 有 关 系 。后 端 如 果 还 没 有 准 备 好 ,前 端 也 可 以 在 这 一 层 模 拟 假 的 数 据 ,不 至 于 被 阻 塞 。第 二 则 是 提 升 前

端 的 运 行 效 率 。前 端 可 以 把 所 需 要 的 多 个 服 务 的 东 西 统 一 汇 总 ,一 次 拿 完 ,免 得发多个请求。 放 置 的 位 置 则 在 API 网 关 之 内 , 让 它 可 以 享 有 API 网 关 所 带 来 的 好 处 和保护。 最后是维护问题。 按照“谁主张, 谁举证”的原则, 既然有了这个中间层, 好处让前端得了,那么,理论上应该由前端来维护。 这样, 一个主要为前端服务的中间层就定义好了。 不同类型的前端 (桌面、 移 动 )可 能 会 有 不 同 的 需 要 ,为 了 避 免 中 间 层 的 碎 片 化 ,我 们 可 以 让 各 个 中 间 层 都 特 定 的 前 端 类 型 紧 密 耦 合 ,比 如 桌 面 专 用 、移 动 专 用 。如 此 ,每 个 中 间 层 都像是某类型前端的专享后端, 所以“前置后端” ( Backend-for-Frontend , 简 称 BFF ) 也 因 此 得 名 。

回路熔断器:提高容错度

现 在 ,调 试 也 方 便 了 ,我 们 又 继 续 开 发 。一 开 始 没 有 什 么 问 题 ,但 部 署 到 预 生 产 环 境 的 时 候 ,又 一 个 问 题 出 现 了 :整 个 体 系 的 容 错 度 很 低 。一 个 小 错 误 容易被层层传递和放大,导致整个体系的崩溃。 我们都知道,编程最麻烦的就是远程调用。本地调用大部分时候结果是 “ 成 功 ” 或 “ 失 败 ” ,但 远 程 调 用 则 很 可 能 是 “ 无 响 应 ” 。“ 无 响 应 ” 有 可 能 是 正 常 的 ,对 方 可 能 稍 后 会 给 你 结 果 ,也 可 能 是 因 为 对 方 已 经 死 了 ,没 法 给 你 响 应 。最 坏 的 结 果 ,就 是 门 口 挤 满 了 人 ,大 家 都 在 等 你 给 结 果 ,而 你 也 在 等 别 人给结果,资源全部占用来等,什么也做不了。 不过, 远程调用是无法避免的。 在微服务体系中, 这个问题被进一步放大。 这 是 因 为 微 服 务 的 模 块 化 以 服 务 为 单 位 ,而 每 个 服 务 独 立 部 署 和 运 维 ,使 得 服 务之间的调用成了家常便饭。 在这种严峻的情况下, 我们必须从架构上尽量提高整个服务体系的容错度, 让个别服务的问题不至于影响到全局。 具 体 的 做 法 ,则 是 给 远 程 调 用 加 一 个 熔 断 阈 值 检 查 ,当 调 用 超 时 次 数 超 过 阈 值 时 ,就 不 再 调 用 ,直 接 返 回 错 误 。过 一 段 时 间 之 后 ,再 把 阈 值 恢 复 ,尝 试 继 续 调 用 ,重 复 前 面 的 过 程 。这 个 机 制 就 是 回 路 熔 断 ,而 这 个 工 具 则 是 回 路 熔 断 器 ( Circuit Breaker ) 。 除了隔离已经出错的服务实例, 熔断器还有一个重要的功能是提供备用方 案 。虽 然 我 们 把 所 有 业 务 都 拆 成 了 服 务 ,但 服 务 有 高 低 贵 贱 之 分 。有 一 些 服 务 属于关键服务,一旦出问题,则整个流程无法继续,有一些则属于分支服务, 即便错了,也不会影响大局。

比 如 说 ,购 买 商 品 的 时 候 ,常 常 会 根 据 用 户 的 习 惯 和 当 前 正 在 购 买 的 东 西 做 一 些 推 荐 。负 责 推 荐 的 服 务 出 问 题 的 话 ,大 不 了 就 不 推 荐 了 ,不 应 该 影 响 用 户 正 常 的 购 买 流 程 。同 理 ,如 果 是 在 线 点 餐 的 地 址 定 位 服 务 出 问 题 了 ,我 们 也 应 该 允 许 用 户 手 动 选 择 餐 厅 进 行 点 餐 ——体 验 虽 然 不 佳 , 但至少正常的流程仍 然可以走完。基于这个考虑,熔断器应该为非必要的服务调用提供备用方案, 尽量保证核心流程的顺畅。

有 了 回 路 熔 断 器 ,远 程 调 用 出 错 的 问 题 就 从 一 定 程 度 上 缓 解 了 。结 合 回 路 熔 断 器 和 对 熔 断 阈 值 变 化 的 监 控 ,开 发 者 可 以 更 容 易 地 发 现 问 题 ,并 及 时 采 取 行动。 负载均衡器:提升服务弹性 要正式上线, 我们还必须做好负载均衡 ( Load Balancing , 下 简 称 LB ) , 提升整个服务的弹性。要做负载均衡,从理论上有两种方式:

客 户 端 负 载 均 衡( Client-Side LB ):由 客 户 端 来 决 定 如 何 分 散 请 求 。 中 间 方 负 载 均 衡 ( Mid-Tier LB ) : 由 DNS 、 网 关 等 中 间 方 来 决 定 如 何 分 散 请 求。 现 在 ,服 务 名 册 中 已 经 有 了 服 务 及 其 对 应 的 实 例 地 址 列 表 ,所 以 客 户 端 的 负载均衡最简便的方式就是把地址拉下来, 然后依次或者随机选择可用的地址。 中 间 方 的 负 载 均 衡 则 选 择 面 较 多 , 从 最 外 层 的 DNS 到 网 关 都 可 以 不 同 程 度 地去按需要去做。 扩展基建 现 在 ,微 服 务 基 建 基 本 完 成 了 。如 果 有 需 要 ,我 们 可 以 对 这 个 基 建 进 行 扩 展 。在 做 扩 展 时 ,架 构 师 应 该 注 意 区 分 哪 些 东 西 应 该 中 心 化 ,哪 些 东 西 应 该 由 服务自行决定。 比如说,在本文提到的基建之中,(几乎是)强制完全中心 化的模块有:
?配置管理 ?服务名册 ?消息队列

其中, 配置管理和服务名册是所有服务都需要的基础设施, 必然需要统一。 消息队列和日志收集都是为了跨服务的操作和追踪,也必须中心化。 半中心化的模块则有:
?路由 ?鉴权

路 由 和 鉴 权 都 必 须 统 一 ,我 们 前 面 讨 论 过 。不 过 ,微 服 务 可 能 会 向 外 界 暴 露 “ 自 用 ” 和 “ 客 用 ” 等 多 套 公 共 API ( 比 如 快 递 公 司 内 部 使 用 的 物 流 API

和 开 放 给 第 三 方 使 用 的 物 流 API ),所 以 可 能 会 有 两 个 API 网 关 ,对 应 会 有 两 套 API 目 录 和 两 套 鉴 权 体 系 , 所 以 , 它 们 是 “ 半 中 心 化 ” 。 这 些 都 是 中 心 化 、半 中 心 化 的 选 择 范 例 。每 一 次 中 心 化 的 选 择 都 可 能 会 让 整 个 架 构 变 得 死 板 ,失 去 灵 活 性 ,所 以 ,我 们 在 设 计 和 扩 展 基 建 的 时 候 应 该 特 别注意这个问题。 除了中心化的选择之外,架构发展的另一个关注点,是让业务保持“黑 盒”。 我们把每个服务之间的关联抽取了出来, 也把权限的定义和验证抽取了出 来 ,每 个 服 务 变 得 简 单 而 纯 粹 ,成 了 “ 纯 业 务 式 服 务 ” ,等 同 于 一 个 仅 包 含 了 业 务 规 则 的 黑 盒 。这 样 ,不 管 服 务 和 模 块 再 多 ,也 没 有 影 响 。业 务 的 重 用 性 也 很高。 总 而 言 之 ,搭 建 好 了 微 服 务 的 必 要 设 施 之 后 ,剩 下 的 就 要 根 据 实 际 情 况 和 项 目 经 验 来 继 续 调 整 了 。比 如 ,我 们 可 能 会 选 择 把 很 多 功 能 合 并 到 一 层 ,以 避 免过度分层所带来的不必要的性能损失,或者对整个基建进行一些细节微调。 只 要 把 控 好 “ 中 心 - 自 理 ” 和 “ 业 务 - 非 业 务 ” 之 间 的 关 系 ,这 个 基 础 设 施 就 能 健康地发展。 微服务基建总结 总结此文, 微服务的基建应该包括如下一些组件 (按请求流中的出场顺序) :
?配置管理:配置集中管理。 ? API 网 关 : 对 外 的 API 总 目 录 ; API 依 赖 关 系 ; 发 起 鉴 权 。 ?服务名册:服务的注册和发现。 ?鉴权服务:提供鉴权服务:认证身份,验证功能权限。

?前置后端:按前端的需求拆解请求、调用服务,并汇总、转换结果。 ?消息中介:全局通知机制;异步调用机制。 ?回路熔断:隔离出问题的服务并等待其恢复;提供备用方案。 ?负载均衡:避免服务过载。

需 要 说 明 的 是 ,这 些 组 件 的 组 合 形 式 ,具 体 拆 分 形 式 ,是 否 需 要 ,都 需 要 结合实际项目和团队的情况来调整。本文权作抛砖引玉,请读者知悉。


链接Dev与Ops的正确姿势_图文.pdf

熟练掌握敏 捷和DevOps方法和实践,对软件研 发...(近期出版) 近期发表文章: Thoughtworks洞见:从集装...外包出去,满足个性化用户 体验,达到产品/服务价值的...