不改代码也能全面 Serverless 化,阿里中间件如何解这一难题?

Serverless 话题涉及范围极广,几乎包含了代码管理、测试、发布、运维和扩容等与应用生命周期关联的全部环节。在线应用如何不改代码也能迁移到 Serverless 架构?今天,咱们来揭秘阿里巴巴成千上万在线应用的Serverless 演进过程。java

AWS Lambda 是 Serverless 领域的标志性产品,但若是将其应用于核心业务,可能会遇到如下难题:(仅表明做者我的观点)web

  • 要求用户以 Function 为单位进行开发,全新的开发框架,云厂商强绑定,社区主流技术栈迁移成本高;
  • Function 启动速度要足够快,毫秒级或者秒级,这个限制对适用场景有很强的约束;
  • Function 之间的调用经过 API Gateway,响应时间更长。

Cloud Service Engine 云服务引擎(如下简称CSE),是阿里云中间件团队开发的面向通用 Serverless 计算的中间件产品,目的是具有 AWS Lambda 的各类优点,同时能够解决用户在使用 AWS Lambda 时遇到的难题。spring

什么是 Serverless?

AWS 对 Serverless 定义是:服务器

AWS 无服务器平台提供的功能:网络

AWS 的整套 Serverless 方案很是完善,可是没有解决存量应用如何迁移到 Serverless 架构的问题。仅仅是针对新开发的应用,建议用户使用 FaaS 方式开发,才有机会转向 Serverless 架构。笔者认为,要将 Serverless 架构大规模推广,必需要能有针对存量业务的解决方案。数据结构

Serverless 对云计算的价值

云计算,归根结底是一种 IT 服务提供模式,不管是公共云仍是专有云(以 IT 设备的归属不一样分类),其本质都是帮助 IT 的最终使用者随时随地,而且简便快速地,获取 IT 服务,目前,IaaS、PaaS 都已经作到了按需付费,PaaS 甚至作到了按请求付费,如 DB,CACHE,MQ 等,可是 IaaS 的付费粒度仍然是时间维度,最快按照小时付费,以分钟来交付。架构

所以,当下的云计算场景,应用的开发维护方式相比传统 IDC 时代的开发维护,差异还不是很大。但 AWS Lambda 提供了一种全新的开发维护方式,用户只须要写好业务代码,提交到云上,全部和机器容量、可用性、机器为单位的运维工做能够所有交给了云平台,这种模式极大地释放了云的弹性价值,真正作到了按需付费。app

CSE 试图提供一种更规模化的解决方案,像 AWS Lambda 同样,能进一步释放云的弹性价值,而且能够平滑迁移存量应用。框架

存量在线业务实现 Serverless 架构的挑战

存量在线应用程序具备如下特色:less

  • 资源分配速度 = 分钟级
  • 应用程序启动速度 = 10分钟+

基于以上客观条件,一般作法是提早预约好机器数量来应对任意时刻的流量峰值,假设上述技术参数变为毫秒级,就有机会将应用程序架构演变成下图所示方式。

上图中,Service A 在调用 Service B 时,若是 B 的容量充足,则调用成功;若是 B 的容量不足,这时候若是线程池满,则直接触发限流阀值,A 会收到一个错误码,而后直接调用资源总控系统,资源总控系统负责新分配一个 Service B 实例,这个分配的速度很是快,耗时几十毫秒,同时把 B 的服务地址直接返回给 A,A 会将以前未完成的请求发送到新建立的 Service B。

以上过程对于开发者彻底透明,具有了如下价值:

  • 价值一:无需管理服务器,即无需容量评估;容量评估这件事情对于应用负责人一直是一个极难解的问题,由于咱们很难预测将来的峰值是什么。
  • 价值二:持续扩展;以前的作法是每一个应用程序独占必定数量的资源,若是变成Serverless 模式,全部应用程序能够共享资源池,每一个应用程序几乎能够无限扩展。
  • 价值三:按照请求计费;由于每一个实例的启动时间甚至比 FaaS 的函数启动时间还快,就能够像 FaaS 同样来核算成本,成本只与如下因素有关:
  1. 请求数量(QPS)
  2. 每次请求CPU执行时间,例如100ms
  3. 每一个实例的内存规格

综上所述:为了作到以上描述的分布式架构,关键技术点在于应用启动速度,这里的应用启动速度是指应用能够正常处理流量为止。

如何将应用启动速度提升到毫秒级?

应用在启动过程当中一般会初始化多个组件,如各类中间件、数据结构,以及网络调用外部服务。在阿里内部普遍使用 SOA 和微服务的状况下,应用在启动过程当中会大量加载共享业务 SDK,存在启动过程达到10分钟量级的状况,个别应用可能会更长。所以,这个启动过程必须提早完成,才有机会以“临阵磨枪”的方式去建立新实例。

