无服务器和React 2:灵巧无欺诈

我可以通过简单的方式向前端开发人员介绍AWS(Amazon Web Services)中的无云无服务器架构吗? 为什么不呢 让我们渲染AWS React / Redux应用程序,然后讨论AWS lambda的优缺点。


该材料基于玛丽娜·米洛诺维奇Marina Mironovich)在圣彼得堡举行的2018年春季HolyJS会议的报告的笔录。

Marina正式是EPAM的领先开发商。 现在,她在一个客户的解决方案架构师小组中工作,因此她参与了许多项目。 因此,对于我们概述她当前兴趣的圈子而言,比列出她所使用的所有技术要容易得多。

首先,我对所有云技术特别是AWS感兴趣,因为我在生产中经常使用它。 但是我尝试跟上其他一切。

前端是我的初恋,似乎永远。 特别是,我目前正在使用React和React Native,所以我对此有所了解。 我还尝试跟踪其他所有内容。 我对与项目文档相关的所有内容都很感兴趣,例如UML图。 由于我是解决方案架构师小组的成员,因此我必须做很多事情。



第1部分。背景


大约一年前,我想到了谈论Serverless的想法。 我想轻松自然地为前端开发人员谈论Serverless。 因此,您不需要任何其他知识即可使用它,更多的技术现在允许您执行此操作。

在某种程度上,这个想法实现了-我在FrontTalks 2017上谈到了无服务器 。但是事实证明,对于一个简单易懂的故事而言,45分钟是不够的。 因此,该报告分为两个部分,现在是您的第二个“系列”。 谁没有看到第一个-不用担心,理解下面写的内容不会有伤害。 就像在体面的电视节目中一样,我将从上一部分的摘要开始。 然后,我将继续介绍果汁本身-我们将渲染React / Redux应用程序。 最后,我将原则上讨论云功能(尤其是AWS lambda)的优缺点,以及它们还能做什么。 我希望这一部分对所有已经熟悉AWS lambda的人有用。 最重要的是,世界并不止于亚马逊,因此让我们来谈谈云功能领域还有什么。

我会用什么


为了呈现该应用程序,我将使用许多Amazon服务:

  1. S3是云中的文件系统。 在那里,我们将存储静态资产。
  2. IAM(用户和服务的访问权限)-隐式,但将在后台使用,以便服务彼此通信。
  3. API网关(访问网站的URL)-您将看到我们可以在其中调用lambda的URL。
  4. CloudFormation(用于部署)-将在后台隐式使用。
  5. AWS Lambda-为此我们来到这里。

什么是无服务器,什么是AWS Lambda?


实际上,无服务器是一个大骗局,因为当然有服务器:在某个地方,一切都开始了。 但是那里发生了什么?

我们正在编写一个函数,该函数在服务器上运行。 当然,它不仅以这种方式开始,而且以某种容器开始。 而且,实际上,服务器上容器中的此功能称为lambda。


对于lambda,我们可以忽略服务器。 我什至会这样说:当编写lambda函数时,考虑它们是有害的。 我们不会像使用服务器那样使用lambda。

如何部署Lambda


出现一个逻辑问题:如果没有服务器,该如何部署? 服务器上有SSH,我们上传了代码,启动了它-一切都很好。 用lambda做什么?

选项1.我们无法部署它。

控制台中的AWS为我们提供了一个很好的温和的IDE,我们可以在那里在那里编写函数。



很好,但不是很可扩展。

选项2。我们可以制作一个zip并从命令行下载它

我们如何制作一个zip文件?

zip -r build/lambda.zip index.js [node_modules/] [package.json]

如果使用node_modules,则将所有这些压缩到一个存档中。
此外,根据您是要创建新功能还是已经拥有该功能,您可以执行以下任一操作

aws lambda create-function...

要么

aws lambda update-function-code...

