2022-01
Unix设计哲学在程序员的圈子里经久不衰,备受追捧。而Go
语言背后有很多Unix
与C语言
的影子,三位创始人Rob Pike(罗伯. 派克),Ken Thompson(肯. 汤普森)和Robert Griesemer(罗伯特. 格利茨默)都是这两块领域的泰山北斗。了解Unix的设计哲学,对写出优秀的代码很有帮助。
Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface. 做一件事,做好它。让程序能够互相协同工作。应该让程序处理文本数据流,因为这是一个通用的接口。
作为管道机制的发明者,Doug McIlroy对这块的解释重点很具有管道特色。这里,我们聚焦于一个点:做好一件事。
将其拆分一下,主要分为两块:
做好
这个标准,尽可能地按照自己的认知上限去做,才可能有成长)。case by case
去看。按照wiki上的说法,1、2可以归纳为 过早的优化是一切罪恶的根源,3、4可以理解为 疑惑不定之时最适合穷举。
而第五条就非常有意思,也就是 数据结构比算法更重要。
这点,和我们在刷算法题时认知相反 - 在做算法题目时,我们往往已经得到了一个具体的数据结构,要做的更多是根据这个数据结构选择合适的算法。当数据结构确定时,可选择的算法就很有限了,这也大大缩小了题解的范围。
在复杂的场景中,我们首先得确定数据结构,这一步尤为复杂:
关于Unix的设计哲学还有很多优秀的见解,但综合起来,可以归纳为KISS
原则,也就是简单性。希望大家能在工程实践中,多多思考怎么保证简单性,对做出优秀的设计会很有启发。
今天我们一起来看CNCF中的第二个项目 - CrossPlane
。它位于CNCF全景图中Kubernetes
旁,受众比较小。
先看一段来自官网 https://crossplane.io/ 的信息:
Crossplane is an open source Kubernetes add-on that enables platform teams to assemble infrastructure from multiple vendors, and expose higher level self-service APIs for application teams to consume, without having to write any code.
我们依旧抽取其中关键的词进行解析:
Kubernetes add-on
CrossPlane的定位是Kubernetes
的插件,并非一个独立的平台assemble infrastructure from multiple vendors
统一封装多个依赖方的基础设施expose higher level self-service APIs
暴露高层接口然后,官方描述了五个关键性的特征:
概括起来,可以定义为:使用 kubectl 封装了各类云的API,来统一管理基础设施、服务和应用。
我们从具体的实践角度来看,统一封装接口往往只是加分项,而核心在于 支持的云基础设施与服务的范围。
从 官方文档 可以看到,CrossPlane
主要支持了亚马逊云、谷歌云、微软云等厂商。可以看到,这款产品主要面向的是国外的公有云厂商。这其实也决定了CrossPlane
更多面向的是国外开发者。
学习CrossPlane
的更多细节,对我们来说暂时没有更大的意义。我们可以尝试着从其理念中得到以下启发:
CNCF
统一了大致上的理念,但细节上的实现各有不同;尤其是结合了账号、权限、资源分配等各类特性后,对接起来的复杂度很高。Kubernetes
这个核心项目带来大量侵入性极强的代码。这时,引入另一个项目作为防腐层,很具有扩展意义。今天的话题将围绕着一篇谈论微服务架构的文章展开。下面给出原文链接,以及一个翻译的版本:
文中给出了以下九个微服务特征:
这些点,每个抛出来都可以写一篇长文。建议有兴趣的各位可以阅读原文,结合自己的实践多多思考。
这里,我选择三个最近感触比较深的点,自己也曾经陷入过的认知误区,在这里和大家聊聊:
业务能力的概念很抽象,虽然我们会经常提及,但在实践过程中又往往容易忽略。
从系统的角度来看,业务能力往往就是对外呈现的功能,对应到内部的技术模块,往往已经决定了七七八八。如何将这些技术模块做合理的拆分与合并,就是微服务架构需要考量的点。这里我谈谈最近比较有心得的三个考量点:
当然,还有更多的内容,需要大家在实践中摸索。
这一点在云原生的服务中体现得淋漓尽致:以RPC、Service Mesh、服务发现等技术为代表。
终端体现在Pod
这一层,也就是对一个具体运行的App来说,通过Istio、CoreDNS等技术将分布式的服务做到和单体应用一致,然后通过轻量级的通讯方案,如HTTP进行交互。这种方式的优点很明显:
目前云原生的Service Mesh技术还未完全形成行业标准,相信很快随着它的落地,将迎来微服务的又一波热潮。
容错性设计,也就是为错误而设计,这一点很反直觉。
作为一名开发者,我们实现功能的思路往往是按照顺序的逻辑步骤;一个一个步骤的串联,才能保证最后的功能实现。但这个时候,如果要我们去关注各类错误的发生,小到网络波动、程序崩溃,大到机房断电,很容易无所适从。
这里,我谈谈自己的理解:主要从发生的概率与影响的严重程度来思考,不要过度追求细节。这里有一个很重要的权衡点 - **健壮性 **与 简单性 :一般来说,要保证程序足够健壮,会引入各种异常的容错性设计,增加系统的复杂度,但这一点并不是绝对的。
从系统整体功能的维度,虽然看起来增加了复杂度,但通过分层、模块化、服务拆分等方式,分而治之 - 一些简单的模块用简单的规则组合成一个大模块,可维护性远远高于一个复杂的模块。
CoreDNS
是CNCF全景图中 协调与服务发现 模块的核心项目,在Kubernetes
1.12版本之后成为了默认的DNS服务。熟悉CoreDNS
是掌握Kubernetes
必不可少的技能。
照例,我们先一起看下其核心定义,非常简洁明了:
官网 - CoreDNS: DNS and Service Discovery CNCF - CoreDNS is a DNS server that chains plugins
今天,我们将围绕一个关键词chains plugins
- 链式插件 展开,这也是CoreDNS
实现的核心特性。
官方对这个特性的定义如下,
CoreDNS chains plugins. Each plugin performs a DNS function, such as Kubernetes service discovery, prometheus metrics, rewriting queries, or just serving from zone files. And many more.
从中不难看出,CoreDNS
将各种DNS
的功能抽象成一个插件,进行链式调用。
我们用 官方github上的Corefile 来了解这个特性:
example.org:1053 {
file /var/lib/coredns/example.org.signed
transfer {
to * 2001:500:8f::53
}
errors
log
}
. {
any
forward . 8.8.8.8:53
errors
log
}
example.org:1053
时,依次触发 file、transfer、errors、log四个插件上面的语法与nginx
非常类似,而作者实际上是参考Caddy
软件进行设计的,有兴趣的可以查阅相关资料,例如这个 博客。
链式调用是一种表述形式非常强的语法:它以一个大众容易接受的顺序逻辑,讲述了一个完整的调用过程,将各个细节也描述地很清晰。
既然链式调用的描述方式那么棒,为什么目前没有大规模地推广到各类工具上呢?这里,我谈谈个人的三个理解:
CoreDNS
在设计之初就强制采用这种规范,没有历史包袱;同样的,Corefile这种声明方式,也或多或少带来了一些问题,例如:
5
是数字还是字符串;CoreDNS
的成功,链式调用插件 这个特性只体现了简单性的理念,并不是关键性的原因,而更多地是依赖大量开箱即用的插件。
云原生有五大代表性的技术 - 容器、服务网格、微服务、不可变基础设施和声明式 API。相对于其余四种概念,不可变基础设施 - Immutable Infrastructure
更难理解,今天我们来一起看看。
入门可以参考这篇文章 - https://zhuanlan.zhihu.com/p/382203966
网上可搜索到的不可变基础设施定义有很多,这里我选择一个比较有代表性的:
Immutable infrastructure refers to servers (or VMs) that are never modified after deployment.
从开发者的角度来看,不可变基础设施是一个很棒的概念。如果用一个词总结它的优点,那就是 时间与空间上的一致性。
如果有一个传统应用希望改造成适配 不可变基础设施 的场景,那么会有哪些常见的改造点呢?
第二点有些抽象,这里我举三个具体的例子:
但在实际的工程中,追求 不可变基础设施 很难完全落地,我们可以适当地做一些权衡:
不难看出,只要我们保证应用在基础设施上产生的数据 可在任意时间丢失,就能实现了一定程度上 应用无状态化,也能保证了不可变基础设施的落地。
不可变基础设施是一种理念,具体落地的技术非常依赖容器或虚拟机,以及分布式存储等配套设施。我们没有必要把它作为一种技术标准去强制执行,而应该结合现状,选择性地朝着这个方向不断优化。
Github: https://github.com/Junedayday/code_reading Blog: http://junes.tech/ Bilibili: https://space.bilibili.com/293775192