对Serverless架构的一点体验和思考

976 阅读10分钟
原文链接: www.jianshu.com

发端

云计算机经过这么多年的发展,逐渐进化到用户仅需关注业务和所需的资源。通过Swarm、K8S这些编排工具,容器服务让开发者的体验达到很完美的境界。我曾经觉得Docker可以替代虚机,用户只要关注自己的计算和需要的资源就行,不需要操心到机器这一层。但是因为Docker对资源的隔离不够好,各大云厂商的做法还是一个Docker对应一台虚机,不仅成本高,给用户暴露虚机也多余了。

用户为什么需要关注业务运行所需要的CPU、内存、网络情况?还有没有更好的解决方案?Serverless架构应运而生,让人们不再操心运行所需的资源,只需关注自己的业务逻辑,并且为实际消耗的资源付费。可以说,随着Serverless架构的兴起,真正的云计算时代才算到来了。

容器在开发模式方面并没有提出新的想法,大家还是在用传统的那一套开发模式,需要写一个大而全的后端服务。与之对比,Serverless架构是事件驱动的,这样让后端的开发体验变得跟前端和移动端很类似了。针对不同客户的需求,先让其购买好相关的资源,然后一个个填坑,给不同的产品添加各种事件处理逻辑就行。这就跟iOS开发一样,界面写出来,然后处理一个个事件就好了,大家都很容易理解这种开发模式。

image.png

AWS Lambda体验

AWS在2014年11月的re:Invent大会上推出Lambda,经过将近三年的发展,已经达到了非常完善的程度。Lambda主要有三个作用。

  1. 跟API Gateway结合起来,方便快捷地提供API服务。
  2. 串联关键产品,比如在DDB插入一条新数据之后,触发Lambda执行,读取新记录送给搜索引擎建索引。
  3. 扩展功能,比如Cognito User Pool提供非常多的点,方便用户在登录的时候增加自己的处理逻辑。


    image.png

AWS Lambda支持多种语言开发,比如C#、Java、Node.js和Python,拥有广泛的群众基础。

AWS Lambda在除北京之外的所有region均可用。AWS中国支持的产品可以参考:地区表

image.png

Serverless Reference Architecture: Mobile Backend是一个非常好的实例,讲述了如何通过Serverless架构实现一个App。

这个App的主要功能类似Evernote,支持上传图片,编写和上传文章。功能非常简单,但是涉及到的产品非常多,玩法也非常老练。

1 2 3
image.png image.png image.png

整个demo用到的云产品和它们相互之间的关系如下图所示。除了Lambda本身,IAM、API Gateway等产品也发挥了巨大的作用。

$ tree cloudformation lambda-functions 
cloudformation
├── config-helper.template
├── mobile-backend-no-cloudfront.template //去除CloudFront相关配置的template文件。在CloudFormation控制台上传该文件。
└── mobile-backend.template //如果CloudFront可用的话,上传这个template文件也OK。
lambda-functions //Lambda代码已经压缩好并放到一个公共的S3 bucket里面,所以不用管这些代码。
├── search
│   └── index.js //CloudSearch搜索接口的代码
├── stream-handler
│   └── index.js //DDB触发建索引的代码
└── upload-note
    └── index.js //新增文章接口的代码,主要是写DDB。
image.png

配置

CloudFormation真的很方便,template上传之后,相关的资源就创建和设置好了。cloudformation目录下有两个template文件,只需上传mobile-backend.template,它会把config-helper.template加载好。阿里云对应的产品是:资源编排ROS

image.png

看起来API Gateway、Cognito、CloudSearch这几款个产品对CloudFormation支持的并不好,所以还需要通过文章中那么多命令行和Web控制台上的设置。

为了能运行这些命令,要把AWS CLI配置好,region设置为us-east-1(弗吉尼亚北部),因为文章中存放Lambda代码压缩包的S3也是在us-east-1区域的。

$ aws configure              
AWS Access Key ID [****************X3CA]: 
AWS Secret Access Key [****************Qo3J]: 
Default region name [us-east-1]:

$ cat ~/.aws/config 
[default]
region = us-east-1
配置里面的一些坑

