顾宇:Serverless 微服务的持续交付解析

向作者提问
埃森哲咨询经理。专注于DevOps、持续交付,微服务以及全功能产品开发团队的设计、实践、落地和推广。
查看本场Chat

2018年1月10日,周三晚上8点30分。专注于 DevOps、微服务及全功能敏捷产品团队发展,拥有丰富的大型系统实战经验,ThoughtWorks高级咨询师顾宇带来了主题为《Serverless 微服务的持续交付》的交流。以下是主持人飘静整理的问答实录,记录了作者和读者问答的精彩时刻。


内容提要:

  • 无服务器微服务的开发和设计和一般微服务有什么不同?
  • 无服务器微服务的性能如何?
  • 哪种编程语言更适合无服务器微服务开发?
  • 无服务器微服务是不是算云计算平台的标准应用架构?主要适用于那些场景?
  • 对于函数化的无服务架构,如何避免函数爆炸式的增长不可控?
  • 函数、API、源代码版本怎么管理?有什么策略?如何解决 API 之间的调用版本依赖?
  • 关于 aws lambda 的,不知道 aws lambda 是否有提供能被自动 trigger 的生命周期函数?

问:无服务器微服务的开发和设计和一般微服务有什么不同?

答:一般微服务设计和开发最好满足 12 Factors App,无服务器微服务基本上满足了这些要求。所以从设计的角度看,传统的微服务需要多考虑如何实现 12 Factors。我个人认为 12 FactorsApp 是非常好的实践。此外,无服务器微服务要考虑如何划分成跟多函数,用函数式的思维去考虑微服务的设计。而一般微服务可能是有状态的,通过基础设施等实现近似无状态。最后,我个人觉得 Serverless 比微服务更面向资源,比如数据和 API 而相对于业务的抽象较弱,而数据的抽象和表达则更多的交由前端负责。


问:无服务器微服务的性能如何?

答:这个分为两个方面,一个方面是对请求的消化。根据我们实测的结果来看。在 AWS Lambda + API Gateway 的组合上。如果业务是纯计算型的,性能比较高,但受限于 Lambda 的资源限制。如果是事务型的,取决于后端服务的反应。如果 Lambda 之后有对应其它服务的话,可以把 Lambda 看做透明的,性能由终端服务性能决定。另外一个方面是请求的扩展,目前在我的压测和使用场景里没有出现请求排队超时的现象。由于 Lambda 本身是根据请求水平扩展的,因此目前没有什么容量扩展的问题。


问:哪种编程语言更适合无服务器微服务开发?

答:基本上是函数式编程模式主导的语言,例如 nodejs,scala 等,面向对象的语言效果不会太好,因为有状态。此外,在 AWS 上面支持的编程语言里。nodejs 是首选,java 的开发效率和性能都不是很好。听说要支持 C#,可以拭目以待测试一下。


问:无服务器微服务是不是算云计算平台的标准应用架构?主要适用于那些场景?

答:我理解不是的。我觉得云计算平台应该是支持多样性的,没有所谓标准不标准。架构都是为业务服务,脱离了业务上下文,很难比较。现在我所经历的适用场景主要是数据转换。把前台的数据转换成另外一种格式传递给后台。其中再有一些计算。

另外一种就是云计算平台之间的资源相互调度,不需要单独写一个应用调度不同的云计算资源,比如我给 S3 存了一张图片,这个图片就能自动加水印放回 S3,然后记录日志到数据库里,再通知消息队列等。成为了云计算服务资源的行为扩展,这样是一种去中心化的面向计算资源的设计,以往都是中心化的设计。


问:对于函数化的无服务架构,如何避免函数爆炸式的增长不可控?

答:我想到能出现这个问题的两个场景。一个场景是微服务划分和切割,这样会把微服务切分的很小,造成数量很多。这实际上是进入了一个微服务反模式,叫做 nano service。出现这个问题的原因是不考虑团队维护微服务服务的成本,而一味追求小和独立。

在我看来,微服务拆分就是把原先应用的内部复杂度提取出来变成外部复杂度。这个复杂度需要符合团队的规模。如果走到这一步,就走错了,需要退回去。此外,可以通过一些无服务架构的框架例如 Serverless 和 Apex 来管理。另外一个场景是功能增长,导致你的函数随着功能一起增长。另外一个场景是功能增长,导致你的函数随着功能一起增长。


问:函数、API、源代码版本怎么管理?有什么策略?如何解决 API 之间的调用版本依赖?

答:源代码版本就按持续交付的版本管理就可以,单开发主干。必要的话可以单独设立一个发布主干。API Gateway 那边对于不同版本的接口可以通过 URL 给出版本,例如 /api/2.0。或者采用 HTTP Request header 上带 API 版本。对于 Lambda 的版本,它是自增的。需要在函数上增加对应的别名来指向不同版本的函数。

此外,别名和版本之间的关系需要单独管理,函数别名 alias。我之前用的是 Jenkins 插件,但是函数多了之后就有问题。另外一种方式是采用函数版本配置文件,需要自己写自动化脚本,用 aws 的 cli 来配置。内部 RPC 的话就要在调用点上加版本了。不过一定注意不能让旧版本下线。这个一不小心很容易出问题,尤其是团队大的时候。

如果你存在多个版本依赖。比如1.1,1.2,1.3 三个版本都存在依赖。就不能让 1.1 版本的 API 下线,最好的办法是让调用端或者消费者端同步升级。否则后来管理各版本依赖会出问题。要么就要在 API 里做好向前兼容。我刚想到了一个我以前碰到的生产事故。就是某 API 在不断升级,但是客户端不升级。当时没考虑向前兼容。就用 URL 版本隔离开。后来团队有个新来的人做重构,看到这个 API 版本很老,就删了。虽然只是个 URL 配置,但是影响蛮大的。当时那个 API 保存了19个版本,这个应该是管理问题。

如果是 http 的话。可以用我前面说的两种方式,一种在 URL 里加版本。另一种在 http Header 里加版本。


问:关于 aws lambda 的,不知道 aws lambda 是否有提供能被自动 trigger 的生命周期函数?

答: TimeOut 的时候会抛出一个异常,你消费这个异常就可以了。


本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。

微信扫描登录