用 C++ 写一个 AWS Lambda Hello World

AWS 自 2014 年推出 Lambda 时仅支持 Node.js,而后添加了对 Python, Ruby, Java, C#, F#, PowerShell 的支持,再来到 2018 年可以自定义运行时了,比如用性能较好的 C, C++, Rust, Go 等语言。见 AWS Lambda Now Supports Custom Runtimes and Enables Sharing Common Code Between Functions.

如果使用 Python, Java 写 Lambda 时觉得还不得快,不想要明显的预热过程,也许 1000 毫秒的任务只想要 600 毫秒就能完成,内存还希望再压缩一些,那着实能在每月千百万次 Lambda 调用的情况下节省一笔可观的支出,那么可以试一试 C, C++, Rust, Go 等编译成了机器指令的语言,况且前三者没有 GC, 执行效率会更高。

本日志记录一下如何用 C++ 创建一个 AWS Lambda, 以及可如何应付 Lambda 的复用。本文主要参考自下面两处

  1. Introducing the C++ Lambda Runtime
  2. GitHub 项目 aws-lambda-cpp

自定义运行时可选择 X86_64 或 arm64 的 Amazon Linux 2023 或 Amazon Linux 2。部署时可选择的 runtime 相应有 provided.al2023, provided.al2, 推荐使用 provided.al2023。runtime provided 不被支持了。

C++ 代码可选择用 GCC 或 Clang 来编译,既然 AWS Lambda 实际的运行时会用到 Amazon Linux 2023,那我们就直接选择 Docker 镜像 amazonlinux:2023 作为我们的编译环境。 阅读全文 >>

Vagrant 没了 VirtualBox 的话可以配 Qemu

开源虚拟机软件 VirtualBox 从当初不可一世的 Sun 易手到 Oracle 之间,变得不那么被许多公司信任了。之前一直是用 Vagrant 搭配 VirtualBox 在 Mac 下使用 Linux 虚拟机,因为不需要用到 Linux 桌面,用 Vagrant 操作虚拟机非常方便。但现在不得不要考虑别的方式,那就是 Vagrant + Qemu。Vagrant 的默认 Provider 是 VirtualBox, 我们搜索 Vagrant Box https://app.vagrantup.com/boxes/search 的时候,注意到  Vagrant 其实支持的 Provider 是一个很长的列表:

aws, cloudstack, digitalocean, docker, google, hyperv, libvirt, lxc, openstack, parallels, qemu, rackspace, softlayer, veertu, virtubalbox, vmware, vmware_desktop, vmware_fusion, vmware_ovf, vmware_workstation, vsphere, xenserver

有些尚未听说过,还有一些虽说支持,但别人提供的相应的 box 不多,Qemu 还算不错的 virtualbox 的替代品。Qemu 也是一款开源的虚拟机软件,它支持 Linux, macOS 和 Windows  平台,但它本身未提供友好的 UI 工具,所以创建一个 Qemu 虚拟机的命令会让人畏而却步。在 macOS 下有一个 Qemu 的 UI 工具 UTM 阅读全文 >>

JDBC 操作 SQL Server 时如何传入列表参数

本文是作为将要对 PostgreSQL 的 in, any() 操作的一个铺垫,也是对先前用 JDBC 操作 SQL Server 的温习。以此记录一下用 JDBC 查询 SQL Server 时如何传递一个列表参数。比如想像一下查询语句

select * from users where id in (?)

 我们是否能给这里的问题参数传递一个 List 或数组呢?

这里所引用的 SQL Server 的 JDBC 驱动是 com.microsoft.sqlserver:mssql-jdbc:11.2.0.jre8

我们尝试调用 PreparedStatement.setArray() 方法来设置这个参数

pstmt.setArray(1, conn.createArrayOf("int", new Integer[]{1,2,3}));

这里会受到两个阻碍,首先

SQL Server 的 PreparedStatement 的实现类 SQLServerPreparedStatement 的 setArray() 未实现,反编译出它的 setArray() 方法是 阅读全文 >>

学习 Airflow 第一篇章

Airflow 起初是由 Airbnb 开发的, 用于调度和监控工作流的平台,后来开源了, 并于 2019 年 1 月成为了 Apache 的顶级项目。它是用 Python 编写的,管理的工作流是有向无环图(DAG - Directed Acyclic Graph), 这能满足绝大多数情况下的需求。

