通过Serverless架构建立一个函数,并输出了Hello World,表明已经完成Serverless架构的初体验。接下来,我们以其中一个云厂商为例(例如阿里云)进行基础的小工具开发和建设,帮助读者进一步了解Serverless架构。
在日常生产中,获取客户端外网IP是一个非常常见的需求,但是在客户端直接获取外网IP实际上是一件比较困难的事情。这时候就会有一个简单的方法:在服务端开一个接口,即当客户端调用该接口之后,该接口返回其IP地址。
如果选择用Python语言来开发这个项目,其传统Web组件模型如图3-27所示。
图3-27 传统Web项目组件模型简图
这里包括Nginx、Python的环境,以及所需要的Web Framework(例如Django、Flask、Bottle、Web2py等),除此之外还包括业务逻辑。在项目开发完成,上线之后,用户还需要对服务器的健康等持续关注,必要时还要做一些高可用方案。在Serverless架构下,这个过程将会变得非常简单,如图3-28所示。
图3-28 Serverless应用组件模型简图
在整个项目中,用户无须关注Nginx这些服务器软件,无须关注Python等环境的安装配置,更不用关注服务器的运维操作,在很多时候也无须关注高可用,只需关心函数代码。让使用者更关注业务逻辑,这也是Serverless的优势之一。
3.2.1 知识准备
为了更好地完成项目,以阿里云函数计算为例,在开始项目之前,我们需要明确一些概念、储备一些基础知识。
1. 什么是运行时
所谓的运行时,我们可以认为是一种环境或者说是一种支持,例如阿里云函数计算提供了Python 2.7的运行时,可以认为你的Python 2.7的应用是可以运行在该环境中的。针对不同的运行时,官方文档中都会有相关的描述。以Python相关的运行时为例,在官网上可以看到相关运行时的描述信息,包括日志的输出方法、所支持的编程语言及版本、所运行的系统类型及版本,以及默认集成的工具/模块/依赖等。
2. 什么是触发器
众所周知,函数计算是通过事件进行触发的。触发器是触发函数执行的方式。在事件驱动的计算模型中,事件源是事件的生产者,函数是事件的处理者,而触发器提供了一种集中、统一的方式来管理不同的事件源。如果发生的事件满足触发器定义的规则,事件源会自动调用触发器所对应的函数。
当然,不同的事件源和函数有一个事件的数据结构的规约。当事件源因为某些规则触发了函数,那么预先规约好的数据结构将会作为参数之一传递给函数。阿里云对象存储与函数计算规约的事件数据结构如下。
{ "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161****" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.***.***" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] }
如果为函数计算设置了OSS触发器,并绑定了某个对象存储的存储桶,当这个存储桶满足绑定操作时,会生成一个事件并触发函数。例如,为函数计算设置一个OSS触发器,并绑定存储桶MyServerlessBook(这个存储桶通常需要和用户设置的函数在同一个账号、同一个地域中),且设置一个触发条件oss:ObjectCreated:PutObject(调用PutObject接口上传文件即会触发该函数),一旦该存储桶收到以PutObject接口上传的文件,就会按照之前规约好的数据结构生成一个事件,触发当前函数并将事件作为参数传递给函数。
3. 什么是函数入口
在学习C语言的时候,我们知道一个叫main的函数。main函数称为主函数。C程序总是从main函数开始执行,例如:
#include <stdio.h> int main(void) { printf("HelloWorld!\n"); return 0; }
其实在函数计算中也是这样,在创建函数的时候,也需要告知系统入口方法是什么。通常情况下,函数入口的格式为[文件名].[函数名]。以Python为例,创建函数时指定的Handler为index.handler,那么函数计算会去加载index.py中定义的handler函数。通常情况下,一个函数计算的入口方法会有两个参数,一个是event,一个是context:
def handler(event, context): return 'hello world'
- event:用户自定义的函数入参,以字节流的形式传给函数。其数据结构由用户自定义,可以是简单的字符串、JSON对象、图片(二进制数据)。函数计算不对event参数的内容进行任何解释。
对于不同的函数触发情况,event参数的值会有以下区别。
- 事件源服务触发函数时,会将事件以一种平台预定义的格式作为event参数的数据结构传给函数。用户可以根据此格式编写代码并从event参数中获取信息。例如OSS触发器触发函数时,会将存储桶及文件的具体信息以JSON格式传递给event参数。
- 函数通过SDK直接调用时,用户可以在调用方法和函数代码之间自定义event参数。调用方按照定义好的格式传入数据,函数代码按格式获取数据。例如定义一个JSON类型的数据结构{"key":"val"}作为event参数的数据结构。当调用方传入数据{"key":"val"}时,函数先将字节流转换成JSON格式,再通过event["key"]来获得值val。
- context:函数计算平台定义的函数入参。它的数据结构由函数计算设计,包含函数运行时的信息。其使用场景通常有两种,一种是获取用户的临时密钥信息,通过context中的临时密钥去访问阿里云的其他服务(使用示例中以访问OSS为例),避免在代码中使用密钥硬编码。另一种是获取本次执行的基本信息,例如requestId、serviceName、functionName、qualifier等。在阿里云函数计算中,context的结构基本如下。
{ requestId: '9cda63c3-1ac9-45ba-8a59-2593bb9bc101', credentials: { accessKeyId: 'xxx', accessKeySecret: 'xxx', securityToken: 'xxx' }, function: { name: 'xxx', handler: 'index.handler', memory: 512, timeout: 60, initializer: 'index.initializer', initializationTimeout: 10 }, service: { name: 'xxx', logProject: 'xxx', logStore: 'xxx', qualifier: 'xxx', versionId: 'xxx' }, region: 'xxx', accountId: 'xxx' }
当然,在第2章中,细心的读者应该已经发现,阿里云函数计算相对于其他云厂商的函数计算,在创建函数的时候多了一个选项:HTTP函数。与普通的事件函数不同的是,HTTP函数更适合快速构建Web服务等场景。HTTP触发器支持以HEAD、POST、PUT、GET和DELETE方式触发函数。同时,HTTP函数的入参和Response也略微不同,以官方例子为例:
# -*- coding: utf-8 -*- import json HELLO_WORLD = b"Hello world!\n" def handler(environ, start_response): request_uri = environ['fc.request_uri'] response_body = { 'uri':environ['fc.request_uri'], 'method':environ['REQUEST_METHOD'] } # do something here status = '200 OK' response_headers = [('Content-type', 'text/json')] start_response(status, response_headers) # Python2 return [json.dumps(response_body)] # Python3 tips: When using Python3, the str and bytes types cannot be mixed. # Use str.encode() to go from str to bytes # return [json.dumps(response_body).encode()]
当然,HTTP函数的一个优势是更加容易与传统的Web框架进行结合。以Python的轻量级Web框架Flask为例:
# index.py from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!'
此时,只需要将函数的入口方法设置为index.app,即可实现一个Flask项目运行在函数计算上。这个过程相对于很多在函数计算层面将JSON对象转换成Request对象的方案要方便得多。当然除了这一点之外,HTTP函数的优势还包括如下内容。
- 减少了开发人员的学习成本和调试过程,可帮助开发人员快速使用函数计算搭建Web Service和API。
- 支持选择熟悉的HTTP测试工具验证函数计算侧的功能和性能。
- 减少请求处理环节,HTTP触发器支持更高效的请求、响应格式,不需要编码或解码成JSON格式,性能更优。
- 方便对接其他支持Webhook回调的服务,例如CDN回源、MNS等。
标签:Serverless,触发器,函数,计算,xxx,开发,事件,应用,event From: https://www.cnblogs.com/muzinan110/p/17067627.html