怎么了 首先,AWS CLI想要知道是否正在创建一个功能或您是否已经拥有一个功能。 这是两个不同的团队。 如果不仅要更新代码,还要更新此函数的某些属性,则会出现问题。 这些命令的数量正在增加,您需要坐在目录中,然后考虑要使用哪个命令。

我们可以做得更好,更轻松。 为此,我们有框架。

AWS Lambda框架


有许多这样的框架。 这主要是AWS CloudFormation,可与AWS CLI结合使用。 CloudFormation是描述您的服务的Json文件。 您在Json文件中描述它们,然后通过AWS CLI说“ execute”,它将自动为您在AWS服务中创建所有内容。

但是,完成诸如渲染这样的简单任务仍然很困难。 此处的输入门槛太大-您需要阅读CloudFormation的结构等。

让我们尝试简化它。 这里出现了各种框架:APEX,Zappa(仅适用于Python),Claudia.js。 我只随机列出了一些。

这些框架的问题和优势在于它们是高度专业化的。 因此,他们非常擅长完成一些简单的任务。 例如,Claudia.js非常适合创建REST API。 她将创建AWS调用API网关,将为您创建一个lambda,所有这些都将被漂亮地锁定。 但是,如果您需要再部署一点,就会出现问题-您必须添加一些内容,帮助,外观等。

Zappa仅适用于Python。 我想要更有野心的东西。 这就是Terraform和我的无服务器之爱。

无服务器是介于可以完成几乎所有工作的大型CloudFormation和这些高度专业化的框架之间的中间位置。 几乎所有内容都可以部署在其中,但是仍然很容易做到。 它的语法也很简洁。

Terraform在某种程度上类似于CloudFormation。 Terraform是开源的,您可以在其中部署所有内容-很好,或几乎所有内容。 当AWS创建服务时,您可以在其中添加新的东西。 但是它又大又复杂。

老实说,在生产中我们使用Terraform,因为有了Terraform,我们拥有的一切都会变得更加容易-无服务器将无法描述所有这一切。 但是Terraform非常复杂。 而且,当我为工作而写东西时,我首先将其写在Serverless上,对其性能进行测试,并且只有在测试和解决了我的配置之后,才在Terraform上重写它(这又“有趣”了几天)。

无服务器


为什么我喜欢无服务器?

  1. Serverless具有一个允许您创建插件的系统。 我认为,这是一切的救赎。 无服务器-开源。 但是向开放源代码添加内容并不总是那么容易。 您需要了解现有代码中正在发生的事情,至少要遵守准则,至少要遵循代码样式,提交PR,他们会忘记此PR,并会尘埃落定三年。 根据结果​​,您可以进行分叉,而这将单独存在。 这一切都不是很健康。 但是,如果有插件,一切都会简化。 您需要添加一些内容-您正在创建自己的小插件。 为此,您不再需要了解Serverless内部的情况(如果这不是超级定制问题)。 您只需使用可用的API,在将插件保存到任何地方或为所有人部署它的位置。 一切都为您服务。 另外,已经有一个大型的插件动物园和编写这些插件的人。 也就是说,也许已经为您决定了一些事情。
  2. 无服务器帮助在本地运行lambda。 lambda的最大不足之处在于,AWS没有考虑我们将如何调试和测试它。 但是Serverless允许您在本地运行所有内容,看看会发生什么(他甚至与Gateway API一起执行)。

示范


现在,我将展示所有这些工作原理。 在接下来的一分半钟到两分钟内,我们将能够创建将呈现HTML页面的服务。
首先,在一个新文件夹中,运行SLS Create模板:


mkdir sls-holyjs
cd sls-holyjs
sls create --template aws-nodejs-ecma-script



npm install



无服务器开发人员照顾我们-使从模板创建服务成为可能。 在这种情况下,我使用nodejs-ecma-script模板,它将为我创建一些文件,例如webpack配置,package.json,一些函数和serverless.yml:

ls



我不需要所有功能。 我将删除holyjs中的第一个,第二个重命名:



我将稍微调整一下serveless.yml,其中包含所有必要服务的说明:



好吧,那么我将修复该函数返回的响应:



