从 Cloud Functions 连接到 Cloud SQL

本页介绍从 Cloud Functions 中运行的服务连接到 Cloud SQL 实例的相关信息和示例。

Cloud SQL 是一种全托管式数据库服务,让您可以轻松地在云端设置、维护、管理和控制关系型数据库。

Cloud Functions 是一个轻量级计算解决方案,可供开发者创建单一用途的独立函数,无需管理服务器或运行时环境即可对云端事件作出响应。

设置 Cloud SQL 实例

  1. 在您要从中进行连接的项目中启用 Cloud SQL Admin API(如果您尚未执行此操作):

    启用 API

  2. 创建 Cloud SQL for MySQL 实例

    默认情况下,Cloud SQL 会为新实例分配公共 IP 地址。您还可以选择分配专用 IP 地址。如需详细了解这两种地址的连接选项,请参阅 连接概览页面。

配置 Cloud Functions

配置 Cloud Functions 的步骤取决于您分配给 Cloud SQL 实例的 IP 地址类型。

公共 IP(默认)

如需配置 Cloud Functions 以启用与 Cloud SQL 实例的连接,请执行以下操作:

  • 确保上面创建的实例具有公共 IP 地址。您可以在 Google Cloud Console 中的实例概览页面上来验证这一点。如果您需要添加 IP 地址,请参阅配置公共 IP 页面来查看相关说明。
  • 获取实例的 INSTANCE_CONNECTION_NAME。您可以在 Google Cloud Console 中的实例概览页面上找到它,也可以通过运行命令 gcloud sql instances describe [INSTANCE_NAME] 来获取。
  • 确保您的函数用于对 Cloud SQL 调用进行身份验证的服务帐号具有适当的 Cloud SQL 角色和权限
    • 您的服务的服务帐号需要以下某个 IAM 角色
      • Cloud SQL Client(首选)
      • Cloud SQL Editor
      • Cloud SQL Admin
      您也可以手动分配下列 IAM 权限:
      • cloudsql.instances.connect
      • cloudsql.instances.get
      如需详细了解如何将 IAM 角色添加到服务帐号,请参阅向服务帐号授予角色

    默认情况下,应用将使用 Cloud Functions 服务帐号向您的连接授权。服务帐号的格式为 service-PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com

    如果授权服务帐号与 Cloud SQL 实例分处不同的项目,则需要为这两个项目添加 Cloud SQL Admin API 和 IAM 权限。

专用 IP

无服务器 VPC 访问通道连接器会处理与您的 VPC 网络的通信。 要使用专用 IP 直接连接,您需要:

  1. 确保上面创建的 Cloud SQL 实例具有专用 IP 地址。如果您需要添加 IP 地址,请参阅配置专用 IP 页面来查看相关说明。
  2. 在 Cloud SQL 实例所在的 VPC 网络中创建配置无服务器 VPC 访问通道连接器。
  3. 连接器必须与使用它的资源位于同一项目和区域中,但该连接器可向其他区域中的资源发送流量。

    无服务器 VPC 访问通道支持与通过 Cloud VPNVPC 网络对等互连连接的 VPC 网络进行通信。

    无服务器 VPC 访问通道不支持旧版网络共享 VPC

  4. 按照下一部分中的说明,使用您实例的专用 IP 和端口 3306 进行连接。

连接到 Cloud SQL

配置 Cloud Functions 后,您可以连接到 Cloud SQL 实例。Cloud Functions 提供了一种使用 Cloud SQL 代理进行连接的机制。

公共 IP(默认)

使用 Unix 套接字进行连接

正确配置后,您可以按照 /cloudsql/INSTANCE_CONNECTION_NAME 格式将服务连接到 Cloud SQL 实例的 Unix 网域套接字。

这些连接会自动加密,无需任何额外配置。 下面显示的代码示例摘自 GitHub 网站上提供的更完整示例。如需了解详情,请点击 View on GitHub

Python

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

