乐趣区

关于云原生-cloud-native:资源成本双优化看-Serverless-颠覆编程教育的创新实践


作者 | 计缘
起源 | Serverless 公众号

说起 Serverless 这个词,我想大家应该都不生疏,那么 Serverless 这个词到底是什么意思?Serverless 到底能解决什么问题?可能很多敌人还没有粗浅的领会和体感,这篇文章我就和大家一起聊聊 Serverless。

什么是 Serverless

咱们先将 Serverless 这个词拆开来看。Server,大家都晓得是服务器的意思,阐明 Serverless 解决的问题范畴在服务端。Less,大家必定也晓得它的意思是较少的。那么 Serverless 连起来,再稍加润饰,那就是较少的关怀服务器的意思。

Serverfull 时代

咱们都晓得,在研发侧都会有研发人员和运维人员两个角色,要开发一个新零碎的时候,研发人员依据产品经理的 PRD 开始写代码开发性能,当性能开发、测试完之后,要公布到服务器。这个时候开始由运维人员布局服务器规格、服务器数量、每个服务部署的节点数量、服务器的扩缩容策略和机制、公布服务过程、服务优雅高低线机制等等。这种模式是研发和运维隔离,服务端运维都由专门的运维人员解决,而且很多时候是靠纯人力解决,也就是 Serverfull 时代。

DevOps 时代

互联网公司里最辛苦的是谁?我置信大多数都是运维同学。白天做各种网络布局、环境规划、数据库布局等等,早晨熬夜公布新版本,做上线保障,而且很多事件是重复性的工作。而后缓缓就有了赋能研发这样的声音,运维同学帮忙研发同学做一套运维控制台,能够让研发同学在运维管制台上自行公布服务、查看日志、查问数据。这样一来,运维同学次要保护这套运维控制台零碎,并且不断完善性能,轻松了不少。这就是研发兼运维的 DevOps 时代。

Serverless 时代

慢慢的,研发同学和运维同学的关注点都在运维控制台了,运维控制台的性能越来越弱小,比方依据运维侧的需要减少了主动弹性扩缩、性能监控的性能,依据研发侧的需要减少了自动化公布的流水线性能。因为有了这套零碎,代码品质检测、单元测试、打包编译、部署、集成测试、灰度公布、弹性扩缩、性能监控、利用防护这一系列服务端的工作基本上不须要人工参加解决了。这就是 NoOps,Serverless 时代。

Serverless 在编程教育中的利用

2020 年注定是不平庸的一年,疫情期间,多少家企业如割韭菜般倒下,又有多少家企业如雨后春笋般茁壮成长,比方在线教育行业。

没错,在线教育行业是这次疫情的最大受益者,在在线教育在这个行业里,有一个细分市场是在线编程教育,尤其是少儿编程教育和面向非专业人士的编程教育,比方编程猫、斑马 AI、小象学院等。这些企业的在线编程零碎都有一些独特的特点和诉求:

屏幕一侧写代码,执行代码,另一侧显示运行后果。
依据题目编写的代码都是代码块,每道题的代码量不会很大。
运行代码的速度要快。
反对多种编程语言。
能撑持不可预计的流量洪峰冲击。

例如小象学院的编程课界面:

联合上述这些特点和诉求,不难看出,构建这样一套在线编程零碎的外围在于有一个反对多种编程语言的、强壮高可用的代码运行环境。

那么咱们先来看看传统的实现架构:

从 High Level 的架构来看,前端只须要将代码片段和编程语言的标识传给 Server 端即可,而后期待响应展现后果。所以整个 Server 端要负责对不同语言的代码进行分类、预处理而后传给不同编程语言的 Runtime。这种架构有以下几个比拟外围的问题。

工作量大,灵活性差

首先是研发和运维工作量的问题,当市场有新的需要,或者洞察到新业务模式时须要减少编程语言,此时研发侧须要减少编程代码分类和预处理的逻辑,另外须要构建对应编程语言的 Runtime。在运维侧须要布局撑持新语言的服务器规格以及数量,还有整体的 CICD 流程等。所以反对新的编程语言这个需要要落地,须要研发、运维破费不少的工夫来实现,再加上黑 / 白盒测试和 CICD 流程测试的工夫,对市场需求的撑持不能疾速的响应,灵活性绝对较差。

高可用本人兜底