我将制作HTML“ Hello HolyJS”并添加用于渲染的句柄。

下一个:

sls deploy

瞧! 我可以在公共访问中看到一个URL,该URL正在呈现:



信任,但要验证。 我将转到AWS控制台并验证是否已创建holyjs函数:



如您所见,在部署它之前,Serverless将使用webpack对其进行构建。 此外,还将创建此处描述的其余基础结构-API网关等。

当我要删除此:

sls remove

serverless.yml中描述的所有基础结构都将被删除。



如果有人支持此处描述的过程,我邀请您简单地查看我以前的报告

在本地运行lambda


我提到过lambda可以在本地运行。 这里有两个启动选项。

选项1.我们只在终端中运行所有内容

我们得到函数返回的结果。


sls invoke local -f [fn_name]

选项2.在本地启动lambda的无服务器离线

别忘了,我们正在开发一个同构应用程序,它将是HTML和CSS,因此在终端中,查看较长的HTML行并不怎么有趣。 在那里您可以检查该功能是否正常工作。 但是我想在浏览器中运行并渲染它。 因此,我需要一堆带有lambda的API网关。

为此,有一个单独的无服务器脱机插件,它将在某个端口上启动您的lambda(已写入),然后它将在终端中显示一个URL,您可以在其中访问它。

sls offline --port 8000 start

最好的部分是热重装。 也就是说,您编写了功能代码,更新了浏览器,并更新了该函数返回的内容。 您不必重新启动所有内容。

这是报告第一部分的摘要。 现在我们继续到主要部分。

第2部分。使用AWS渲染


下面描述的项目已经在GitHub上。 如果您有兴趣,可以在此处下载代码。

让我们从所有工作原理开始。



假设有一个用户-我。

  • 我打开网站。
  • 在某个URL,我们访问网关API。 我想指出,网关API已经是AWS服务,我们已经在云端。
  • 网关API将调用lambda。
  • Lambda将呈现网站,所有这些都将返回浏览器。
  • 浏览器将开始呈现并意识到一些静态文件丢失。 然后,他将转到S3存储桶(我们的文件系统,我们将在其中存储所有静态数据;在S3存储桶中,您可以放置​​所有内容-字体,图片,CSS,JS)。
  • 来自S3存储桶的数据将返回到浏览器。
  • 浏览器将呈现页面。
  • 大家都很开心

让我们对我写的内容进行一些代码审查。

如果您转到GitHub,则将看到以下文件结构:

lambda-react
README.md
config
package.json

public
scripts
serverless.yml
src

yarn.lock

所有这些都是在React / Redux工具箱中自动生成的。 实际上,在这里,我们将仅对几个文件感兴趣,并且需要对其进行一些更正:

  • 配置
  • package.json
  • serverless.yml-因为我们将进行部署,
  • src-没有它的地方。

让我们从配置开始


为了将所有内容整合到服务器上,我们需要添加另一个webpack.config:



如果使用模板,则已经为您生成了webpack.config。 并且slsw.lib.entries变量会自动替换,它将指向您的lambda处理程序。 如果需要,可以自己指定其他内容来更改它。



我们将需要渲染节点的所有内容( target: 'node' )。 原则上,所有其他加载程序都与常规React应用程序相同。

除了package.json


我们将只添加几个脚本-使用React / Redux已经生成了start和build-没有任何变化。 添加脚本以启动lambda和脚本以部署lambda。



无服务器


一个很小的文件-只有17行,所有这些都在下面:



对我们来说,什么是有趣的? 首先,经理。 文件的完整路径被src/lambda/handlersrc/lambda/handler ),并且处理程序功能通过点指定。

如果确实需要,可以在一个文件中注册多个处理程序。 这也是webpack的路径,应该收集所有这些内容。 基本上,一切:其余的已经自动生成。

最有趣的是src


这是一个巨大的React / Redux应用程序(对我而言,它并不大-到页面)。 在附加的lambda文件夹中,我们需要渲染lambda的所有内容:



