Circuit
CIRCUIT 是一种新的思维方式。 它表面上与现有软件相似,但实际上却截然不同。
Circuit 是一种可编程平台即服务(PaaS)和/或基础架构即服务(IaaS),用于管理、发现、同步和编排包含云应用程序的服务和主机。
Circuit 的设计是为了在技术企业中实现清晰、可靠和安全的人机接口,最终提高生产力。上面说明了典型的基于 Circuit 的体系结构中的工程角色分离。
circuit 的用户是:
- 运营工程师,负责在主机、进程和网络级别维护云应用程序
- 数据科学家,他们通过连接和分发第三方实用程序来开发分布式计算管道
- 分布式软件的制造商,他们希望以标准化的方式编写安装和维护过程的代码,而不是通过文档(即 MySQL)进行通信。
circuit 的一些技术特点:
- 单一和多数据中心开箱即用
- 系统流量的认证和安全
- 基于 TCP 和 UDP 多播(类似于 mDNS)的内部节点发现
- 零配置/盲重启,以便在主机配置端轻松重启
- 全局的、视图一致的键值空间,其中键是分层的路径,值是数据、进程、同步等的控制对象。
- 在物理主机的超高流失率下保持一致性
- 对 API 的命令行和编程访问
- 与 Docker 集成
在典型的 circuit 场景中:
- 供应工程师确保新配置的计算机在启动时作为守护程序启动零配置 circuit 服务器。
- 作工程师通过命令行工具或语言绑定来编程启动和动态响应行为。
采用注意事项:
- 占用空间小:circuit 守护进程空闲时几乎不留下任何通信和内存占用。这使得 circuit 与已有的架构一起,成为增量采用的理想选择。
- 直接影响:即使是简短而简单的 circuit 脚本也可以节省手动时间
- 知识核算:circuit 脚本可以用可执行的发现、诊断、行动和不行动的方法来代替文本的事后分析报告。
- circuit 服务器以执行顺序记录所有操作,从而在事后调试和分析期间实现最大的可见性。
编程环境:
- circuit 程序(circuit API 的调用序列)不是声明性的(如 Puppet,Chef 等)。它们实际上是 CSP 并发模型中的命令式程序,该模型允许工程师编码跨越多个数据中心的复杂动态响应行为。
在 wiki 中查找与其他技术(如 Zookeeper,etcd,CoreOS,raft,Consul,Puppet,Chef 等)的比较。
无与伦比但相关的作品
- Google Cloud Platform and Kubernetes
- Hashicorp Consul
- Puppet
- Chef
- Ansible
- CoreOS
- Apache Zookeeper
- Polymer (Google)
- Julia (MIT)
- 等等......
这些相关产品都不认为集群是一个封闭的系统。在这种情况下,circuit 就不同了。下一节将以精确的术语解释这一点。
集成
circuit 是一个微小的服务器进程,它在一组机器上运行实例,形成一个高效、灵活的网络,从而实现任何一台机器的分布式流程编排和同步。
circuit 的一些目标应用是:
- 例如,在数值计算中,复杂计算流水线的自动动态编排
- 打包和分发可以自组织成复杂云应用程序的通用分布式二进制文件
- 小型和大型 OPS 工程工作流程的增量自动化
通过快速启动幻灯片直接投入其中。
有关 The Circuit 的概念性介绍,请查看 GopherCon 2014 视频。由于录制了本视频,API-via-file-system 方法被抛弃,取而代之的是更简单的命令行工具和 Go 客户端库。
另请参阅高级教程:带有后通道的 Watchbot 的仿真动画演示。
circuit 是通过命令行工具和客户端库在整个集群中执行和同步 UNIX 进程的工具。
circuit 是一个二进制文件,用于服务器和命令行客户端。
构建
circuit 包含一个小二进制文件。它可以为 Linux 和 Darwin 构建。
假设已经安装了 Go 语言编译器,您可以使用一行构建和安装 circuit 二进制文件:
go get github.com/gocircuit/circuit/cmd/circuit
运行服务器
可以使用该命令异步(并以任何顺序)启动 circuit 服务器
circuit start -a 10.0.0.1:11022
所有实例都使用相同的命令。 -if 选项指定要绑定到的网络接口,而 -discover 命令指定要用于自动服务器 -- 服务器发现的 UDP 多播通道的 IP 地址。
通过将环境变量 CIRCUIT_DISCOVER 设置为等于所需的多播地址,可以省略 -discover 选项。
备选高级服务器启动
要在第一台机器上运行 circuit 服务器,请选择一个公共 IP 地址和端口让它监听,并像这样启动它
circuit start -a 10.0.0.1:11022
circuit 服务器将在其标准输出上打印自己的 circuit URL。应该是这样的:
circuit://10.0.0.1:11022/78517/Q56e7a2a0d47a7b5d
复制它。我们需要它告诉下一个 circuit 服务器在网络中即 “join” 这个circuit,即 circuit。
登录到另一台机器,同样在那里启动一个 circuit 服务器。这次,使用 -j 选项告诉新服务器加入第一个:
circuit start -a 10.0.0.2:11088 -j circuit://10.0.0.1:11022/78517/Q56e7a2a0d47a7b5d
您现在有两个相互感知的 circuit 服务器,运行在集群中的两个不同主机上。
您可以以类似的方式将任意数量的附加主机连接到 circuit 环境,甚至是数十亿台主机。该 circuit 采用了一种基于扩展器的现代图形算法,实现了真实的分布式状态感知和有序通信;它很少使用通信和连接,空闲时几乎不留痕迹。
编程框架
每个 circuit 服务器的目的是代表用户托管一组称为 elements 的控制原语。在每个服务器上,托管的元素都组织在一个层次结构中(类似于 Apache Zookeeper 中的文件系统),其节点称为锚。锚(类似于文件系统目录)有名称,每个锚可以承载一个 circuit 元素或为空。
所有服务器的层次结构在逻辑上由全局 circuit 根锚统一,其子节点是各个 circuit 服务器层次结构。一个典型的锚路径是这样的
/X317c2314a386a9db/hi/charlie
路径的第一个组件是托管叶子锚点的 circuit 服务器的ID。
除了 circuit 根锚(其不对应于任何特定 circuit 服务器)之外,所有其他锚可以存储过程或信道元素,至多一个,并且另外可以具有任何数量的子锚。在某种程度上,锚点就像目录,可以有任意数量的子目录,但最多只有一个文件。
创建 circuit 元素并与之交互是用户控制和反映其分布式应用程序的机制。这可以通过包含的Go客户端库或使用 circuit 可执行文件本身中包含的命令行工具来完成。
过程元素用于在主机 circuit 服务器上执行,监视和同步 OS 级进程。它们允许从 circuit 集群中的任何机器查看和控制 OS 进程,而不管底层 OS 进程的物理位置如何。
通道元素是同步原语,类似于 Go 中的通道,其发送和接收侧可从 circuit 集群中的任何位置访问,而其数据结构存在于托管其锚点的 circuit 服务器上。
使用
一旦 circuit 服务器启动,您就可以交互式地创建、观察和控制 circuit 元件(i)使用兼作命令行客户端的 circuit 二进制 -- 以及(ii)以编程方式使用 circuit Go 客户端软件包 github.com/gocircuit/circuit/client。事实上,circuit 命令行工具只是Go客户端库的前端。
客户端(工具或您自己的)拨入 circuit 服务器以与整个系统进行交互。所有服务器在各方面都是平等的公民,特别是任何一台服务器都可以作为拨入的选择。
该工具(稍后更详细地描述)本质上是一组命令,允许您遍历 circuit 元素的全局分层命名空间,并与它们交互,有点类似于使用 Zookeeper 命名空间的方式。
例如,要列出整个 circuit 集群锚点层次结构,请键入
circuit ls /
然后,你可能会得到这样的回应
/X88550014d4c82e4d /X938fe923bcdef2390
两个根级锚点对应于两个 circuit 服务器。
将工具指向 circuit 群
在使用 circuit 工具之前,您需要告诉它如何为我们找到一个 circuit 服务器拨入点。
有两种方法可以为工具提供拨入服务器地址:
如果使用 -discover 选项或 CIRCUIT_DISCOVER 环境变量启动 circuit 服务器,则命令行工具可以使用相同的方法查找 circuit 服务器。例如:
circuit ls -discover 228.8.8.8:7711 /...
或者,
export CIRCUIT_DISCOVER=228.8.8.8:7711 circuit ls /...
使用命令行选项 -d,例如
circuit ls -d circuit://10.0.0.1:11022/78517/Q56e7a2a0d47a7b5d /
或者,等效地,通过将环境变量 CIRCUIT 设置为指向其内容是所需拨入地址的文件。例如,(在 bash 中):
echo circuit://10.0.0.1:11022/78517/Q56e7a2a0d47a7b5d > ~/.circuit export CIRCUIT="~/.circuit" circuit ls /
帮助屏幕上显示了可用工具命令的列表
circuit help
有关其含义和功能的更详细说明,请参见客户端软件包 github.com/gocircuit/client 的文档。
示例:制作流程
这里有一些例子。要在某个选定的群集计算机上运行新进程,请首先查看可用的计算机:
circuit ls /... /X88550014d4c82e4d /X938fe923bcdef2390
运行一个新的 ls 进程:
circuit mkproc /X88550014d4c82e4d/pippi << EOF { "Path": "/bin/ls", "Args":["/"] } EOF
看看发生了什么:
circuit peek /X88550014d4c82e4d/pippi
关闭标准输入以表示无意写入:
cat /dev/null | circuit stdin /X88550014d4c82e4d/pippi
读取输出(请注意,在您先关闭标准输入之前,输出不会显示,如上所示):
circuit stdout /X88550014d4c82e4d/pippi
从锚点层次结构中删除 process 元素
circuit scrub /X88550014d4c82e4d/pippi
示例:创建一个 docker 容器
与 OS 进程的情况非常相似,该 circuit 可以创建、管理和同步 Docker 容器,并将相应的 docker 元素附加到锚文件系统中的路径。
要允许创建 docker 元素,必须使用 -docker 开关启动任何单个服务器。 例如:
circuit start -if eth0 -discover 228.8.8.8:7711 -docker
要使用该工具创建和执行新的 docker 容器:
circuit mkdkr /X88550014d4c82e4d/docky << EOF { "Image": "ubuntu", "Memory": 1000000000, "CpuShares": 3, "Lxc": ["lxc.cgroup.cpuset.cpus = 0,1"], "Volume": ["/webapp", "/src/webapp:/opt/webapp:ro"], "Dir": "/", "Entry": "", "Env": ["PATH=/usr/bin"], "Path": "/bin/ls", "Args": ["/"], } EOF
与 docker 命令行工具对应的命令行选项类似,可以省略这些字段中的大多数。
其余的 docker 元素命令与进程的命令相同:stdin、stdout、stderr、peek 和 wait。在一个异常中,peek 将返回容器的详细描述,该描述来自 docker inspect。
示例:创建频道
再次,看一下可用的服务器:
circuit ls /... /X88550014d4c82e4d /X938fe923bcdef2390
选一个。 假设是 X88550014d4c82e4d。 现在,让我们在 X88550014d4c82e4d 上创建一个频道:
circuit mkchan /X88550014d4c82e4d/this/is/charlie 3
该行的最后一个参数是通道缓冲容量,类似于在 Go 中创建通道的方式。
验证通道已创建:
circuit peek /X88550014d4c82e4d/this/is/charlie
这应该打印出这样的东西:
{ "Cap": 3, "Closed": false, "Aborted": false, "NumSend": 0, "NumRecv": 0 }
使用该命令完成向通道发送消息
circuit send /X88550014d4c82e4d/this/is/charlie < some_file
从上面命令的标准输入中读出消息的内容。 除非消息的通道缓冲区中有可用空间,否则此命令将阻塞,直到接收器可用。
当命令解除阻塞时,它将向接收器发送任何数据。 如果没有接收器,但消息缓冲区中有空格,该命令也将解除阻塞并消耗其标准输入(将其保存为最终接收器),但最多只能为32K字节。
使用该命令完成接收
circuit recv /X88550014d4c82e4d/this/is/charlie
收到的消息将在上面命令的标准输出上生成。
示例:创建 DNS 服务器元素
Circuit 允许您在任何 circuit 服务器上创建和动态配置一个或多个DNS服务器元素。
和以前一样,选择一个可用的 circuit 服务器,比如 X88550014d4c82e4d。像这样创建一个新的DNS服务器元素
circuit mkdns /X88550014d4c82e4d/mydns
这将在给定 circuit 服务器的主机上启动新的 DNS 服务器,将其绑定到可用端口。或者,您可以提供指定绑定地址的IP地址参数,如
circuit mkdns /X88550014d4c82e4d/mydns 127.0.0.1:7711
无论哪种方式,您都可以通过窥视相应的 circuit 元素来检索DNS服务器正在侦听的地址:
circuit peek /X88550014d4c82e4d/mydns
此命令将生成类似于此的输出
{ "Address": "127.0.0.1:7711", "Records": {} }
创建 DNS 服务器元素后,您可以使用一次一个地添加资源记录
circuit set /X88550014d4c82e4d/mydns "miek.nl. 3600 IN MX 10 mx.miek.nl."
资源记录使用各种 RFC 中描述的规范语法。您可以在 DNS Go 库中找到此类 RFC 的列表以及作为我们实施基础的示例:github.com/miekg/dns/dns.go
可以使用单个命令删除与给定名称关联的所有记录:
circuit unset /X88550014d4c82e4d/mydns miek.nl.
通过查看元素,可以检索当前活动记录集:
circuit peek /X88550014d4c82e4d/mydns
假设一个名称有多个与之关联的记录,peek 会产生类似于这个的输出:
{ "Address": "127.0.0.1:7711", "Records": { "miek.nl.": [ "miek.nl.\t3600\tIN\tMX\t10 mx.miek.nl.", "miek.nl.\t3600\tIN\tMX\t20 mx2.miek.nl." ] } }
示例:在服务器上侦听 join 和 leave 通知
该 circuit 提供了两种特殊的元素类型 @join 和 @leave,称为订阅。他们的工作是在新的 circuit 服务器加入系统或其他人离开时通知您。它们都表现得像只接收频道。
circuit mk@join /X88550014d4c82e4d/watch/join circuit mk@leave /X88550014d4c82e4d/watch/leave
每次cicruit服务器加入系统时,join订阅都会发送一条新消息。收到的消息保存新服务器的锚路径。
circuit recv /X88550014d4c82e4d/watch/join
同样,每次 circuit 服务器从系统中消失时,休假订阅都会发送一条新消息。
circuit peek /X88550014d4c82e4d/watch/join
要有创意
该 circuit 允许在流程编排中具有不寻常的灵活性。例如,看看两个“watchbot”教程,它们演示了如何在集群中实现半弹性自持机制。在这里找到更简单的一个
https://github.com/gocircuit/circuit/tree/master/tutorial/watchbot
在这里,更精致的一个展示了频道的使用
https://github.com/gocircuit/circuit/tree/master/tutorial/watchbot-with-chan
安全
默认情况下, circuit 服务器和客户端通过纯文本TCP进行通信。支持基于 HMAC 的对称认证,其后是非对称RC4流密码。
要启用加密,请使用 -hmac 命令行选项将 circuit 可执行文件指向包含 circuit 私钥的文件。例如:
circuit start -a 10.0.0.1 -hmac .hmac
或者,如果您正在调用该工具:
circuit ls -hmac .hmac /...
或者,您可以将环境 CIRCUIT_HMAC 设置为指向私钥文件。
要为 circuit 生成新的私钥,请使用该命令
circuit keygen
网络
从网络和协议的角度来看, circuit 服务器和客户端是对等的:所有通信(服务器 - 服务器和服务器 - 客户端)都使用通用的 RPC 框架,这通常需要服务器能够反向拨入客户端。
出于这个原因, circuit 客户端( circuit 工具或您的应用程序)不能在他们拨入的服务器的防火墙后面。
学到更多
向 The Circuit 用户组 提问。
用于编写 circuit 应用程序的 Go 客户端包
github.com/gocircuit/circuit/client
该软件包的公共接口是独立的。 circuit 仓库中的其他封装是内部的。
可以在客户端软件包目录中找到教程
github.com/gocircuit/circuit/client/tutorial
此外, circuit 二进制目录包含 circuit 工具的实现, circuit 工具本身是使用客户端构建的,是 circuit 应用程序的另一个综合示例。它可以在
github.com/gocircuit/circuit/cmd/circuit
要及时了解最新的开发,文档和文章,请关注Twitter @gocircuit 上的 The Circuit Project 或 @maymounkov。
用推特捐款
请关于 circuit 的推文(提及 @gocircuit)。推文是一种非常受欢迎的捐赠,它们帮助我们和我们的赞助商衡量对这种非常规想法的兴趣。
(First edition: vz edited at 2019.09.07)