其次整个在线编程零碎的稳定性是重中之重。所以所有 Server 端服务的高可用架构都须要本人搭建,用以保障流量顶峰场景和稳态场景下的零碎稳固。高可用一方面是代码逻辑编写的是否优雅和欠缺,另一方面是部署服务的集群,无论是 ECS 集群还是 K8s 集群,都须要研发和运维同学一起布局,那么对于对编程语言进行分类和预处理的服务来讲,尚能给定一个节点数,然而对于不同语言的 Runtime 服务来讲,市场需求随时会变,所以不好具体掂量每个服务的节点数。另外很重要的一点是所以服务的扩容,缩容机制都须要运维同学来实时手动操作,即使是通过脚本实现自动化,那么 ECS 弹起的速度也是远达不到业务预期的。

老本管制粒度粗

再次是整个 IaaS 资源的老本管制,咱们都晓得这种在线教育是有显著的流量潮汐的,比方上午 10 点到 12 点,下午 3 点到 5 点,早晨 8 点到 10 点这几个时段是流量比拟大的时候,其余工夫端流量比拟小,而且夜晚更是没什么流量。所以在这种状况下,传统的部署架构无奈做到 IaaS 资源和流量的贴合。举个例子,退出为了应答流量顶峰期间,须要 20 台 ECS 搭建集群来承载流量冲击,此时每台 ECS 的资源使用率可能在 70% 以上,利用率较高,然而在流量小的时候和夜晚,每台 ECS 的资源使用率可能就是百分之十几甚至更低,这就是一种资源节约。

Serverless 架构

那么咱们来看看如何应用 Serverless 架构来实现同样的性能,并且解决上述几个问题。在抉择 Serverless 产品时,在国内自然而然优先想到的就是阿里云的产品。阿里云有两款 Serverless 架构的产品 Serverless 利用引擎和函数计算,这里咱们应用函数计算来实现编程教育的场景。

函数计算(Function Compute)是事件驱动的全托管计算服务,简称 FC。应用函数计算,咱们无需洽购与治理服务器等基础设施,只需编写并上传代码。函数计算为您筹备好计算资源,弹性地、牢靠地运行工作,并提供日志查问、性能监控和报警等性能。

这里不对 FC 的含意做过多赘述,只举一个例子。FC 中有两个概念,一个是服务,一个是函数。一个服务蕴含多个函数:

这里拿 Java 微服务架构来对应,能够了解为,FC 中的服务是 Java 中的一个类,FC 中的函数是 Java 类中的一个办法:

然而 Java 类中的办法诚然只能是 Java 代码,而 FC 中的函数能够设置不同语言的 Runtime 来运行不同的编程语言:

这个构造了解分明之后,咱们来看看如何调用 FC 的函数,这里会引出一个触发器的概念。咱们最常应用的 HTTP 申请协定其实就是一种类型的触发器,在 FC 里称为 HTTP 触发器,除了 HTTP 触发器以外,还提供了 OSS(对象存储)触发器、SLS(日志服务)触发器、定时触发器、MNS 触发器、CDN 触发器等。

从上图能够大略了解,咱们能够通过多种路径调用 FC 中的函数。举例两个场景,比方每当我在指定的 OSS Bucket 的某个目录下上传一张图片后,就能够触发 FC 中的函数,函数的逻辑是将刚刚上传的图片下载下来,而后对图片做解决,而后再上传回 OSS。再比方向 MNS 的某个队列发送一条音讯,而后触发 FC 中的函数来解决针对这条音讯的逻辑。

最初咱们再来看看 FC 的高可用。每一个函数在运行代码时底层必定还是 IaaS 资源,但咱们只须要给每个函数设置运行代码时须要的内存数即可,最小 128M,最大 3G,对使用者而言,不须要思考多少核数,也不须要晓得代码运行在什么样的服务器上,不须要关怀启动了多少个函数实例,也不须要关怀弹性扩缩的问题等,这些都由 FC 来解决。

从上图能够看到,高可用有两种策略:

给函数设置并发实例数,如果设置为 3,那么有三个申请进来时,该函数只启一个实例,然而会启三个线程来运行逻辑。

线程数达到下限后,会再拉起一个函数实例。

大家看到这里,可能曾经大略对基于 FC 实现在线编程教育零碎的架构有了一个大略的轮廓。

上图是基于 FC 实现的在线编程教育零碎的架构图,在这个架构下来看看上述那三个外围问题怎么解:

  • 工作量和灵活性:咱们只须要关注在如何执行代码的业务逻辑上,如果要加新语言,只须要创立一个对应语言 Runtime 的 FC 函数即可。
  • 高可用:多线程运行业务逻辑和多实例运行业务逻辑两层高可用保障,并且函数实例的扩缩齐全都是 FC 主动解决,不须要研发和运维同学做任何配置。
  • 老本优化:当没有申请的时候,函数实例是不会被拉起的,此时也不会计费,所以在流量低谷期或者夜间时,整个 FC 的老本耗费是非常低的。能够做到函数实例个数、计费粒度和流量完满的贴合。