这些是2个文件:



让我们从处理程序开始。 最重要的是第13行。 这是渲染器,它是将在云中调用的非常λ的值:



如您所见, render ()函数返回一个promise,必须从中捕获所有异常。 这是lambda的特性,否则lambda不会立即结束,但会一直工作到超时。 您将不得不为已经下降的代码支付额外的费用。 为了防止这种情况的发生,您需要尽早完成lambda-首先,捕获并处理所有异常。 稍后我们将回到此。

如果没有任何错误或异常,则调用createResponse函数,该函数实际上需要五行。 我们只添加所有标题,以便它在浏览器中正确呈现:



这里最有趣的是render函数,它将渲染我们的页面:



此功能来自renderer.js。 让我们看看那里有什么。

同构应用程序在那里渲染。 而且,它可以在任何服务器上呈现-不管它是否为lambda。

我不会详细告诉您什么是同构应用程序,如何呈现它,因为这是一个完全不同的主题,并且有人告诉我它比我更好。 这是我在短短几分钟内通过谷歌搜索找到的一些教程:



如果您知道其他报告,则可以建议,我会在我的Twitter上提供指向这些报告的链接。

为了不失去任何人,我只是上楼,告诉那里发生了什么。
首先,我们需要使用HTML / React / Redux渲染它。

这是通过标准的React方法renderToString



接下来,我们需要渲染样式,以便我们的内容不会闪烁。 这不是一个非常琐碎的任务。 有几种解决方案。 例如,我使用了node-style-loader ,它将所有内容放到styleTag ,然后可以将其粘贴到HTML中。



如果有更好的软件包-由您自行决定。

接下来,我们需要传递Redux状态。 由于要在服务器上进行渲染,因此您可能想要获取一些数据,并且不希望Redux重新询问并重新渲染它。 这是一个相当标准的任务。 Redux主网站上有一些有关如何执行此操作的示例:我们创建一个对象,然后将其传递给全局变量:


现在离lambda更近了。

有必要进行错误处理。 我们想抓住一切并与他们合作,至少停止lambda的发展。 例如,我通过promise做到了这一点:



接下来,我们需要用URL代替静态文件。 为此,我们需要找出lambda在哪里运行-在本地还是在云中的某个地方。 如何找出?

我们将通过环境变量来做到这一点:




const bundleUrl = process.env.NODE_ENV === 'AWS' ?
AWS_URL : LOCAL_URL;

一个有趣的问题:环境变量如何在lambda中聚集在一起。 其实很容易。 在yml中,您可以将任何变量传递到environment 。 锁定后,它们将可用:



好了,这是奖金-在部署lambda之后,我们要部署所有静态资产。 为此,我们已经编写了一个插件,您可以在其中指定要在其中部署内容的S3篮子:


总共,我们在大约五分钟内进行了同构应用,以证明这一切都很容易。

现在让我们来谈谈理论-lambda的优缺点。

让我们从坏处开始。

缺点lambda函数


缺点可能包括(或可能不包括)冷启动时间。 例如,对于我们现在正在编写的Node.js上的lambda,冷启动时间的意义并不大。

下图显示了冷启动时间。 这可能是一件大事,尤其是对于Java和C#(请注意橙色点)-您不希望它花五到六秒钟来启动代码。

对于Node.js,开始时间几乎为零-30-50 ms。 当然,对于某些人来说,这可能也是一个问题。 但是可以对功能进行预热(尽管这不是本报告的主题)。 如果有人对如何进行这些测试感兴趣,欢迎访问acloud.guru,他们将告诉您一切( 在本文中 )。



那有什么缺点呢?

功能码大小限制


该代码必须小于50 MB。 可以编写这么大的函数吗? 请不要忘记node_modules。 如果连接某些东西,尤其是那里有二进制文件,那么即使是zip文件,也可以轻松超过50 MB。 我有这种情况。 但这是查看您要连接到node_modules的另一个原因。

运行时限制