一个坑是CloudFront可能没有初始化好,导致CloudFormation创建失败。懒得去配置了,所以我干脆删除了CloudFormation里面CloudFront相关的配置。这样并不会影响体验。

image.png image.png

CloudFormation有一个资源创建失败后,会rollback。它把资源的创建当做一个事务来处理,全部成功才行。

image.png

客户端使用Swift 2.3写的。因为代码也比较简单,所以Convert到3.0就行。后面接着会报Ambiguous use of 'continue'错误,类似下面这样的代码使用一对小括号括住block就行。

let noteApiClient = APINotesApiClient(forKey: "USEast1NoteAPIManagerClient")
noteApiClient?.notesPost(noteRequest).continue ({ (task) -> AnyObject! in
    
    if let error = task?.error {
        print("Failed creating note: [\(error)]")
    }
    if let exception = task?.exception {
        print("Failed creating note: [\(exception)]")
    }
    if let noteResponse = task?.result as? APICreateNoteResponse {
        if((noteResponse.success) != nil) {
            print("Saved note successfully")
        }else {
            print("Unable to save note due to unknown error")
        }
    }
    return task
})

程序运行起来之后,Upload Image到S3没有问题。但是上传文章的时候会报forbidden的错误。Xcode里面会打印下面这个错误。通过Charles抓包,发现服务器端给了错误提示。

image.png

需要在Usage Plans里面Add API Stage里面操作一下,API和Stage对上就好了。文章中没有提到这个配置。

image.png
一些技术细节

App直接面对API Gateway和S3,要先从Cognito Identity Pool获取到一个id(Unauthenticated),这个Pool对应MobileClientRole角色,可以看一下这个角色的具体配置,主要是针对S3和API Gateway相关action的allow 。这里直接使用了API Gateway生成的SDK,结合Cognito Identity Pool用着也挺方便。API Gateway也支持使用Cognito UserPool做验证器,不需要SDK,用起来更加简单一些,详细信息可以参看: 对AWS Cognito的一些理解

image.png image.png

/notes的post接口交给NotesApiFunction Lambda来处理,在控制台可以看得很清楚。

image.png

DDB变动会触发执行DynamoStreamHandlerFunction这个Lambda,从配置里面也可以很清楚看到这个trigger。

image.png

效果

S3里面可以看到图片。

image.png

Dynamo DB里面可以看到Post数据。

image.png

但是CloudSearch里面Searchable Documents却一直都是0。

image.png

可以看看DynamoStreamHandlerFunction这个Lambda的数据,发现调用都失败了。

image.png

去CloudWatch里面看看。提示TypeError: Cannot read property 'S' of undefined

image.png

对着stream-handler/index.js看了一下,发现拿到Dynamo DB的数据之后,要通过.S将其转型为字符串类型。再对着文档看看,其实是没有毛病的,所以这个问题还不知道怎么解决。

function createSearchDocuments(records) {
    var searchDocuments = [];

    for(var i = 0; i<records.length; i++) {
        var record = records[i];

        if (record.eventName === "INSERT") {
            var searchDocument = {
                type : 'add',
                id : record.dynamodb.Keys.noteId.S,
                fields : {
                    headline : record.dynamodb.NewImage.headline.S,
                    note_text : record.dynamodb.NewImage.text.S
                }
            };
            searchDocuments.push(searchDocument);
        }
    }
    return searchDocuments;
}

这个问题突然就消失了,建索引和检索功能都正常了,amazing~

image.png image.png

费用

Lambda根据使用内存和调用次数收费。内存最低是128MB。具体信息请参看:Lambda 定价详情

image.png image.png

这个App使劲玩,花不了几块钱的。Lambda累计运行了240秒,没有花钱,主要是S3和数据传输花了点钱。

image.png image.png

Serverless成功的关键

拥有丰富的产品,并且打通所有的云产品,是Serverless成功的前提条件。Lambda不适合处理复杂的业务逻辑,比较适合作为胶水代码,粘合关键的产品。另外就是Lambda不管怎么完善,可能只能解决80%的问题,剩下20%的逻辑需要用户自己写服务,通过docker发布,然后给Lambda或者用户使用。这种混合的编码方式可能是未来的主流开发模式。

image.png

