探索支付宝云开发,开启一段 100ms 的神奇旅程!

随着数字化时代的快速发展,移动互联网正在深刻地改变着我们的生活方式。其中,小程序以其即扫即用的特性,为用户提供了无需下载、无需安装、即刻享用的便利体验,并逐渐成为了我们日常生活中不可或缺的一部分。
然而,开发小程序并非易事。小程序的流量具有极高的波动性,如何在早晚高峰时段、节假日等流量激增的情况下保持服务器的稳定性,是一大挑战;同时,小程序的需求变化迅速,对开发者的技术能力和运维能力提出了更高的要求。
针对这些挑战,以函数计算(Function as a Service,FaaS)为代表的无服务器技术为开发者们提供了一个理想的解决方案,极大地降低了后端的研发门槛。开发者只需关注业务逻辑,而无需关心运行环境和服务器等底层资源,减轻了运维负担。函数计算的自动弹性伸缩特性,能够有效应对流量的波动,保证小程序的稳定运行,同时也避免了资源闲置的浪费,帮助开发者有效地降低成本。
为了进一步帮助开发者快速、低成本地开发小程序应用,支付宝推出了以函数计算为核心的云开发产品。我们在冷启动、高可用和安全等方面做出了创新性的工作,为开发者提供了无缝、稳定的使用体验。
在本文中,我们将以一个小程序请求的视角切入,阐述函数计算在小程序开发中的应用和优势,同时分享我们在冷启动、高可用和安全等方面的创新解决方案。我们期待与大家一起深入探讨,分享经验和思考。
旅行的攻略:旅行路线图

在这一次的分享中,我将带领大家踏上一段旅行,共同探索小程序、支付宝 APP、网关以及函数四个站台所构成的技术生态系统。在这个系统中,我们致力于打造一个安全可靠的环境,保障每位旅客的信息安全和使用体验。
首先,我们的首发站是小程序。作为一个轻量级应用,小程序的便捷性和易用性备受用户喜爱,也带来了更高的安全风险。为了确保每位旅客不要上错车,我们引入了安全认证,通过对用户身份验证,确保只有合法用户才能使用我们的小程序。
第二站是支付宝 APP。支付宝 APP 是我们技术生态系统中的重要一环,也是用户进行交易的关键环节。为了确保每笔交易的安全性,我们采用了多重保障措施,包括密码、短信验证码、指纹识别等,防止坏人上车。
第三站是网关。作为用户与后端服务的桥梁,网关的安全可靠性对整个系统至关重要。我们引入了反向代理、WAF 等技术,确保网关不会成为攻击者的入口,同时也保护了后端服务的安全。
终点站是函数。作为我们技术生态系统中的核心,函数的安全可靠性对整个系统的稳定运行和数据安全至关重要。我们引入了灰度发布、监控告警等技术,对函数进行全方位的安全保障,同时也保证了函数在高并发情况下的稳定运行。
通过以上措施的实施,我们成功地为每位旅客提供了一个安全可靠的环境,让他们可以愉快地享受旅行带来的便捷和乐趣。在未来,我们将继续加强技术生态系统的安全可靠性,为用户提供更加优质的服务和使用体验。
旅行的开始:发起一个小程序请求
首先参考文档,编写以下的支付宝小程序代码,通过不到 10 行的代码就可以开始这段旅行。
旅行的安全:支付宝云开发管家 7*24 护航
旅客需要凭票上车
在小程序访问函数过程中,我们需要通过 session 来获取对应的信息,包括:appId、openId、env 等信息。下面是具体的访问流程:
小程序的 callFunction 请求会通过本地的代理转发到支付宝客户端进行无感认证。通过这种方式,我们可以在保证安全性的同时,提高整个访问的效率。
支付宝客户端通过 session 服务验证 session 的合法性。这里,我们引入了 session 服务来确保访问的安全性和合法性。只有在 session 验证成功后,才能够继续访问下一步。
合法的 session 可以获取到对应的 appId、openId、资源和服务信息等。我们通过这些信息来进行后续的操作和访问。
最终,通过对应的 appId、openId、env 等信息,才可以访问函数。这是保证函数访问的合法性和有效性的重要一步。
通过以上流程和技术手段,我们成功地实现了小程序访问函数的安全可靠,并提高了整个访问的效率。