默认情况下,该函数执行一秒钟。 如果一秒钟后仍未结束,则您将超时。 但这一次可以在设置中增加。 创建函数时,可以将值设置为五分钟。 五分钟是一个艰难的期限。 这对于网站来说不是问题。 但是,如果您想在lambda上做一些更有趣的事情,例如处理图像,将文本转换为声音或将声音转换为文本等,则此类计算可能很容易花费超过五分钟的时间。 那将是一个问题。 怎么办呢? 优化或不使用lambda。

与执行lambda的时间限制有关的另一件有趣的事情。 回顾我们网站的布局。 在产品问世并希望在站点上实时提供消息之前,一切工作都非常顺利,以便实时显示新闻。 我们知道这是通过WebSockets实现的。 但是WebSocket不能工作五分钟,需要保持更长的时间。 在这里,五分钟的限制就成了问题。



一句话。 对于AWS,这不再是问题。 他们找到了解决方法。 但是总的来说,只要出现Web套接字,lambda都不是您的解决方案。 您需要再次切换到旧的服务器。

每分钟的并行功能数


上限为500到3,000,具体取决于您所在的地区。 我认为,在欧洲,将近有500. 3000在美国得到了支持。

如果您的站点很忙,并且每分钟期望超过三千个请求(这是很难想象的),那么这将成为一个问题。 但是在我们讨论这个负数之前,让我们先讨论一下lambda是如何扩展的。

一个请求来到我们这里,我们得到一个lambda。 在执行此lambda时,我们又收到了两个请求-我们再启动两个lambda。 人们开始进入我们的网站,越来越多的请求出现并启动了lambda。



这样做,您需要支付运行lambda的时间。 假设您为一秒钟的lambda执行支付了1美分。 如果您每秒有10 lambda,那么您将为此支付10美分。 如果您每秒要运行一百万个lambda,则大约是一万美元。 令人不愉快的数字。

因此,AWS决定如果您不正确地执行测试并且自己启动DDOS,导致lambda或其他人来执行DDOS,则他们不想在一秒钟内清空您的钱包。 因此,建立了三千个限制-这样您就有机会应对这种情况。

如果您经常处理3000个请求,则可以在AWS中编写,这样会增加限制。

无状态


这是最后一个有争议的减号。

什么是无状态? 这里出现了一个关于金鱼的笑话-它们根本不符合上下文:



第二次调用的lambda对第一次调用一无所知。

让我给你看一个例子。 假设我有一个系统-一个大黑匣子。 而且,该系统可以发送SMS。

用户来说:发送SMS模板编号1,然后系统将其发送到真实设备。



在某个时候,产品表示希望找出将要去那里的东西,并检查该系统在任何地方都没有损坏。 为此,我们将真实的设备替换为某种测试编号-例如,Twilio可以做到这一点。 他将呼叫Webhook,发送SMS文本,我们将在应用程序中处理此SMS文本(我们需要检查我们的模板已成为正确的SMS)。

要进行检查,我们需要知道发送了什么-我们将通过测试应用程序进行发送。 它仍然可以比较并显示结果。



让我们尝试在lambda上执行相同的操作。

Lambda将发送短信,短信将到达Twilio。



我画的虚线不是偶然的,因为SMS可以在几分钟,几小时或几天内返回-这取决于您的运营商,也就是说,这不是同步呼叫。 到这个时候,lambda将会忘记所有内容,并且我们将无法检查SMS。

我会说这不是减号,而是功能。 该方案可以重做。 有几种方法可以做到这一点,我将提供自己的方法。 如果我们有无状态,并且想要保存一些东西,那么我们肯定需要使用存储,例如数据库S3,但是任何可以存储上下文的东西。

在带有SMS存储的方案中,它将被发送到测试编号。 当Webhook调用它时-我建议例如调用第二个lambda,因为这是一个稍微不同的功能。 第二个lambda将已经能够从数据库中提取SMS-ku,对其进行检查并显示结果。



宾果!