# The SQLAlchemy engine will help manage interactions, including automatically
# managing a pool of connections to your database
db = sqlalchemy.create_engine(
    # Equivalent URL:
    # mysql+pymysql://<db_user>:<db_pass>@/<db_name>?unix_socket=/cloudsql/<cloud_sql_instance_name>
    sqlalchemy.engine.url.URL(
        drivername="mysql+pymysql",
        username=db_user,
        password=db_pass,
        database=db_name,
        query={"unix_socket": "/cloudsql/{}".format(cloud_sql_connection_name)},
    ),
    # ... Specify additional properties here.
    # ...
)

Java

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

// The configuration object specifies behaviors for the connection pool.
HikariConfig config = new HikariConfig();

// Configure which instance and what database user to connect with.
config.setJdbcUrl(String.format("jdbc:mysql:///%s", DB_NAME));
config.setUsername(DB_USER); // e.g. "root", "postgres"
config.setPassword(DB_PASS); // e.g. "my-password"

// For Java users, the Cloud SQL JDBC Socket Factory can provide authenticated connections.
// See https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory for details.
config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
config.addDataSourceProperty("cloudSqlInstance", CLOUD_SQL_CONNECTION_NAME);

// ... Specify additional connection properties here.
// ...

// Initialize the connection pool using the configuration object.
DataSource pool = new HikariDataSource(config);

Node.js

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

const createUnixSocketPool = async (config) => {
  const dbSocketPath = process.env.DB_SOCKET_PATH || "/cloudsql"

  // Establish a connection to the database
  return await mysql.createPool({
    user: process.env.DB_USER, // e.g. 'my-db-user'
    password: process.env.DB_PASS, // e.g. 'my-db-password'
    database: process.env.DB_NAME, // e.g. 'my-database'
    // If connecting via unix domain socket, specify the path
    socketPath: `${dbSocketPath}/${process.env.INSTANCE_CONNECTION_NAME}`,
    // Specify additional properties here.
    ...config
  });
}

Go

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

var (
	dbUser                 = mustGetenv("DB_USER")
	dbPwd                  = mustGetenv("DB_PASS")
	instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME")
	dbName                 = mustGetenv("DB_NAME")
)

var dbURI string
dbURI = fmt.Sprintf("%s:%s@unix(/cloudsql/%s)/%s", dbUser, dbPwd, instanceConnectionName, dbName)

// dbPool is the pool of database connections.
dbPool, err := sql.Open("mysql", dbURI)
if err != nil {
	return nil, fmt.Errorf("sql.Open: %v", err)
}

// ...

return dbPool, nil

专用 IP

使用 TCP 进行连接

使用您实例的专用 IP 地址和端口 3306 直接连接。

最佳做法和其他信息

在本地测试应用时,您可以使用 Cloud SQL 代理。如需了解详细说明,请参阅《快速入门:使用代理进行本地测试》

连接池

与底层数据库的连接可能会被数据库服务器本身或 Cloud Functions 的底层基础架构断开。我们建议您使用支持连接池的客户端库,因为连接池可自动重新连接断开的客户端连接。此外,我们建议您使用全局范围的连接池,以便提高函数在后续调用中重复使用同一连接的可能性,并在逐出(自动缩减)实例时自然关闭连接。如需查看有关如何使用连接池的详细示例,请参阅管理数据库连接

连接限制

Cloud SQL 对并发连接数量设定了上限,这些限制可能因所选的数据库引擎而有所不同(请参阅 Cloud SQL 配额和限制)。使用连接池时,请务必将连接数上限设置为 1。
  1. 在 Cloud Functions 中,每个实例只能并发执行 1 次。您永远不会遇到一个函数实例同时处理两个请求的情况。因此在大多数情况下,只需要一个数据库连接。
您应该尽可能仅为需要使用连接池的函数初始化连接池。如果部署的函数初始化它不需要的连接池,则可能会创建未使用的连接,这些连接数目将计入您的配额。如需详细了解如何在 Cloud Functions 中处理全局变量,请参阅提示与技巧。如需查看有关如何限制连接数的详细示例,请参阅管理数据库连接

API 配额限制

Cloud Functions 提供了一种使用 Cloud SQL 代理进行连接的机制,该代理使用 Cloud SQL Admin API。 API 配额限制适用于 Cloud SQL 代理。