阿里云Serverless函数计算FC集成TableStore表格存储

阿里云Serverless技术、产品选型理由

从发展历程中,我们也可以看出,以函数为起点,Serverless 的技术和产品逐步趋于多元化。多种形态相互补充,为解决更复杂、更多样化的业务场景提供支撑,我们通常会把场景分为三类:

  • 函数计算(FaaS):面向函数,用户只需关注函数层级的代码,用于解决轻量型、无状态、有时效的任务;>
  • Serverless 应用托管:面向应用,用户只需要更关注应用本身,与微服务结合,它融合应用治理、可观测,降低了新应用的构建成本、老应用的适配改造成本;
  • Serverelss 容器服务:面向容器,在不改变当前 Kubernetes 的前提下,由于不再需要关注节点,大大提升了前期资源的准备过程,降低了维护成本,使得应用的全生命周期管理更高效。

随着 Serverless 的内涵持续外延,计算的 Serverless 化要求 BaaS 服务也具备与之配套的托管能力和极致弹性,全链路完整支撑真正 Serverless 化的应用构建。

——《Serverless 进阶实战课》极客时间

Serverless 产品概念:
信通院标准书

Servless解决方案图:
信通院标准书

目前Serverless技术绝大部分都是基于Knative来进行构建的。Knative是什么:

Knative is a platform-agnostic solution for running serverless deployments.

Knative 是一种用于运行无服务器部署的与平台无关的解决方案。

—— What is Knative | Knative

运行Serverless函数会自动生成一个容器

When you build or run a function, an Open Container Initiative (OCI) format container image is generated automatically for you, and is stored in a container registry. Each time you update your code and then run or deploy it, the container image is also updated.

当您构建或运行函数时,会自动为您生成开放容器计划 (OCI) 格式的容器映像,并将其存储在容器注册表中。每次更新代码然后运行或部署它时,容器映像也会更新。

—— About Knative Functions | Knative

也就是无论时面向函数、应用、容器的Serverless服务,实际上底层的实现都是通过将代码打包成OCI镜像,然后用Knative容器来运行该镜像的。

容器与虚拟机的差异:

容器允许应用组件共享单个操作系统实例的资源,就像虚拟机 (VM) 允许应用共享单个物理计算机的资源一样。 容器比虚拟机更小、资源效率更高,更适合敏捷和 DevOps 开发方法的增量发布周期,容器已成为现代云原生应用事实上的计算单元。

—— 为什么 Kubernetes 需要 Knative

再且由于实际上Serverless的运行单位是容器,再加上阿里云支持自定义容器镜像,所以可以将Rust、AI、GPU等非阿里云内置支持语言打包成容器镜像以后,进行Serverless部署

Serverless预留资源

TableStore当业务稳定以后,需要将纯按量计费提升为预留吞吐量按量计费,这样可以节省成本。

详情:TableStore不同预留读写吞吐量的计费案例

访问量稳定以后,可以通过预留函数实例来避免冷启动导致请求延迟

详情:配置预留实例

Serverless应用开发

前提:

  1. 因为事件函数不能响应HTTP请求,不能处理HTTP触发器的参数,所以函数类型只能选择Web函数(可自定义容器镜像)。
  2. 再进一步,想要提交代码以后自动构建并部署函数,并对函数版本进行管理,就使用“应用”

创建Serverless应用

应用创建:选择模板(Express,轻量级nodejs,必要功能齐全,可通过中间件扩展)
因为应用最终还是要变成函数执行,所以创建应用会带一个函数,该函数在后续也不能删除。

开发和部署

创建出来的模板仓库中,有README.md文档,里面有如何本地开发并部署上云的。(但是windows下执行s deploy会导致异常,因为s.yaml中的命令是unix的。)

所以直接在WebIDE开发,然后保存提交部署可以解决部署问题(但是测试速度慢,得等1分钟部署好)

添加依赖的方式

nodejs可以直接在package.json中添加依赖。