在一开始,我说过如果编写lambda,则需要忘记服务器。我遇到了一些使用node.js编写并用于表达服务器的人。他们喜欢依靠缓存,并且缓存停留在lambda中。有时,当他们进行测试时,它将起作用,有时则不会。这怎么可能?

假设我们有一个服务器,并在其中启动了一个容器。发射容器是相当昂贵的操作。首先,您需要制作此容器。只有在创建功能代码后,功能代码才会在那里部署并可以执行。执行函数后,不会终止容器,因为AWS认为您可以再次调用此函数。在函数停止后,AWS从未写过该容器的寿命。我们做了实验。在我看来,对于节点来说这是三分钟,对于Java,他们可以将一个容器保持12-15分钟。但这意味着,当调用下一个函数时,将在同一容器和同一环境中调用该函数。如果在某处使用节点缓存,则在此创建变量,依此类推。 -如果您不清洁它们,它们将保留在那里。因此,如果您使用lambda书写,那么您通常需要忘记缓存,否则您将陷入不愉快的境地。这很难改变。

Lambda函数的优点


他们很少,但对我来说,它们似乎更令人愉快。

  • 首先,我们真的忘记了有一台服务器。作为开发人员,我用JavaScript编写了函数,仅此而已。我敢肯定,你们中的许多人都使用javascript编写了函数,而您对此一无所知。
  • 无需考虑缓存,也无需考虑垂直或水平缩放。你写的东西行得通。不管一个人一个月访问您的网站,还是会有一百万次访问,都没关系。
  • 对于AWS Lambda,它们已经与几乎所有服务器(DynamoDB,Alexa,API Gateway等)实现了自己的集成。

在lambda上还能做什么?


我举了一个相当标准的示例-我谈到了渲染同构应用程序,因为基本上他们将lambdas视为REST API。但是我想举一些例子说明他们可以做什么,只是为了给您思考和想象的机会。

原则上,在lambda上,您可以执行任何操作...带星号。

  • HTTP服务就是我所说的。REST API,每个端点API都是一个lambda。它完美匹配。尤其要考虑企业如何经常使用node.js创建中间件。我们有负责所有成本计算的Java,然后在js上编写了一个可以非常轻松地处理请求的层。可以用lambdas重写它,甚至会更酷。
  • IoT — , Alexa - -, , .
  • Chat Bots — , IoT.
  • Image/Video conversions.
  • Machine learning.
  • Batch Jobs — - , Batch Job .

现在,除了亚马逊,谷歌,Azure,IBM,Twillio,几乎所有大型服务都希望在其家中实现云功能。如果Roskomnadzor阻止了所有内容,我们将在车库中启动一个小型服务器,然后在其中部署我们的云计算。为此,我们需要开源(更是如此,因为您必须付费购买服务,并且开源是免费的)。开源并不会停滞不前。他们已经对所有这些进行了不切实际的实现。我现在对前端说可怕的话-Docker Swarm,Kubernetes-所有这些都是这样的。

最好的部分是,首先,云功能保持不变。如果您在AWS或lambda上具有功能,则将它们转换为开源也很容易。

并非所有进展都在下面列出。我只是选择了一个更大,更有趣的游戏。完整列表非常庞大:许多初创公司现在开始就此主题开展工作:

  • 铁功能
  • 项目
  • Openfaas
  • Apache OpenWhisk
  • 无核
  • 裂变
  • 功能

我尝试了Fnproject,仅花费了几个小时就将该同构应用程序转移到Fnproject,并使用Kubernetes容器在本地运行它。

它仍然可以快速扩展。您将拥有一堆网关API(当然,没有其余的服务),但是您仍然会有一个调用lambda的URL。实际上,几乎每个人都可以像承诺的那样忘记服务器,只有一个人将部署此框架并配置此Kubernetes编排,以便快乐的开发人员以后可以使用它。

. HolyJS 2018 Moscow, 24-25 . , Early Bird-.

Source: https://habr.com/ru/post/zh-CN417943/


All Articles