我相信,我们从不缺精彩的应用创意,我们缺少的把这些想法变成现实的时间和付出。
我认为,无服务器技术真的有助于最大限度节省应用开发和部署的时间,并且无服务器技术用可控的成本,实现了我的那些有趣的想法。
在我 20 多年 IT 从业经历中,一直专注于 IT 基础架构的设计和搭建,并没有很多编程的经验。入职亚马逊云科技之后,我成为一名开发者布道师,为了了解和传播亚马逊云科技的无服务器技术,我做了一系列"这就是无服务器"的学习视频。我想仅仅了解技术的功能和特性是不够的,我还应该掌握如何利用无服务器技术,编译和运行代码来构建我的应用。
亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术,观点,和项目,并将中国优秀开发者或技术推荐给全球云社区。如果你还没有关注/收藏,看到这里请一定不要匆匆划过,点这里让它成为你的技术宝库!
你可能是和我一样,对编码比较陌生,只是在寻找一种方法来建立我们心中的应用程序。或者,你可能是一个有很多编码经验的人,但仅限于在服务器或容器上运行过应用程序,现在希望探索无服务器。无论你带着哪种目的关注这篇,我都希望以下的内容带你了解我的无服务器学习之旅,了解我如何从对无服务器一无所知到建立自己的应用程序。
项目背景
因为我所在的团队是一个分布在全球的组织。对于实现有效的沟通,语言是个重要工具。我在学习英文的同时,我的"歪果仁"同事也在学习中文。我们互为对方的语言老师。在学习的过程中,我发现中文的学习看起来要比英文学习更为困难。为了让我的同事跟上我的进度,我有了为他构建一个中文学习 app 的有趣想法。
首先这个应用程序要提供交付中文单词学习的日提醒服务。我想这个 app 设计逻辑应该是从一个词汇数据库里按照设定好的时间和规则拉出一个词,并通过邮件或者文本的方式发送给用户。
然而,我只是有一些 Python 和 JavaScript 简单的 coding 经验,但是我还是希望把这个 app 做成一个能真正被使用的语言学习 app:
- 它能够持续维护并可以扩展新功能;
- 作为一个运行在云端的真正的应用,我希望它的成本不要太高;
- 由于目前仅有一个运维工程师(就是本人)的 app,我希望它的运营和维护工作量也不要太大,而且最好它还能根据访问情况,自动的扩缩容(这个很重要)。
构建平台和服务的选择
对于这个应用,我选择无服务器服务和架构。
所谓的无服务器不是指没有服务器,代码的编译和运行还是需要服务器的计算资源,只是无论是代码编译还是运行,都不用配置和管理服务器。
举个例子,以前我们运行一个应用或者构建一个 web 网站,首先需要对服务器进行配置,包括系统安装,补丁以及更新。同时还需要容量的预估和分配。为业务高峰预留的资源大部分时间闲置,但是仍需付费。除此之外在整个应用的生命周期中,服务器的管理和运维也会花费很多时间。总而言之,除了应用构建本身,还需要大量的时间和资源花在服务器的管理上。
做为亚马逊云科技的构建者,我将这个应用部署在亚马逊云科技的云平台上并选用 Amazon Lambda,做为计算服务,通过 lambda 函数,运行任何类型的代码,我只需要把一段代码放进函数。同时由于它是事件驱动的,对于这个应用,日历做为事件来触发 lambda 函数运行代码。所有服务器相关的配置和管理工作由亚马逊云科技提供,而我只需要专注于应用本身,只需要专注于代码编译和运行。同时无服务器的技术特点就包括了自动扩缩容、按需付费,不用考虑底层计算资源的配置和预留,等等。
接下来,我需要 API 让应用的前端和后端进行交互,同时我选择 Amazon S3 和 Amazon DynamoDB 做为应用数据的存储。应用程序之间需要不同类型的粘合剂,因此我用到来亚马逊云科技提供其他无服务器架构的集成服务,包括:
- SQS 帮我创建消息队列;
- 使用 Amazon SNS 发送文本信息或电子邮件;
- Amazon EventBridge 通过设置一个按每天或每周的节奏运行的事件,来触发 lambda 函数;
- Amazon Step Functions 用来构建工作流;
- ...
我还需要托管我们静态内容的服务,比如 HTML 以及前端的相关内容,我选择了 Amazon Amplify。考虑到如果有用户需要登录这个网站或进行某种身份验证,因此我有用了 Amazon Cognito 来实现身份验证。
所有的这些服务协同工作,彼此深度集成,帮助我快速的构建应用。
开发工具和应用架构的选择
在设计开发这个应用程序的一开始,我花了很多时间在 testfunction console 和这个可爱的按钮上,因为它允许我当场测试我的函数代码的可行性。
如果你只是想学习一下 lambda,感受它是怎么工作的,测试你写的一小段代码是否正常工作,console 绝对是个好地方。你直观的看到代码执行过程中具体发生了什么。这是一种很好的方式去学习和理解 lambda 函数。
如果你只是想单纯的学习和测试一下函数,只是看看它们的样子,以及它们是如何工作的,使用 testfunction console 就可以了。
但是如果你想构建一个便于更改的应用程序,同时可以支持迭代更新,并且可以通过模版进行部署",那我建议您选择 "serverless infrastructure as code" 做为开发框架。
这意味着可以将整个应用程序都用代码定义,将所有变更都保存下来,对于开发过程中,需要回滚到应用程序的先前版本,或者确保每次都以正确的方式进行配置的要求,IaC 是非常有帮助。
对于 IaC 的开发框架,开发者们有很多选择,包括亚马逊云科技开源的 SAM(serverless application model),Serverless Framework,以及 Amazon Cloud development Kit or Amazon CDK。
我个人比较推荐使用 Amazon SAM。在这个中文学习 app 的构建中我使用了 Amazon SAM。原因是它对初学者很友好。
这是一段 SAM template,使用的 Python 3.8 运行:
如果你和我一样,也在亚马逊云科技云平台上构建应用,相信你一定用 IAM policy 对不同服务之间的调用进行过身份验证。那么你一定对很多很多行代码才能实现的过程印象深刻。而在这段 SAM policy template,SNS published message policy,仅仅需要两行代码。最后通过创建 "DailyEventBridgeEvent" 事件来触发 lambda 函数,就完成了。
使用 SAM 部署 serverless 应用,是不是真的很简单,容易上手?
对于 serverless 架构的应用来说,它可以自动获得云上的资源。因此我们需要常常面对资源的变化带来的部署问题。建议的方式是设置自动部署 pipeline。只要用一种非常简单的自动化方式来将代码添加到资源库,很快就能看到它们在云端上线,这是一种非常美好的感受。对于设置自动部署 pipeline,实现 CI/CD,有很多的工具和方式可以选择,比如 CircleCI,GitHub 以及亚马逊云科技提供的 Amazon CodePipeline。
无服务器应用构建
1. 消息发送
使用 Amazon EventBridge 来计划每日事件。Amazon EventBridge 将触发 lambda 函数,通过运行代码从 S3 存储桶中提取单词并随机选择一个做为今天的学习词汇。然后由 Amazon SNS 将这个随机选取的单词用短信的方式发送到手机端。基于这个架构的 lambda 函数代码示例。
ini
import json
import boto3
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')
def lambda_handler(event, context):
# Call S3 to retrieve today's vocabulary word
message = "Today's word is " + word
try:
response = sns_client.publish(
TargetArn='arn:aws:sns:us-east-1:1234567890:App',
Message=json.dumps({'default': json.dumps(message)}),
MessageStructure='json'
)
except Exception as e:
print(f"Failed to send text message. Error: {e}")
实现每提取一个词汇,生成一条消息,然后调用 SNS 将该消息发布到目标 ARN。在这里我将消息发布到我的一个同事的手机端,因此我只需要把 Target ARN 定义成他的手机号码,他就可以每天收到中文词汇的学习信息了。
2. 订阅模式的扩展
随着更多同事对这个中文学习的 app 感兴趣,我发现手动添加手机号码和功能管理就成了麻烦事儿。所以我决定再做一个订阅网站,通过用户界面让他们自己订阅或者退订。
如同所示,我做了小的调整:
为了节省成本,将中文词汇用 email 的方式发送客户端,替换掉之间短信发送的方式。然后用 Amazon Amplify 托管静态网页的内容,比如一些 HTML 和 CSS 的前端显示。使用 API Gateway 来连接 lambda 函数。当用户想要订阅或者退订服务的时候,API 就会触发函数执行操作,在 Dynamo DB 数据库中进行相关数据的更新。
这就是中文学习应用的用户界面,有限的 JavaScript 的能力就只能做到这里了。不过这个应用支持订阅,还可以根据不同的级别接受相关中文词汇学习信息的定期邮件发送。
3. 规划数据库访问模式
在应用开始的模型中,我仅用了 S3 服务存储一个 CSV 文件,其中包含所有词汇表。但有了更多用户并更改为订阅模式后,我决定用更结构化数据管理方式来升级应用程序的存储配置。
于是我选择 DynamoDB,因为他具有 serverless 属性,比如按用量付费、使用 IAM 对他进行身份验证,通过 API 调用来实现和其他服务之间的交互等。因此我就不会遇到传统数据库服务的一些限制,比如指定的是时间内连接数的限制。同时,用 Amazon Web Services lambda 与之搭配。这样在面对 lambda 的弹性扩展,数据库的调用才不会成为瓶颈。
但 DynamoDB 也是一种 No SQL 的非关系型数据库,这和运行在单实例上完整的数据库不同,当向 DynamoDB 添加数据时,它会自动对该数据进行分片或分解成块,并将其放在不同的服务器上。我想确保我最常提取的数据被组合在一起,因此我规划了数据库访问模式,将最常被拉取的数据分组在一起。
4. 丰富用户登陆功能
我还希望这个中文学习 app 能够有更多功能来优化一下用户的登录体验。比如用户最好能够通过输入用户名和密码验证登录。另外订阅用户能够配置自己个性化的信息。甚至我还想让用户在这个 app 中设置词汇测试...
于是对于这个应用,我继续改进。
我向后端添加了用户身份验证和用户配置文件,添加了两个新的 lambda 函数和两个新的 API 端点。一个获取用户数据,一个更新用户数据。这两者都需要数据保护服务。因此他们还需要调用 Cognito 来进行身份验证,验证通过才能访问和获取数据。具体的架构就变成了这样:
改造后用户交互界面就变成了这个样子:
一个中文学习 app 就基本完成了,这是我的一个事件驱动型的 serverless 应用:实现了云资源的自动扩所容,基本不需要太花精力在底层资源的运维。在云上的构建和运行成本也是可以承受的。
我大致做了一个估算,成本分析如下:
用户规模如果达到 100+ 的活跃订阅者,每个月会产生 4500 API Gateway requests,4800 Lambda invokes,10000 Amazon CloudFront requests 以及 32000 Amazon S3 requests,那么每月应用运行的总支出不超过 1 美金。这是真的。
开始你的第一个事件驱动型 serverless 应用
如同开始所提到的,事件驱动型无服务器应用具有完全托管、无状态、事件驱动、自动扩展、轻量低成本、弹性高可用、以及无需运维等特点。这使其非常适合处理短暂、高并发和容易扩展的工作流,能够大幅提高资源利用率并降低应用成本。因此,它正逐渐演进为构建云原生应用的主流架构与方式。也成为云上构建者首选的技术和应用架构。
当你打开亚马逊云科技的官方主页,搜索并了解亚马逊云科技提供的所有 serverless 服务时,你会发现,这是一个大家族,从计算,到存储,再到数据库和信息集成,还有最新的数据分析服务。亚马逊云科技提供了全栈式的 serverless 服务。
希望亚马逊云科技提供的无服务器服务和开发框架以及我的开发经历可以帮助到你开始你的第一个事件驱动型的 serverless 应用。
请持续关注 Build On Cloud 微信公众号,了解更多面向开发者的技术分享和云开发动态!