参考为函数安装第三方依赖

通过层添加依赖,是一个可以在多个函数中共用依赖的方法。将公共依赖或者工具类放到层中,让函数依赖层。

WebIDE终端安装依赖的方式无效,并不会实际作用到package.json中。

Serverless应用集成TableStore

客户端配置

根据推荐的方式,将拥有TableStore权限的RAM账号,AccessKey ID和Secret设置为环境变量,在程序中读取环境变量,会更安全。

但是每次应用部署时就会覆盖函数的配置,包括环境变量。所以环境变量目前只写在了s.yaml中,和硬编码在代码里差不多。

Serverless函数的日志设置也是,每次应用部署都会被应用覆盖,导致没开启,这个还得解决。

Express请求中等待TableStore请求响应再返回

因为Express的Route Handler有同步和异步两种形式。

TableStore的Client请求时,既接受callback回调函数,也会在同一个方法调用时返回一个Promise,以用来支持async语法(官方示例没有提到,翻看源码才看到)。

如果是直抄默认示例的话,那么同步的Route Handler加上Client的回调函数,会导致在Client的回调函数还没有执行完的时候,Express请求响应就结束了。或者如果把response的输出放在了callback回调函数中的话,就会导致Route Handler执行完了,但是没有返回响应。

所以正确的做法是,使用async修饰Route Handler,书写成异步路由处理器;再在Route Handler方法中使用await等待TableStore的Client调用的Promise结果resolve或者catch。这样才能在Route Handler处理完成时,既拿到TableStore的处理结果,也能将处理结果在响应中返回。

条件查询

因为SQL查询需要额外按量收费,所以优先使用TableStore提供的API。

条件查询文档:过滤器 | TableStore 阿里云文档

function getRowWithCompositeCondition() {
  //设置过滤器,当col1 = 表格存储且col5 = 123456789时,返回该行。
  var condition = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
  condition.addSubCondition(new TableStore.SingleColumnCondition('col1', '表格存储', TableStore.ComparatorType.EQUAL));
  condition.addSubCondition(new TableStore.SingleColumnCondition('col5', Long.fromNumber(123456789), TableStore.ComparatorType.EQUAL));

  params.columnFilter = condition;
  client.getRow(params, function (err, data) {
    if (err) {
      console.log('error:', err);
      return;
    }
    console.log('success:', data);
  });
}

TableStore过滤器源码 | Github

条件更新

样例代码

var TableStore = require('../index.js');
var Long = TableStore.Long;
var client = require('./client');

var params = {
    tableName: "sampleTable",
    primaryKey: [{ 'gid': Long.fromNumber(20013) }, { 'uid': Long.fromNumber(20013) }],
    updateOfAttributeColumns: [{ 'PUT': [{ 'col1': 'test6' }] }]
};

/*
条件更新使用说明:
1、期望行是否存在
RowExistenceExpectation.IGNORE 表示不管此行是否已经存在,都会插入新数据,如果之前有会被覆盖。
RowExistenceExpectation.EXPECT_EXIST 表示只有此行存在时,才会插入新数据,此时,原有数据也会被覆盖。
RowExistenceExpectation.EXPECT_NOT_EXIST 表示只有此行不存在时,才会插入数据,否则不执行。
2、条件组合
TableStore.SingleColumnCondition 只有一个条件的时候使用
TableStore.CompositeCondition 有多个条件的时候使用
*/

//示例:指定条件 期望行存在,并且name=john,addr=china
var condition = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
condition.addSubCondition(new TableStore.SingleColumnCondition('name', 'john', TableStore.ComparatorType.EQUAL));
condition.addSubCondition(new TableStore.SingleColumnCondition('addr', 'china', TableStore.ComparatorType.EQUAL));

params.condition = new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_EXIST, condition);

client.updateRow(params,
    function (err, data) {
        if (err) {
            console.log('error:', err);
            return;
        }
        console.log('success:', data);
    });

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值