车上持续护航-防止坏旅客作恶
在小程序访问函数的过程中,我们不仅需要保证访问的安全可靠性,更需要在旅客上车后,对每位旅客进行持续的保护和隔离,防止坏旅客作恶。下面是具体的保护流程:
首先,当旅客已经上车后,我们会持续护航,保证该旅客只能访问属于自己的函数和资源信息。这样可以确保旅客之间的互相隔离,同时也保护了其他旅客的信息安全。
接着,每个旅客上车后会获得属于自己的 ak/sk,sk 信息不能泄漏。在支付宝云开发这趟车上,ak/sk 信息对旅客是无感的,同时也是自动绑定旅客和自动轮换过期的,即免鉴权访问功能。这样不仅可以提高访问效率,还可以保证旅客的访问安全性。
每个旅客想要访问其他的函数和资源需要通过自己的 sk 进行签名。这是为了防止旅客之间的信息泄露和访问不当。只有在签名验证通过时,才会授权访问。
通过以上措施的实施,我们成功地为每位旅客提供了一个安全可靠的访问环境,并持续地保障旅客之间的信息安全和访问隔离。在未来,我们将继续加强技术手段和措施,提高访问效率和安全性,为用户提供更加优质的服务和使用体验。

防止坏人上车
我们采用的一些关键技术,以防止坏人上车,保障用户信息和访问的安全可靠性。以下是具体的技术手段:
首先,我们采用 DDoS 原生防护功能提升 DDoS 攻击防御能力,主要提供针对三层和四层流量型攻击的防御服务。当流量超出 DDoS 原生防护的默认清洗阈值后,自动触发流量清洗,实现 DDoS 攻击防护。这样可以有效地防止针对网络层和传输层的攻击,保障用户的访问安全和稳定性。
同时,我们的 DDoS 原生防护采用被动清洗方式为主、主动压制为辅的方式,针对 DDoS 攻击在反向探测、黑白名单、报文合规等标准技术的基础上,在攻击持续状态下,保证被防护云产品仍可以正常对外提供业务服务。这样可以在保证防御效果的同时,尽可能减少对业务的影响。
除此之外,我们的支付宝云开发产品还提供了很多维度的限流、防刷、访问控制等安全防护的能力。这些安全措施包括但不限于 IP 访问控制、URL 访问控制、Dos 攻击防范、恶意爬虫拦截等,可以有效地防止恶意攻击和不良行为的发生,保障用户信息和访问的安全可靠性。
通过以上技术手段的实施,我们成功地防止坏人上车,为用户提供了一个安全可靠的访问环境。

旅客还不知道目的地景点?快速的函数实例调度
当旅客拿票上车之后,却并不知道目的地景点?不用担心,在旅客从车门外跨进车门内的一步路的时间内,支付宝云开发产品会快速地进行函数实例的实时调度,立刻确认好函数实例的信息,也就是景点信息。
我们会在旅客上车后立刻进行函数实例的实时调度,以确保旅客能够快速地获得景点信息。这个过程是并行处理的,即同时处理旅客行程(函数请求)和景点信息的计算(函数实例调度)。这样可以大大缩短旅客等待时间,提高整个访问过程的效率。
在函数实例调度过程中,我们采用了一系列智能化的策略和算法,以确保函数实例的快速调度和高效运行。我们会根据实际需要,对资源进行动态调整,以满足不同的业务需求。
同时,在函数实例调度的过程中,我们还采用了多种技术手段,包括但不限于负载均衡、服务发现、容器编排等,以确保系统的稳定性和可靠性。这些技术手段可以帮助我们快速定位问题,并快速采取措施,以保证系统的正常运行和访问的可用性。
旅客行程:函数请求处理和分发

当旅客上车后,会到达函数网关,并在网关里面进行短暂的停留。首先,网关通过 GRPC 协议将请求转发给函数节点网关,以实现函数请求的分发。函数节点网关会将请求缓存起来,并按照实例进行分组,以便后续的调度和处理。
在函数请求分发前,网关会进行函数实例的调度,以确保函数实例能够快速响应请求。调度器会实时返回对应节点的信息,即景点信息。这样,就可以确定对应的函数实例,进而快速处理请求,提高整个访问过程的效率和稳定性。
在函数实例启动后,它会作为客户端来拉取请求,并在处理请求完成后返回请求结果。这样可以有效地避免因请求量过大而导致的资源浪费和延迟响应等问题。
目的地景点的计算:函数实例调度
函数实例调度是一个复杂的过程,需要考虑到调度粒度、规模、性能和高可用等多方面的因素。针对调度粒度和规模的挑战,我们采用了一次函数调用即一次容器调度的方式。这样可以实现更细粒度的调度,提高整个访问过程的效率和响应速度。
我们还采用了 HUSE 调度引擎,即 Hyper-elastic Unified Serverless Engine,它是蚂蚁容器调度引擎的下一代架构,是专门面向高吞吐低延迟、低成本、极速启动的 Serverless 场景而设计的。这些技术手段可以帮助我们实现更快速、更可靠的容器调度,提高系统的稳定性和可用性。
此外,我们还需要考虑到容器调度对业务流量的影响,因此我们需要保证调度系统的高可用能力。为此,我们采用了一系列的高可用技术手段,包括但不限于容器冗余、自动扩缩容、容器启动优化等。这些技术手段可以帮助我们应对各种突发情况,保证系统的正常运行和访问的可用性,为用户提供了一个高效、稳定、可靠的访问环境。在未来,我们将继续加强技术的研发和优化,以更好地满足用户的需求和提升用户的使用体验。