顺带插一句,Airflow 用了与 Google Photos 极其相似的 Logo,不知算不算侵权。

说到工作调度,头脑中很快会掠过 Cron, 计划任务, Quartz, Spring Schedule, 和 Control-M。除了商业的 Control-M 有调度和监控工作流的功能外,其他的基本只用来调度任务,监控全靠自己的日志。

还有一个类似的工具是由易观贡献给 Apache 的 DolphinScheduler, 它处理的也是 DAG 工作流,用 Java 实现的,所以体量大,硬件要求会高些。它的工作流的创建是通过 Web UI 可视化界面完成的,对程序员来说不那么友好。奇怪的是, 作为 Apache 旗下的项目,项目首页面是中文的,启动后控制台默认界面也是中文的。

而 Airflow 功能就厉害了, 它可动态管理工作流,易于扩展,可集群化进行伸缩,更有一个漂亮的 UI 用于实时监控任务。基于以上特性 Airflow 是很适于执行数据的 ETL(Extract, Transform, Load) 操作的。

这么好的开源产品, 免不了又被 AWS 盯上了, 以 Amazon Managed Workflows for Apache Airflow(MWAA) 服务进行出售,费用还真不菲。AWS 创造性的以 vCPU 数量,DAG 数量限制进行分层次进行收费,远比自己启动一两个 EC2 实例部署 Airflow 贵的多。但 MWAA 有个方便的特性就是 DAG 文件可以放到 S3 中自动部署,相信自己部署的 Airflow 也能进行扩展而从 S3 加载 DAG。 阅读全文 >>

Python 3.9 新特性回顾

Python 3.10 虽已于 2021/10/04 发布,但目前主要使用的 Python 版本仍然是 3.9。之前有两篇介绍了 Python 3.7 和 3.8 带来的新特性

  1. Python 3.7 所带来的新特性
  2. 体验一下 Python 3.8 带来的主要新特性

于此,再补充一下 Python 3.7 和 3.8 各自的发布日期是 2018/06/27 和 2019/10/14。Python 3.9 是在 2020/10/05 发布,由此看出 Python 是每年一发布。

每个版本的主要新特性就是它们的亮点,不关注新特性也就不能很好的掌握这种语言,除非是直接使用汇编或字节码指令,他们的变迁比较缓慢。

对于以 Python 3.9 为现阶段基准版本使用来说,更有必要了解一下 Python 3.9 的新特性,不然别人一见代码就仿佛是以二战时的打法应对现代战争。

Python 3.9 主要有哪些新特征呢?总结起来就是

字典的更新/合并, 字符串新增删除前/后缀的方法,datetime 支持时区了, Executor.shutdown() 可取消未执行的任务,类型提示可直接用 list[str], dict[str, int] 这样表示泛型 阅读全文 >>

构建 AWS AMI 镜像(EC2 Image Builder + Terraform)

使用到 AWS 的 EC2 服务时,选择一个基础镜像后,要定制的话需要在 userdata 中写上一堆脚本。如果不想每次重复 userdata,或者要更快速的初始化一个虚拟机,就应该定制自己的 AMI,特别是在 Batch, ECS, EKS 选择的基础镜像还不方便使用 userdata。

定制一个 AMI, 我们可以用 aws create-image 命令,或是 HashiCorp 提供的 Packer(它不仅支持 AWS, 还能为 阿里云,Azure, Google 云,vmware, docker, Vagrant 等定制镜像)。而我们这里将要介绍的仍然是 HashiCorp 公司的 Terraform 并结合 AWS 的 EC2 Image Builder 服务来构建 AMI 镜像。

EC2 Image Builder 是 2019 年 12 月 1 日推出来的服务,见 Introducing EC2 Image Builder

构建一个镜像的基本过程是选择一个基础镜像来启动一个实例,然后在该实例中做一系列的操作,再保存操作后的状态为自己的镜像。这和用 Dockerfile 定制自己的 Docker 镜像是类似的。 阅读全文 >>

使用原生的 Windows Docker 容器

