OpenWhisk是一个事件驱动的计算平台,也称为无服务器计算或功能即服务(FaaS),用于响应事件或直接调用而运行代码。下图显示了高级OpenWhisk体系结构。
事件的示例包括数据库记录的更改,超过特定温度的IoT传感器读数,将新代码提交到GitHub存储库或来自Web或移动应用程序的简单HTTP请求。来自外部和内部事件源的事件通过触发器进行传递,并且规则允许操作对这些事件做出反应。
操作可以是小的代码片段(支持JavaScript,Swift和许多其他语言),也可以是嵌入在Docker容器中的自定义二进制代码。每当触发触发器时,OpenWhisk中的操作就会立即部署并执行。触发次数越多,调用的动作越多。如果没有触发触发器,则不会运行任何操作代码,因此没有成本。
除了将动作与触发器相关联之外,还可以通过使用OpenWhisk API,CLI或iOS SDK直接调用动作。一组动作也可以链接在一起,而无需编写任何代码。依次调用链中的每个动作,并将一个动作的输出作为输入传递到序列中的下一个动作。
对于传统的长期运行的虚拟机或容器,通常的做法是部署多个VM或容器以抵御单个实例的故障。但是,OpenWhisk提供了一种替代模型,没有与弹性相关的成本开销。按需执行操作可提供固有的可伸缩性和最佳利用率,因为正在运行的操作数始终与触发率匹配。此外,开发人员现在只关注代码,而不必担心监视,修补和保护基础服务器,存储,网络和操作系统基础结构。
与其他服务和事件提供程序的集成可以随包一起添加。一揽子计划是一堆提要和操作。提要是一段代码,用于配置外部事件源以触发触发事件。例如,使用Cloudant变更Feed创建的触发器将配置服务,以在每次文档被修改或添加到Cloudant数据库时触发该触发器。包中的动作表示服务提供者可以提供的可重用逻辑,以便开发人员不仅可以将服务用作事件源,还可以调用该服务的API。
现有的软件包目录提供了一种快速的方法来增强具有有用功能的应用程序,并访问生态系统中的外部服务。启用了OpenWhisk的外部服务的示例包括Cloudant,The Weather Company,Slack和GitHub。
OpenWhisk的工作方式
作为一个开源项目,OpenWhisk站在Nginx,Kafka,Docker,CouchDB等巨头的肩膀上。所有这些组件共同构成了“无服务器基于事件的编程服务”。为了更详细地解释所有组件,让我们跟踪动作在系统发生时的调用。无服务器引擎的核心工作是OpenWhisk中的调用:执行用户输入到系统中的代码,并返回执行结果。
创建动作
为了提供一些上下文说明,我们首先在系统中创建一个动作。我们将在稍后浏览系统时使用该操作来解释概念。以下命令假定已正确设置OpenWhisk CLI。
首先,我们将创建一个包含以下代码的action.js文件,该代码会将“ Hello World”打印到标准输出,并在键“ hello”下返回一个包含“ world”的JSON对象。
function main() { console.log('Hello World'); return { hello: 'world' }; }
我们使用创建该动作。
wsk action create myAction action.js
做完了 现在我们实际上要调用该动作:
wsk action invoke myAction --result
内部处理流程
OpenWhisk幕后实际上发生了什么?
进入系统:nginx
第一:OpenWhisk的面向用户的API完全基于HTTP,并采用RESTful设计。因此,通过wsk CLI发送的命令实际上是针对OpenWhisk系统的HTTP请求。上面的特定命令大致翻译为:
POST /api/v1/namespaces/$userNamespace/actions/myAction Host: $openwhiskEndpoint
注意这里的$ userNamespace变量。用户可以访问至少一个名称空间。为了简单起见,假设用户拥有放置myAction的名称空间。
进入系统的第一个入口是通过nginx,“ HTTP和反向代理服务器”。它主要用于SSL终止并将适当的HTTP调用转发到下一个组件。
进入系统:控制器
对我们的HTTP请求没有做很多事情,nginx将其转发到Controller,这是我们通过OpenWhisk进行的下一个组件。它是实际REST API(基于Akka和Spray)的基于Scala的实现,因此可以用作用户可以做的所有事情的接口,包括在OpenWhisk中对实体的CRUD请求和动作的调用(这就是我们的现在正在做)。
控制器首先消除用户要做什么的歧义。它基于您在HTTP请求中使用的HTTP方法来执行此操作。根据上面的翻译,用户向现有动作发出POST请求,控制器将其转换为动作的调用。
鉴于控制器的中心作用(因此得名),以下步骤在一定程度上都会涉及它。
身份验证和授权:CouchDB
现在,控制器将验证您的身份(身份验证),以及您是否有权对实体执行您想做的事情(授权)。将根据CouchDB实例中的所谓主题数据库验证请求中包含的凭据。
在这种情况下,将检查用户是否存在于OpenWhisk的数据库中,并检查该用户是否有权调用动作myAction,我们假设该动作是用户拥有的命名空间中的动作。后者有效地赋予了用户调用该操作的特权,这是他希望执行的操作。
一切正常后,门打开,进入下一阶段的处理。
采取行动:再次CouchDB…
由于Controller现在确定允许用户进入并具有调用其操作的特权,因此它实际上是从CouchDB的拂数据库中加载了此操作(在本例中为myAction)。
动作记录主要包含要执行的代码(如上所示)和要传递给动作的默认参数,并与实际调用请求中包含的参数合并。它还包含执行时对其施加的资源限制,例如允许使用的内存。
在这种特殊情况下,我们的操作没有任何参数(该函数的参数定义是一个空列表),因此我们假设我们没有设置任何默认参数,也没有向该操作发送任何特定的参数,从这个角度来看,最琐碎的情况。
谁来执行该操作:负载均衡器
作为控制器一部分的负载均衡器通过连续检查其运行状况来全局查看系统中可用的执行器。这些执行者被称为祈求者。知道哪些可用的调用程序的负载均衡器会选择其中之一来调用请求的操作。
请排队:Kafka
从现在开始,您发送的调用请求可能主要发生两件事:
- 系统可能崩溃,丢失您的调用。
- 系统可能会承受如此沉重的负担,以至于调用需要先等待其他调用才能完成。
两者的答案都是Kafka,“一个高吞吐量,分布式,发布-订阅消息系统”。Controller和Invoker仅通过Kafka缓冲和保留的消息进行通信。这样就减轻了控制器和调用者的内存缓冲负担,并冒出OutOfMemoryException的风险,同时还确保在系统崩溃的情况下不会丢失消息。
为了调用该动作,控制器将消息发布到Kafka,其中包含要调用的动作和传递给该动作的参数(在本例中为无)。该消息发送给控制器从上方从可用调用者列表中选择的调用者。
Kafka确认收到消息后,将使用ActivationId响应对用户的HTTP请求。用户稍后将使用它来访问此特定调用的结果。请注意,这是一个异步调用模型,在该模型中,一旦系统接受了调用某个动作的请求,HTTP请求就会终止。可以使用同步模型(称为阻塞调用),但本文不会介绍。
实际上已经在调用代码了:调用者
调用程序是OpenWhisk的心脏。调用者的职责是调用一个动作。它也在Scala中实现。但是还有更多的东西。为了以隔离和安全的方式执行操作,它使用Docker。
Docker用于为我们以快速,隔离和受控的方式调用的每个动作设置一个新的自封装环境(称为容器)。简而言之,对于每个动作调用,都会产生一个Docker容器,该动作代码被注入,并使用传递给它的参数执行该操作代码,获得结果,该容器被销毁。这也是进行大量性能优化以减少开销和缩短响应时间的地方。
在我们的特定情况下,由于手头有一个基于Node.js的操作,Invoker将启动一个Node.js容器,从myAction注入代码,不带任何参数运行它,提取结果,保存日志并销毁再次使用Node.js容器。
存储结果:再次CouchDB
由于调用者获得了结果,因此将其存储为激活数据库,作为上面进一步提到的ActivationId下的激活。激活数据库位于CouchDB中。
在我们的特定情况下,Invoker从操作中获取返回的JSON对象,获取Docker编写的日志,将它们全部放入激活记录中并将其存储到数据库中。大致如下所示:
{ "activationId": "31809ddca6f64cfc9de2937ebd44fbb9", "response": { "statusCode": 0, "result": { "hello": "world" } }, "end": 1474459415621, "logs": [ "2016-09-21T12:03:35.619234386Z stdout: Hello World" ], "start": 1474459415595, }
注意记录如何包含返回的结果和写入的日志。它还包含操作调用的开始时间和结束时间。激活记录中有更多字段,为简化起见,这是简化版本。
现在,您可以再次使用REST API(再次从步骤1开始)以获取激活,从而获得操作结果。为此,您可以使用:
wsk activation get 31809ddca6f64cfc9de2937ebd44fbb9
摘要
我们已经了解了一个简单的wsk动作如何调用myAction贯穿OpenWhisk系统的不同阶段。系统本身主要仅包含两个自定义组件,即Controller和Invoker。其他一切都已经存在,由开源社区中如此众多的人开发。
您可以在以下主题中找到有关OpenWhisk的其他信息:
- 实体名称
- 动作语义
- 限度
- REST API