据我在Golang中了解:the DB handle is meant to be long-lived and shared between many goroutines
。
但是当我将Golang与AWS lambda结合使用时,情况就大不相同了,因为lambda在完成后会停止该功能。
我正在Lambda调用函数中使用:defer db.Close()
,但不受影响。在MySQL上,它仍然保持该连接为Sleep query
。结果,它在MySQL上导致too many connections
。
当前,我必须将MySQL中的wait_timeout
设置为小数。但我认为这不是最佳解决方案。
在Lambda上使用Go SQL驱动程序时,是否可以关闭连接?
谢谢
答案 0 :(得分:3)
我们需要解决两个问题
让我们了解AWS如何管理容器。来自AWS docs:
执行Lambda函数后,AWS Lambda会维护 在预期另一个Lambda的情况下执行上下文 函数调用。实际上,该服务会冻结执行 Lambda函数完成后的上下文,并解冻 重用(如果AWS Lambda选择在Lambda时重用上下文) 函数再次被调用。 这种执行上下文重用方法具有以下含义:
Lambda函数代码中的任何声明(处理程序外部) 代码,请参阅编程模型)保持初始化状态,并提供其他 再次调用该函数时的优化。例如,如果您的 Lambda函数建立数据库连接,而不是 重新建立连接时,原始连接用于 后续调用。我们建议您在代码中添加逻辑以进行检查 创建连接之前是否存在连接。
每个执行上下文在以下位置提供500MB的额外磁盘空间: / tmp目录。目录内容在执行时保留 上下文被冻结,提供可用于以下目的的临时缓存 多次调用。您可以添加额外的代码来检查缓存是否具有 您存储的数据。有关部署限制的信息,请参阅 AWS Lambda限制。
Lambda函数启动的后台进程或回调 如果AWS Lambda恢复了功能结束时未完成的操作 选择重用执行上下文。你应该确保任何 代码中的后台进程或回调(对于Node.js) 在代码退出之前完成。
第一个要点指出,两次执行之间保持状态。让我们看看实际情况:
let counter = 0
module.exports.handler = (event, context, callback) => {
counter++
callback(null, { count: counter })
}
如果您部署它并连续多次呼叫,您会看到计数器将在两次呼叫之间递增。
现在您知道了-不应调用defer db.Close()
,而应重用数据库实例。您只需将db
设为包级变量即可。
首先,创建一个数据库程序包,该程序包将导出一个Open
函数:
package database
import (
"fmt"
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
)
var (
host = os.Getenv("DB_HOST")
port = os.Getenv("DB_PORT")
user = os.Getenv("DB_USER")
name = os.Getenv("DB_NAME")
pass = os.Getenv("DB_PASS")
)
func Open() (db *gorm.DB) {
args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", user, pass, host, port, name)
// Initialize a new db connection.
db, err := gorm.Open("mysql", args)
if err != nil {
panic(err)
}
return
}
然后在您的handler.go文件中使用它:
package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/jinzhu/gorm"
"github.com/<username>/<name-of-lib>/database"
)
var db *gorm.DB
func init() {
db = database.Open()
}
func Handler() (events.APIGatewayProxyResponse, error) {
// You can use db here.
return events.APIGatewayProxyResponse{
StatusCode: 201,
}, nil
}
func main() {
lambda.Start(Handler)
}
OBS :不要忘记用正确的路径替换github.com/<username>/<name-of-lib>/database
。
现在,您可能仍然会看到too many connections
错误。如果发生这种情况,您将需要一个连接池。
来自Wikipedia:
在软件工程中,连接池是数据库的缓存 保持连接,以便在以下情况下可以重用连接 以后需要对数据库的请求。连接池是 用于提高在数据库上执行命令的性能。
您将需要一个连接池,该连接池的允许连接数必须等于运行的并行lambda数,您有两种选择:
MySQL Proxy是一个简单的程序,位于您的客户端和 可以监视,分析或转换其MySQL服务器 通讯。它的灵活性允许广泛的用途, 包括负载平衡,故障转移,查询分析,查询过滤 和修改等等。
Amazon Aurora Serverless是按需自动缩放配置 适用于Amazon Aurora(与MySQL兼容的版本),数据库将在其中 自动启动,关闭并根据容量增加或减少容量 根据您的应用程序的需求。它使您可以在以下位置运行数据库 云,无需管理任何数据库实例。很简单 具有成本效益的选项,可用于偶尔,间歇或不可预测的情况 工作量。
无论您选择哪种方式,互联网上都有很多关于如何同时配置两者的教程。