一谈到 Docker 容器,按照以往的惯性思维,那就是 Linux 容器(LXC),和 Windows 没多大关系,顶多也就是在 Windows 的 Linux 虚拟机中跑 Docker 容器。

不过自从 Windows Server 2016 开始,出现了 Windows 原生的 Docker 容器,它再也不只是 Linux 下的专利了。Docker 容器中可以运行 Windows 系统了, 每个 Windows 容器共享宿主机的 Windows 内核(--isolation=process,),或使用一个高度优化虚拟机中的 Windows 内核(--isolation=hyperv)。

我们说自 Windows Server 2016 开始,包括现在的 Windows Server 2019, Windows Server 2022, 还有桌面系统的 Windows 10 和  11 上 借助于 Docker Desktop 也能跑 Windows 容器。

原本在 Windows 桌面版上安装 Docker Desktop 就能用来运行 Linux 容器,由此可知在 Windows 桌面版上(如 Windows 7, 10, 11) 可运行两种类型的容器

  1. Linux 容器: 每个容器运行的是 Linux 实例,用 cgcroups 命名空间隔离资源。默认的,使用 Docker Desktop 的 LinuxEngine
  2. Windows 容器:容器中运行的是 Windows 实例,进程隔离模式是容器共享主 机的 Windows 内核,Hyper-V 隔离模式是容器使用高度优化虚拟机的内核。需启用 Windows 的 Hyper-V 特性,并切换 Docker Desktop 使用 WindowsEngine

阅读全文 >>

AWS Assume IAM role 的使用

AWS 要授权给他人访问指定资源有哪几种方式呢?

  1. 创建一个 AWS 帐号让别人用,那是 AWS 干的事
  2. 在自己帐号下创建一个用户,把 Access Key ID 和 Secret Access Key 告诉别人。可为该用户限定权限,但任何获得那两个 Key 的人都能使用该用户。
  3. 创建一个 IAM Role, 并指定谁(帐号或 Role) 能以该 Role 的身份来访问。被 Assume 的 Role 可限定权限和会话有效期。

用 Assume Role 的方式具有更高的安全可控性,还不用维护 Access Key ID 和 Secret Access Key。比如在构建和部署时通常是有一个特定的 Account, 然后 Assume 到别的 IAM Role 去操作资源。

本文将详细介绍在帐号 A 创建一个 IAM Role(标注为 R) 并分配一些权限,然后允许另一个帐号 B 以 IAM Role - R 的身份来访问帐号 A 下的资源。IAM Role 将用 awscli 来创建,Assume Role 的过程用 awscli 和 boto3 Python 代码两种方式来演示。 阅读全文 >>

Python 转换 Apache Avro 数据为 Parquet 格式

前面尝试过用 Java 转换 Apache Avro 数据为 Parquet 格式,本文用 Python 来做同样的事情,并且加入 logicalType: date 类型的支持。本测试中的 Avro 数据也是由 Python 代码生成的。

重复一句 Avro 与 Parquet 的最粗略的区别:Avro 广泛的应用于数据的序列化,如 Kafka,它是基于行的格式,可被流式处理,而 Parquet 是列式存储格式的,适合于基于列的查询。

第一步,生成 Avro 数据文件 user.avro, 须先安装 fastavro

pip install fastavro

生成 user.avro 的代码

阅读全文 >>

用一个例子理解 ES6 的 export/import 用法

使用了一段时间的 Vue.js 以后,其中有大量的 ES6 的 export/import 用法,如

import axios from 'axios';
import Home from '../views/Home.vue';
export default {
  data() { .... }

因为目前对 ES6 的 export/import 用法是一知半解的,所以基本上都是基于 vue-cli 创建的项目上依葫芦画瓢,更是不太理解 vue 的项目是如何由 main.js -> App.vue 把所有的 router, views, 和 components 串联起来的。为了进一步理清 Vue.js 项目的初步运行机制,现在开始着手试图通过一个例子来尽可能多的理解 ES6 的 export/import 用法。

我不是标题党,所以不可能命名如:理解 export/import 一篇就够了,全网最全诸如此类的。且本人博客主要是记录自己学习过程的,而非为了招人眼球。所以尽力吧,在一个代码例子中尽可能多的展示 export/import 的用法,为不增加代码的复杂性,有些技巧在代码后进行解释。 阅读全文 >>