1984 年,Rob Pike 和 Brian W. Kernighan 在 AT&T 贝尔实验室技术期刊上发表了一篇名为“Unix 环境中的程序设计”的文章,文章中他们以 BSD 的 cat -v 实现为例,论证了 Unix 哲学。简而言之,该哲学是:构建小型、专注的程序(无论使用何种语言),这些程序只做一件事,但要做好这件事,通过 stdin/stdout 进行通信,并通过管道连接。
听起来耳熟吗?
是的,我也这么认为。这与 James Lewis 和 Martin Fowler 提供的 微服务定义 非常相似。
简而言之,微服务架构风格是将单个应用程序开发为一组小型服务的 approach,每个服务都在自己的进程中运行,并通过轻量级机制(通常是 HTTP 资源 API)进行通信。
虽然一个 *nix 程序或一个微服务本身可能非常有限甚至不是很有趣,但正是这些独立工作单元的组合揭示了它们的真正好处,以及因此而来的力量。
*nix 与微服务
下表比较了 *nix 环境(例如 cat 或 lsof)中的程序与微服务环境中的程序。
*nix | 微服务 | |
---|---|---|
执行单元 | 使用 stdin/stdout 的程序 | 具有 HTTP 或 gRPC API 的服务 |
数据流 | 管道 | ? |
配置和参数化 | 命令行参数、 环境变量、配置文件 |
JSON/YAML 文档 |
发现 | 包管理器、man、make | DNS、环境变量、OpenAPI |
让我们更详细地探讨每一行。
执行单元
*nix(例如 Linux)中的执行单元是可执行文件(二进制文件或解释型脚本),理想情况下,它从 stdin 读取输入并将输出写入 stdout。微服务设置处理的是公开一个或多个通信接口(例如 HTTP 或 gRPC API)的服务。在这两种情况下,您都会找到无状态示例(本质上是纯粹的功能行为)和有状态示例,在有状态示例中,除了输入之外,一些内部(持久化)状态决定了会发生什么。
数据流
传统上,*nix 程序可以通过管道进行通信。换句话说,感谢 Doug McIlroy,您无需创建临时文件来传递数据,并且每个文件都可以处理进程之间几乎无尽的数据流。据我所知,除了我 2017 年基于 Apache Kafka 的小型实验之外,微服务中没有与管道标准化的东西。
配置和参数化
您如何配置程序或服务——无论是永久性的还是按需的?嗯,对于 *nix 程序,您基本上有三个选项:命令行参数、环境变量或完整的配置文件。在微服务中,您通常处理 YAML(甚至更糟,JSON)文档,这些文档定义了单个微服务的布局和配置,以及依赖项和通信、存储和运行时设置。示例包括 Kubernetes 资源定义、Nomad 作业规范或 Docker Compose 文件。这些可能是参数化的,也可能不是;也就是说,要么您有一些模板语言(例如 Kubernetes 中的 Helm),要么您会发现自己做了很多 sed -i 命令。
发现
您如何知道有哪些程序或服务可用以及它们应该如何使用?嗯,在 *nix 中,您通常有一个包管理器以及古老的 man;在它们之间,它们应该能够回答您可能有的所有问题。在微服务设置中,在查找服务方面有更多的自动化。除了像 Airbnb 的 SmartStack 或 Netflix 的 Eureka 这样的定制方法之外,通常还有基于环境变量或基于 DNS 的 方法,允许您动态发现服务。同样重要的是,OpenAPI 为 HTTP API 文档和设计提供了事实上的标准,而 gRPC 为更紧密耦合的高性能用例提供了相同的标准。最后但并非最不重要的一点是,考虑到开发者体验 (DX),从编写良好的 Makefile 开始,到使用(或在?)style 编写文档结束。
优点和缺点
*nix 和微服务都提供了一些挑战和机遇
可组合性
设计一个具有清晰、明确焦点并且可以与他人良好协作的东西是很难的。跨不同版本正确地实现它并引入相应的错误处理能力就更难了。在微服务中,这可能意味着重试逻辑和超时——也许将这些功能外包到服务网格中是一个更好的选择?这很困难,但如果您做对了,它的可重用性将是巨大的。
可观察性
在单体应用(2018 年)或试图完成所有事情的大型程序(1984 年)中,当事情出错时,找到罪魁祸首是相当简单的。但是,在一个
yes | tr \\n x | head -c 450m | grep n
或涉及 20 个服务的微服务设置中的请求路径中,您甚至如何开始弄清楚哪个服务行为不端?幸运的是,我们有标准,特别是 OpenCensus 和 OpenTracing。如果您正在考虑迁移到微服务,可观察性可能仍然是最大的单一障碍。
全局状态
虽然对于 *nix 程序来说可能不是什么大问题,但在微服务中,全局状态仍然是一个讨论的问题。即,如何确保有效地管理本地(持久化)状态,以及如何尽可能轻松地使全局状态保持一致。
总结
最后,问题仍然是:您是否为给定的任务使用了正确的工具?也就是说,就像专门的 *nix 程序实现一系列功能可能是某些用例或阶段的更好选择一样,单体应用 可能是您组织或工作负载的最佳选择。无论如何,我希望本文能帮助您看到 Unix 哲学和微服务之间的许多强烈相似之处——也许我们可以从前者中学到一些东西来使后者受益。
5 条评论