解决AWS Lambda不断重启的问题
今天一个在测试部署在AWS Lambda的Function时遇到个问题,这个Function很简单,基于Java开发,通过httpclient发送请求到第三方服务器再发送给client收到的数据。从CloudWatch Logs里看,经常是一个请求耗时10秒左右,但紧接着的另一个请求就很正常,2-3秒结束。
1. 分析
一开始把问题锁定在httpclient上,加入了新的日志后发现,httpclient冷启动需要3秒,程序使用了httpclient单例模式。在冷启动之后,之后的请求将直接调用已存在的单例,几乎不费时。但是在服务闲置10来分钟之后,再次发送请求,httpclient竟然又一次冷启动。而且不止httpclient,整个Java runtime都重启了,耗时长达6秒。猜想是AWS Lambda会不定时重启Function 的context,查了下文档和其他开发者的经验,果然是这样。
Lambda will restart the context at any time so that the whole java runtime including httpclient will be re-initialized continuously.
AWS starts an execution context the first time your Lambda is called and then reuses it for the next requests. However, this is not guaranteed. AWS may shut down this context at any time, or create others to scale your Lambda in case your of heavy load.
Do not develop “heavy” application.
Minimize the complexity of your dependencies. Prefer simpler frameworks that load quickly on Execution Context startup. For example, prefer simpler Java dependency injection (IoC) frameworks like Dagger or Guice, over more complex ones like Spring Framework.
Best Practices for Working with AWS Lambda Functions
上传的代码压缩后不能超过50MB,解压后不能超过250MB,运行环境中的临时空间不超过500MB,最长运行时间不超过5分钟,等等。因此 Lambda 并不适合部署大型应用,任何启动时间长,或者代码和资源量比较大的应用都不适合部署在 Lambda 上。
Why nodejs is quickly
In nodejs, initialization code is executed once per container creation, before the handler is called for the first time.
2. 解决方案
如果Lambda服务在服务闲置后不定期重启Context,那么是不是可以用另一个Heartbeat服务定时调用这个Lambda服务,这个Heartbeat服务可以部署到另一个Lambda function里。后来发现Amazon其实是提供类似的功能CloudWatch Timer,参考这篇文章:How to Keep Your Lambda Functions Warm
登录 AWS console,进入Services->CloudWatch -> Events 点击 Create rule. 选择event type 为 Schedule, 以每1分钟的频率运行该event。之后从Targets里选择要链接的Lambda function, 保存。
可以自定义heartbeart的发送信息, 比如:
1 |
{'heartbeart': 'true'} |
如果使用默认设置,这个请求将发送空body到Lambda Function。 (APIGatewayProxyRequestEvent.getBody() is null)
3. 总结
可以使用Amazon自有的服务CloudWatch Event发送心跳到Lambda Function服务,保持服务持续运行不挂机。