在考虑如何在无服务器环境下避免供应商锁定
这是2016年12月19日《无服务器架构 Advent Calendar》的文章。
在构建无服务器架构时,尽管在运营成本方面有一些好处,但简单地依赖某个特定的云供应商会带来依赖性太强的问题。如果可能的话,希望能够在发生 AWS 的 API Gateway 或 Lambda 突然终止服务的情况下有一些应对措施。因此,根据 Swagger 定义,我创建了一个名为 Swagger Code Builder 的工具,可以在多种配置下进行运营。
虽然与Swagger CodeGen类似,但由于项目结构差异较大,因此我们只重用了swagger-parser并重新构建了它。
追求的构图
一般来说,组成
\o/ +-----+ +-----------+
| -------->|Nginx|-->|File System|
/ \ +-----+ +-----------+
User |
|
|
| +---------------+ +----+ +-----+
+->|Spark Framework|-->|Java|-->|MySQL|
+---------------+ +----+ +-----+
Spark Framework是一种与Ruby的Sinatra和Python的Flask类似的Java微框架。虽然Spring Boot也是个不错的选择,但我选择了看起来更轻巧的(但或许这是一个失败的决定,后面会提到)。关于使用Spark Framework,可以参考过去的文章。
无服务器架构
\o/ +----------+ +--+
| -------->|CloudFront|-->|S3|
/ \ +----------+ +--+
User |
v
+-----------+ +------+ +---------+
|API Gateway|-->|Lambda|-->|Dynamo DB|
+-----------+ +------+ +---------+
我认为,虽然有很多人想使用Cognito进行验证,但我们现在先专注于这种配置。之所以使用Java作为Lambda的语言,是因为我们公司有很多擅长Java的人。如果使用JavaScript的人越来越多,那可能用node.js和Express会更好。个人而言,我更喜欢Python和Flask,但听说在这个领域有一个叫Zappa的东西。关于备受瞩目的Serverless Framework,它与我们追求的双管齐下的目标有所不同。
战略
控制器层
使用Swagger的定义,可以自动生成每个配置的代码,并编写与调用方无关的代码。开发人员可以编写代码来接收和返回符合规范的POJO对象,在调用方使用自动生成的代码进行相应的转换。
# 規約に沿ったロジックの雛形
./swagger-code-builder \
--structure java-services \
--api-spec-path swagger-spec.yaml
# 通常構成の雛形
./swagger-code-builder \
--structure sparkjava \
--api-spec-path swagger-spec.yaml
# Serverless 構成の雛形
./swagger-code-builder \
--structure java-awsserverless \
--api-spec-path swagger-spec.yaml \
--aws-region ap-northeast-1 \
--aws-account-id [Account ID]
然而,我们决定放弃解决库和对象依赖关系,而是选择逐个编写它们。我们将手动编写 Gradle 的 dependencies、Spark Framework 中使用的 Guice 的 Module、以及 Lambda 的构造函数等部分。虽然我认为如果能够巧妙地利用 DI,这些部分可以被简化,但目前还没有完全整合好。
此外,我們也正在自動生成轉換 Spark Framework 的 Request 物件的程式碼,但如果想要使用自動生成之外的目標物件,那麼這個轉換也需要進行修改。另外,像 Swagger CodeGen 這樣的 POJO 自動生成工具可能還不完善,對於與持久層的整合也需要進一步探討,目前我們對此尚未有太多進展。
我已经使 API Gateway 的设置生成供应商扩展自动生成,只需运行 Lambda 的上传、import-rest-api 和授权脚本即可完成。您还可以在生成选项中设置全局的 CORS 和 API Key。然后,在 AWS 控制台上点击几次即可完成部署。
考虑到之前请求的接受部分(包括Nginx的反向代理、Cloud Front的源和行为),我认为除了Kong之外,还应考虑其他方法。
持久化层
将模型分成逻辑层(Service Layer)和处理具体数据读写的部分(Data Access Object Layer),并通过依赖注入来切换。由于在DAO部分中编写了冗余的代码,需要另外解决这个问题。
在中国本地化的方式只需要一个选择:
操作 DynamoDB 使用 JDBC 可能有一些专有的方式,但似乎没有开源的解决方案。在 RDB←→DynamoDB 方面,处理 List、Map 和 Set 数据会很麻烦;在 DynamoDB←→Cassandra 方面,类型定义的对应似乎也很麻烦。虽然没有被纳入主体,但考虑到 Spring Data DynamoDB 的存在,或许选择使用 Spring 会更好。
最终
尽管Swagger Code Builder还有很多问题,但我们实际上正在使用它来开发小型的内部工具。我认为特别是在API Gateway的集成方面,不需要在屏幕上点点点操作,这真的非常方便。如果您想实现避免供应商锁定的无服务器架构开发,我们非常希望您能够尝试它。期待您的反馈和问题。