组件介绍
huse-scheduler:请求入口和任务调度器,提供 1w/s 的任务调度吞吐和 <20ms 的调度延迟性能;
huselet:任务节点执行器,负责任务的资源创建和生命周期管理;
流程说明
函数网关会向 huse-scheduler 提交调度请求,huse-scheduler 会根据节点的运行负载情况进行算法调度。在这个过程中,huse-scheduler 会选择一个最优的节点来运行函数实例,并将景点信息返回给函数网关。一旦函数网关获取到景点信息,它就可以结束本次请求,至于这个景点是否存在,是不需要关注的。
因为景点信息只是一个元数据,代表一个函数实例的基本信息。而函数实例的调度和运行是由 huse-scheduler 和 huselet 来负责的,它们会根据负载情况和实际运行情况来做出调度决策,以确保系统的高效性和稳定性。
因此,当函数网关获取到景点信息后,它就可以将其返回给旅客,告知他们终点。与此同时,函数实例的创建由 huselet 并发完成。
碰上春运这么办?性能吞吐稳定性
针对春运高峰期这样的特殊情况,我们的支付宝云开发产品具备高并发、高吞吐、低延迟、高可用等特点,可以保障系统的稳定性和可用性。以下是具体的技术实现方式:
首先,在网关和调度器的设计和实现中,我们采用了一系列的高并发、高吞吐、低延迟的技术手段,以应对大规模并发访问和请求量的提高。这些技术手段包括但不限于负载均衡、缓存、异步处理、预热、横向扩展等,可以在保证系统性能的同时,提高系统的可用性和稳定性。
同时,我们还采用了一系列的高可用技术手段,以应对系统故障或异常情况。这些技术手段包括但不限于容器冗余、自动扩缩容、多活部署、容器启动优化等,可以帮助我们保证系统的高可用性和可靠性。
最后,我们还会定期进行系统测试和优化,以保持系统的高效运行和不断提升用户的使用体验。通过这些技术手段的实施,我们可以保障用户在旅途中遇到春运高峰期等特殊情况时,仍能够得到稳定的服务和实时的响应。
高性能高吞吐的网关
函数网关采用 gw-on-envoy 方案,即在开源的云原生代理 Envoy 的基础上用 Go 语言扩展出 gw。其中 enovy 负责基础的四层通信和七层协议编解码,gw 负责服务发现、配置下发、访问控制、路由选择、审计采样等等互通网关逻辑,如下图所示:

Envoy 由 C++ 编写,gw 由 Go 编写,两个语言的代码无法直接互相理解,ABI(应用二进制接口)层负责定义跨语言传递的请求、响应数据结构,和对应的处理函数,再利用 Go 语言的 cgo 机制,将其编译成动态链接库和对应的头文件。之后,在 Envoy 代码中使用 C++ 实现一个自定义插件,并在此插件中调用动态链接库中的处理函数。
得益于 Envoy 高性能的单线程非阻塞处理模型及 Go runtime GC 压力下降,gw 在 CPU 使用率和请求 RT 方面都有显著下降,总体性能指标如下:


稳定可靠的调度系统
为了提供一个满足支付宝云开发场景需求,高可用、高性能的容器调度引擎,HUSE 在协议、调度算法、消息通信、节点调度以及包管理等方面都做了基于场景的优化。具体来说 HUSE 为支付宝云开发服务提供以下关键能力:

全栈高可用
整个调度系统具备 0 损发布升级能力,结合 0 感重调度,即使某些系统组件异常也不影响业务整体可用性。
资源秒级弹性
整个节点技术栈 All in One 打包在一个镜像中,业务流量驱动式的扩缩容,集群资源可以秒级弹性,帮助用户轻松应对业务洪峰。
多级自适应缓存
调度器和节点联动,根据业务流量、函数代码版本、函数语言等多因素决策,构建全栈的多级缓存,低至 50ms 交付一个可运行的函数实例。同时,缓存的函数实例可以实现多个函数代码的复用,提升用户体验的同时节省了用户成本。
高速协议通信
针对支付宝云开发场景低延迟的强需求,HUSE 自研了基于增量通信的全并行事件处理层,可以实现 10000 调度 QPS 下,us 级的调度结果分发。同时,调度器和节点基于该消息通信层互相守护,实现秒级 FO。
智能包加载
对于用户函数请求,HUSE 通过智能包分发技术,预测函数请求并提前将用户代码包分发至最适合的节点上,将函数代码包的加载速度提升到 ms 级。
节点自运维 &自调度
传统中心化的运维方式已经无法满足支付宝云开发场景对故障发现和处理的时效性要求。HUSE 的运维体系是去中心化的,节点高度自治,具备自运维和自调度能力,可以实现 ms 级故障发现和自愈。
高性能
全集群 10000 QPS 调度吞吐下,HUSE 可以实现平均 21ms 的容器调度延迟。

目的地景点不存在?极致的容器冷启动
当旅客在拿到目的地景点信息之后,发现景点不存在?不怕,在旅客驶向目的地的这段时间,支付宝云开发就可以从 0-1 制作一个安全、稳定、低消耗的景点(函数实例)。
NanoVisor 是一款重构于开源 gVisor 项目,为云原生应用专门定制、优化的弹性安全容器运行时。作为一个容器运行时,它可以对接 Kubernetes CRI API,容器用户无感接入;作为一款安全容器,防止容器逃逸,降低基础设施安全风险,保障云原生的安全可信;作为一个应用内核,加速热点路径、定制内核逻辑,实现可编程的内核;作为一个引擎,从 1 到 N,按需、极速实例创建,让计算更加绿色。

在支付宝云开发场景下,NanoVisor 针对函数启动这一热点路径做了很多优化,成功突破 100ms 大关。
造一个景点:极速启动优化
支付宝云开发场景下,原先控制面的非热点路径——容器启动,变成了时延敏感的热点路径。当前场景内,只有等到 Node.js Runtime 完成初始化之后,才能够去接收用户过来的请求,所以如何加速 Runtime 启动成为了一个亟待解决的课题。

我们采用 checkpoint/restore 的方法,首先按照传统方式创建、启动一个容器,等待容器内的 Node.js Runtime 初始化完成之后,使用 checkpoint 技术(参考)对 Node.js Runtime 进程和应用程序内核 sentry 进行状态、数据的保存。

在容器启动阶段,我们使用 restore 来进行容器启动,使用 restore 的好处是,直接利用之前保存好的进程、内核状态和数据进行恢复,不再需要重新初始化 Node.js Runtime,在恢复完成之后,Node.js Runtime 就可以开始处理来自用户的请求。经由这种方法,函数实例的启动速度大大提升(节省了 Node.js Runtime 初始化时间)。
景点安保:安全防护
作为安全容器运行时,NanoVisor 相较于传统的 Linux 容器(使用 cgroup, namespace, seccomp, chroot)增加了多层防护和管控能力,主要分为纵向隔离(防止容器逃逸)和横向隔离(尤其是网络 ACL)两个方向。
纵向隔离
NanoVisor 提供了一个 Go 语言编写的应用程序内核 sentry,它会处理所有函数实例(Node.js 代码)的系统调用,一个函数实例对应 Host 上的一个用户态进程(runsc-sandbox)。应用程序(Node.js)运行在虚拟化的 guest 态,它的系统调用会被 sentry(运行在 guest kernel 态和 host user 态)处理和响应。虚拟化由一个轻量级的 vmm 管理,它是 host 上的一个内核模块。sentry 本身的系统调用由 seccomp 进行限制。
因此,如果有用户执行了恶意的 Node.js 代码,如果想要攻破宿主机,就首先要攻破 Go 语言的应用程序内核 sentry,然后再突破 seccomp 的限制。多层防御纵深使得攻击成本和难度都大大增加,极大增强了安全性。
横向隔离

NanoVisor 在应用程序内核 sentry、网络协议栈 TLDK 内增加了访问控制模块(Access Control,AC),用户可以通过 runsc 命令对指定的容器下发管控规则,实现行为管控,包括:
网络行为审计(网络相关的操作,如 connect, accept, recvmsg 等)
DNS 请求审计、拦截
端口监听管控
基于五元组的信息的四层网络管控
游记:旅行的时间和花费
以下是 100ms 的神奇旅行的总结:

凭票上车:花费 5ms
获取目的地信息:花费 5ms
在目的地造一个景点:花费 90ms
敬请期待:从火车🚇到高铁🚄
毫秒级的极致容器冷启动(在目的地造一个景点花费<10ms):one request per instance
如果您在使用过程中遇到技术问题,欢迎来官网社区留言反馈,我们会尽快给您做出响应。
评论