Serverless的主要优点

  1. 开发者更加专注于业务逻辑,开发效率更高。开发一个典型的服务器端项目,需要花很多时间处理依赖、线程、日志、发布和使用服务、部署及维护等相关的工作,基于Serverless架构则不需要操心这些工作。
  2. 用户为实际使用的资源付费。用户购买的ECS使用时间一般不到5成,但是为另外5成闲置时间付费了。Lambda按照运行的时间收费,成本会低很多。
  3. NO Architecture,NO Ops。架构师的责任是设计一个高可用、高扩展的架构。运维负责整个系统稳定可靠地运行,适当缩减和增加资源。大型云厂商能保证产品的高可用,Serverless架构本身就是高扩展的。Serverless不再需要服务器端的工作人员,给客户节省了大量的资源。架构师和运维的同学应该好好思考一下未来的出路了。架构师可以转型去做销售,整理用户的需求,然后写写CloudFormation的template就好了。
  4. 还是成本。IT行业一些领先的公司基础设施非常完善,开发工程师写好代码,然后通过发布平台发布,感觉也是挺方便的。比起Serverless的架构,成本还是要高不少。
    1. 机器成本。日常、预发、线上,1+1+2=4台服务器少不了。
    2. 时刻要关注业务数据,盘点资源,看看是否需要扩容和缩减资源。扩容容易,缩减难,造成大量资源闲置。
    3. 全链路压测是不是很烦?

Serverless的主要缺点

  1. 排查问题困难,因为逻辑散落在各处,一个操作可能触发成百上千个Lambda执行。AWS的X-Ray和CloudWatch等产品可以帮助用户排查问题。


    image.png
  2. 准备runtime需要时间,流量瞬间爆发容易导致超时。

  3. 带状态的Lambda写起来很困难。

  4. Lambda运行有诸多资源限制,比如运行时长、内存、磁盘、打开的文件数量等。


    image.png
  5. 厂商锁定。云计算是赢者通吃的行业,大而全的云厂商优势巨大,Serverless加剧了这种趋势。以前用户还需要自己写很多服务器端的逻辑,迁移的时候,把服务器端代码重新部署一下。采用Serverless架构之后,代码都是各个平台的Lambda代码片段,没法迁移。从客户的角度来看,是不希望自己被某家云厂商所绑架的。所以云计算行业需要做很多标准化的工作,方便用户无缝在各种云之间迁移。

阿里云对Serverless的支持情况

阿里云在今年四月份南京云栖大会上推出了自己的Serverless产品:函数计算,目前只支持API Gateway和OSS,并且只能在华东2区域使用。还没有形成体系,很难满足用户多样的需求。

推广Serverless不是一件容易的事情,一是现有产品上云要接入的东西有点多,比如售卖、权限、风控、服务等级等,未来还需要接入Serverless。开发团队很累。第二个是,现有大量的产品要一个个去推动做改造,不是一件容易的事情。

不过阿里云也在很努力完善对Serverless的支持,未来可期。函数计算携手API网关轻松实践Serverless架构

image.png

云栖社区有一些相关的文章:阿里云 Serverless Computing,讲得非常好,可以了解一下。

MBaaS/MPaaS为什么不赚钱?

移动开发领域最早有一些厂商提供移动推送、Crash收集分析、移动数据分析等基础服务,也就是MPaaS。然后逐渐有一些厂商开始提供数据库、存储、配置等相关的服务,管理员在Web控制台上操作,移动端直接使用这些服务,不需要经过服务器端中转,这就是MBaaS。

目前移动开发领域的服务提供商,比如Facebook的Parse(已关闭)、Firebase(已被Google收购,现在很强大)、国内的LeanCloud都发展得不好。我觉得主要还是因为产品线不够丰富,只能满足一些小App或者App发展初期的需要。MBaaS/MPaaS依托主流云厂商丰富的产品线,通过类似Lambda机制将这些产品串联起来,应该会有不错的发展。

参考资料

  1. 十年生聚,十年教训——我眼中的云计算
  2. Liming的动态
  3. 夏日清风 - 基于Docker Swarm的极简Serverless实践
  4. InfoQ虚拟研讨会:无服务器计算的实践方法
  5. 诱人却非万能,理性看待Serverless的落地
  6. 对AWS Cognito的一些理解