方案一:应用冷启动资源压缩方案

L1 弹性能力是指在一台物理机或者大规格的 ECS 上部署同一个应用的多个实例,经过操做系统和 JVM 的优化,一个占用 4G 内存的应用,即便部署10份,仅需占用2.2G RAM。

L1 总结来看是一种高密度部署方式,因为应用已经提早启动,而且对容器进行冻结,意味着这个应用实例 CPU 占用率为0,RAM 占用至关于以前的1/20,可是具有了毫秒级弹性的能力。L1的特色是启动速度极快,可是须要消耗资源,且只能垂直弹性。

L2 是经过将应用程序启动后在 RAM 中的指令和数据结构 dump 到磁盘文件,只须要在机器之间拷贝文件便可以达到横向弹性的能力,这个时间消耗主要是数据的网络传输时间+内存拷贝时间,大约在5秒左右就能够完成。L2 的成本开销只有网络磁盘容量,开销极低,可忽略不计。

L2 的每一个 SNAOSHOT 对应一个可运行的实例,例如预计一个应用须要最大启动100个实例,那么须要提早生成100个 SNAOSHOT,每一个 SNAOSHOT 对应一个运行实例,须要启动时,从远程磁盘加载这个 SNAPSHOT。

此方案经过 L1 和 L2 的组合来达到加速应用启动的目的,在支持必定流量脉冲能力下,能够最大50ms内启动任意应用,平均在10ms内完成。

方案二:应用热复制启动加速方案

L1 采用经过 fork 种子进程达到快速启动的效果,操做系统团队专门为此开发了 fork2 技术,与 Linux Native fork 的关键区别在于能够指定 PID 来 fork 一个进程。

L2 的单个 SNAPSHOT 能够建立多个进程,一对多关系。

两种自研方案的对比

  • 方案一:不存在 UUID 问题,可是每种语言的 VM 要单独定制,成本效果相比方案二略差。
  • 方案二:会存在 UUID 问题,若开发者但愿应用的每一个实例启动时,都赋值一个 UUID 给一个静态变量,但经过 fork 会致使每一个实例的这个静态变量都相同,这与开发者预期不符。方案二的优点是更易实现、和语言无关、成本效果更优,适合 FaaS、NBF 这类场景或者开发者本身定义的开发框架,能避免 UUID 的问题。

总体来看,方案一的适用场景更广,可是实现成本更高,方案二较适合 FaaS、NBF 这类场景。

和 AWS Lambda 相比

Lambda 为了作到快速扩缩容,要求用户的应用以 Function 为单位开发,Lambda Runtime 动态加载 Function 来快速增长实例。

CSE 则经过将一个应用的多个实例启动后,共享相同的指令数据,抽取出不一样的指令数据,每次启动实例只须要加载多实例的差别部分。所以能够透明兼容社区主流技术栈,如 Spring Boot,PHP/Java/Python/Node.JS 等。

CSE 的成本优点

理论模型:

Serverless 方式应用占用的实例数随时在变化,所以能够多个应用错峰使用同一台机器。

量化分析:

Serverless 的成本优点是能够和 CPU Share &离在线混部等调度技术的成本优点作叠加,能给最终用户一个更优的整体成本。

CSE 的代码样例

HSF demo

package com.test.pandora.hsf;

import com.alibaba.boot.hsf.annotation.HSFProvider;

@HSFProvider(serviceInterface = HelloWorldService.class)
public class HelloWorldServiceImpl implements HelloWorldService {
    @Override
    public String sayHello(String name) {
        return "hello : " + name;
    }
}

Spring Boot demo

package com.example.java.gettingstarted;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class HelloworldApplication {
  @RequestMapping("/")
  public String home() {
    return "Hello World!";
  }

  @RequestMapping("/health")
  public String healthy() {
    // Message body required though ignored
    return "Still surviving.";
  }

  public static void main(String[] args) {
    SpringApplication.run(HelloworldApplication.class, args);
  }
}

CSE 的生产实践

某电商业务 A:Serverless 化后,机器数量从11台下降到2台(2~10台之间波动),某促销节,服务流量峰值从数千瞬间飙到十多万,CSE 瞬间弹性扩容,从2台-->5台-->10台,流量峰值回落后又缩容到2台。

某电商业务 B:Serverless 化后,机器数量从4台到2台(2~10台之间波动)。

某电商业务 C:以前固定4台机器,Serverless 化完成后,机器数量变成1台(1~4台之间波动),预发可实现0 - 1台实例之间波动。


原文连接 本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索