Python 编程语言示例

上面以运行 Python 代码为例来看看如何用 FC 实现 Python 在线编程 Demo。

创立服务和函数

关上函数计算(FC)控制台,抉择对应的 Region,抉择左侧服务 / 函数,而后新建服务:https://fc.console.aliyun.com/fc/overview/cn-hangzhou

输入服务名称,创立服务。

进入新创建的服务,而后创立函数,抉择 HTTP 函数,即可配置 HTTP 触发器的函数:

设置函数的各个参数:

几个须要的留神的参数这里做以阐明:

  • 运行环境:这个很好了解,这里抉择 P ython3
  • 函数实例类型:这里有弹性实例和性能实例两种,前者最大反对 2C3G 规格的实例,后者反对更大的规格,最大到 8C16G。
  • 函数入口:具体参见文档 – HTTP 触发器认证形式:anonymous 为不须要鉴权,function 是须要鉴权的。https://help.aliyun.com/document_detail/74756.html?spm=a2c4g.11186623.6.572.195359cdselnzR

代码解析

函数创立好,进入函数,能够看到概述、代码执行、触发器、日志查问等页签,咱们先看触发器,会看到这个函数主动创立了一个 HTTP 触发器,有调用该函数对应的 HTTP 门路:

而后咱们抉择代码执行,间接在线写入咱们的代码:

具体代码如下:

-- coding: utf-8 --
import logging
import urllib.parse
import time
import subprocess
def handler(environ, start_response):
context = environ['fc.context']
request_uri = environ['fc.request_uri']
for k, v in environ.items():
if k.startswith('HTTP_'):
pass
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
# 获取用户传入的 code
request_body = environ['wsgi.input'].read(request_body_size)
codeStr = urllib.parse.unquote(request_body.decode("GBK"))
# 因为 body 里的对象里有 code 和 input 两个属性,这里别离获取用户 code 和用户输出
codeArr = codeStr.split('&')
code = codeArr[0][5:]
inputStr = codeArr[1][6:]
# 将用户 code 保留为 py 文件,放 /tmp 目录下,以工夫戳为文件名
fileName = '/tmp/' + str(int(time.time())) + '.py'
f = open(fileName, "w")
# 这里预置引入了 time 库
f.write('import time \r\n')
f = open(fileName, "a")
f.write(code)
f.close()
# 创立子过程,执行方才保留的用户 code py 文件
p = subprocess.Popen("python" + fileName, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf-8')
# 通过规范输出传入用户的 input 输出
if inputStr != '' :
p.stdin.write(inputStr + "\n")
p.stdin.flush()
# 通过规范输入获取代码执行后果
r = p.stdout.read()
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [r.encode('UTF-8')]

整个代码思路如下:

  • 从前端传入代码片段,格局是字符串。
  • 在 FC 函数中获取到传入的代码字符串,截取 code 内容和 input 的内容。因为这里简略实现了 Python 中 input 交互的能力。
  • 将代码保留为一个 Python 文件,以工夫戳为文件名,保留在 FC 函数的 /tmp 目录下。(每个 FC 函数都有独立的 /tmp 目录,能够寄存临时文件)
  • 而后在文件中追加了引入 time 库的代码,应答 sleep 这种交互场景。
  • 通过 subprocess 创立子过程,以 Shell 的形式通过 Python 命令执行保留在 /tmp 目录下的 Python 文件。如果有用户输出的信息,则通过规范输入输出写入子过程。
  • 最初读取执行后果返回给前端。

前端代码

前端我应用 VUE 写了简略的页面,这里解析两个简略的办法:

页面加载时初始化 HTTP 申请对象,调用的 HTTP 门路就是刚才函数的 HTTP 触发器的门路。

这个办法就是调用 FC 中的 PythonRuntime 函数,将前端页面的代码片段传给该函数。这里解决 input 交互的思路是,扫描整个代码片段,以蕴含 input 代码为标识将整个代码段分成多段。没有蕴含 input 代码的间接送给 FC 函数执行,蕴含 input 代码的,申请用户的输出,而后代码片段带着用户输出的信息一起送给 FC 函数执行。

演示如下:

结束语

这篇文章给大家介绍了 Serverless,阿里云的 Serverless 产品函数计算(FC)以及基于函数计算(FC)实现的在线编程零碎的 Demo。大家应该有所体感,基于函数计算(FC)实现在线编程零碎时,研发同学只须要专一在如何执行由前端传入的代码即可,整个 Server 端的各个环节都不须要研发同学和运维同学去关怀,根本体现了 Serverless 的精华。

基于 Serverless 还有很多其余的利用场景,之后我会一一分享给大家,咱们不见不散!

退出移动版