이 페이지에서는 Cloud SQL 데이터베이스 연결을 효과적으로 사용하는 애플리케이션을 만드는 데 도움이 되는 권장사항과 언어별 코드 샘플을 제공합니다.
이 샘플은 GitHub에서 제공하는 완전한 웹 애플리케이션에서 발췌하였습니다. 자세히 알아보기
Cloud SQL에 연결된 샘플 웹 애플리케이션을 실행하는 방법에 대한 단계별 안내를 확인하려면 사용 중인 환경에 해당하는 링크로 이동하세요.
- 빠른 시작: 로컬 컴퓨터에서 연결
- 빠른 시작: Compute Engine에서 연결
- 빠른 시작: Cloud Run에서 연결
- 빠른 시작: Cloud Functions에서 연결
- 빠른 시작: Google Kubernetes Engine에서 연결
연결 풀
연결 풀이란 연결 지연 시간 및 성능의 개선을 위해 공유 및 재사용되는 데이터베이스 연결의 캐시를 의미합니다. 애플리케이션에서 데이터베이스 연결이 필요하면 풀에서 임시로 하나를 빌려오고 연결이 필요 없어지면 연결을 풀에 반환합니다. 이 연결은 다음에 애플리케이션에서 데이터베이스 연결이 필요할 때 재사용될 수 있습니다.
TCP로 연결
Python
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
import os
import sqlalchemy
def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
"""Initializes a TCP connection pool for a Cloud SQL instance of MySQL."""
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
db_host = os.environ[
"INSTANCE_HOST"
] # e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
db_user = os.environ["DB_USER"] # e.g. 'my-db-user'
db_pass = os.environ["DB_PASS"] # e.g. 'my-db-password'
db_name = os.environ["DB_NAME"] # e.g. 'my-database'
db_port = os.environ["DB_PORT"] # e.g. 3306
pool = sqlalchemy.create_engine(
# Equivalent URL:
# mysql+pymysql://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
sqlalchemy.engine.url.URL.create(
drivername="mysql+pymysql",
username=db_user,
password=db_pass,
host=db_host,
port=db_port,
database=db_name,
),
# ...
)
return pool
자바
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
참고:
- INSTANCE_CONNECTION_NAME은 <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>으로 표시되어야 합니다.
- 인수 ipTypes=PRIVATE을 사용하면 SocketFactory가 인스턴스의 연결된 비공개 IP와 강제로 연결됩니다.
- pom.xml 파일에 대한 JDBC 소켓 팩토리 버전 요구사항은 여기를 참조하세요.
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
public class TcpConnectionPoolFactory extends ConnectionPoolFactory {
// Saving credentials in environment variables is convenient, but not secure - consider a more
// secure solution such as https://cloud.google.com/secret-manager/ to help keep secrets safe.
private static final String DB_USER = System.getenv("DB_USER");
private static final String DB_PASS = System.getenv("DB_PASS");
private static final String DB_NAME = System.getenv("DB_NAME");
private static final String INSTANCE_HOST = System.getenv("INSTANCE_HOST");
private static final String DB_PORT = System.getenv("DB_PORT");
public static DataSource createConnectionPool() {
// The configuration object specifies behaviors for the connection pool.
HikariConfig config = new HikariConfig();
// The following URL is equivalent to setting the config options below:
// jdbc:mysql://<INSTANCE_HOST>:<DB_PORT>/<DB_NAME>?user=<DB_USER>&password=<DB_PASS>
// See the link below for more info on building a JDBC URL for the Cloud SQL JDBC Socket Factory
// https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory#creating-the-jdbc-url
// Configure which instance and what database user to connect with.
config.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s", INSTANCE_HOST, DB_PORT, DB_NAME));
config.setUsername(DB_USER); // e.g. "root", "mysql"
config.setPassword(DB_PASS); // e.g. "my-password"
// ... Specify additional connection properties here.
// ...
// Initialize the connection pool using the configuration object.
return new HikariDataSource(config);
}
}
Node.js
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
const mysql = require('promise-mysql');
const fs = require('fs');
// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of MySQL.
const createTcpPool = async config => {
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
const dbConfig = {
host: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
port: process.env.DB_PORT, // e.g. '3306'
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'
// ... Specify additional properties here.
...config,
};
// Establish a connection to the database.
return mysql.createPool(dbConfig);
};
Go
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
package cloudsql
import (
"crypto/tls"
"crypto/x509"
"database/sql"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"github.com/go-sql-driver/mysql"
)
// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of MySQL.
func connectTCPSocket() (*sql.DB, error) {
mustGetenv := func(k string) string {
v := os.Getenv(k)
if v == "" {
log.Fatalf("Fatal Error in connect_tcp.go: %s environment variable not set.", k)
}
return v
}
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
var (
dbUser = mustGetenv("DB_USER") // e.g. 'my-db-user'
dbPwd = mustGetenv("DB_PASS") // e.g. 'my-db-password'
dbName = mustGetenv("DB_NAME") // e.g. 'my-database'
dbPort = mustGetenv("DB_PORT") // e.g. '3306'
dbTCPHost = mustGetenv("INSTANCE_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
)
dbURI := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true",
dbUser, dbPwd, dbTCPHost, dbPort, dbName)
// dbPool is the pool of database connections.
dbPool, err := sql.Open("mysql", dbURI)
if err != nil {
return nil, fmt.Errorf("sql.Open: %w", err)
}
// ...
return dbPool, nil
}
C#
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
using MySql.Data.MySqlClient;
using System;
namespace CloudSql
{
public class MySqlTcp
{
public static MySqlConnectionStringBuilder NewMysqlTCPConnectionString()
{
// Equivalent connection string:
// "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<INSTANCE_HOST>;Database=<DB_NAME>;"
var connectionString = new MySqlConnectionStringBuilder()
{
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
Server = Environment.GetEnvironmentVariable("INSTANCE_HOST"), // e.g. '127.0.0.1'
// Set Host to 'cloudsql' when deploying to App Engine Flexible environment
UserID = Environment.GetEnvironmentVariable("DB_USER"), // e.g. 'my-db-user'
Password = Environment.GetEnvironmentVariable("DB_PASS"), // e.g. 'my-db-password'
Database = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'
// The Cloud SQL proxy provides encryption between the proxy and instance.
SslMode = MySqlSslMode.Disabled,
};
connectionString.Pooling = true;
// Specify additional properties here.
return connectionString;
}
}
}
Ruby
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
tcp: &tcp
adapter: mysql2
# Configure additional properties here
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
username: <%= ENV["DB_USER"] %> # e.g. "my-database-user"
password: <%= ENV["DB_PASS"] %> # e.g. "my-database-password"
database: <%= ENV.fetch("DB_NAME") { "vote_development" } %>
host: "<%= ENV.fetch("INSTANCE_HOST") { "127.0.0.1" }%>" # '172.17.0.1' if deployed to GAE Flex
port: <%= ENV.fetch("DB_PORT") { 3306 }%>
PHP
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
namespace Google\Cloud\Samples\CloudSQL\MySQL;
use PDO;
use PDOException;
use RuntimeException;
use TypeError;
class DatabaseTcp
{
public static function initTcpDatabaseConnection(): PDO
{
try {
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
$username = getenv('DB_USER'); // e.g. 'your_db_user'
$password = getenv('DB_PASS'); // e.g. 'your_db_password'
$dbName = getenv('DB_NAME'); // e.g. 'your_db_name'
$instanceHost = getenv('INSTANCE_HOST'); // e.g. '127.0.0.1' ('172.17.0.1' for GAE Flex)
// Connect using TCP
$dsn = sprintf('mysql:dbname=%s;host=%s', $dbName, $instanceHost);
// Connect to the database
$conn = new PDO(
$dsn,
$username,
$password,
# ...
);
} catch (TypeError $e) {
throw new RuntimeException(
sprintf(
'Invalid or missing configuration! Make sure you have set ' .
'$username, $password, $dbName, and $instanceHost (for TCP mode). ' .
'The PHP error was %s',
$e->getMessage()
),
$e->getCode(),
$e
);
} catch (PDOException $e) {
throw new RuntimeException(
sprintf(
'Could not connect to the Cloud SQL Database. Check that ' .
'your username and password are correct, that the Cloud SQL ' .
'proxy is running, and that the database exists and is ready ' .
'for use. For more assistance, refer to %s. The PDO error was %s',
'https://cloud.google.com/sql/docs/mysql/connect-external-app',
$e->getMessage()
),
$e->getCode(),
$e
);
}
return $conn;
}
}
Unix 소켓으로 연결
Python
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
import os
import sqlalchemy
def connect_unix_socket() -> sqlalchemy.engine.base.Engine:
"""Initializes a Unix socket connection pool for a Cloud SQL instance of MySQL."""
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
db_user = os.environ["DB_USER"] # e.g. 'my-database-user'
db_pass = os.environ["DB_PASS"] # e.g. 'my-database-password'
db_name = os.environ["DB_NAME"] # e.g. 'my-database'
unix_socket_path = os.environ[
"INSTANCE_UNIX_SOCKET"
] # e.g. '/cloudsql/project:region:instance'
pool = sqlalchemy.create_engine(
# Equivalent URL:
# mysql+pymysql://<db_user>:<db_pass>@/<db_name>?unix_socket=<socket_path>/<cloud_sql_instance_name>
sqlalchemy.engine.url.URL.create(
drivername="mysql+pymysql",
username=db_user,
password=db_pass,
database=db_name,
query={"unix_socket": unix_socket_path},
),
# ...
)
return pool
자바
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
public class ConnectorConnectionPoolFactory extends ConnectionPoolFactory {
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
private static final String INSTANCE_CONNECTION_NAME =
System.getenv("INSTANCE_CONNECTION_NAME");
private static final String INSTANCE_UNIX_SOCKET = System.getenv("INSTANCE_UNIX_SOCKET");
private static final String DB_USER = System.getenv("DB_USER");
private static final String DB_PASS = System.getenv("DB_PASS");
private static final String DB_NAME = System.getenv("DB_NAME");
public static DataSource createConnectionPool() {
// The configuration object specifies behaviors for the connection pool.
HikariConfig config = new HikariConfig();
// The following URL is equivalent to setting the config options below:
// jdbc:mysql:///<DB_NAME>?cloudSqlInstance=<INSTANCE_CONNECTION_NAME>&
// socketFactory=com.google.cloud.sql.mysql.SocketFactory&user=<DB_USER>&password=<DB_PASS>
// See the link below for more info on building a JDBC URL for the Cloud SQL JDBC Socket Factory
// https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory#creating-the-jdbc-url
// 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", "mysql"
config.setPassword(DB_PASS); // e.g. "my-password"
config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
config.addDataSourceProperty("cloudSqlInstance", INSTANCE_CONNECTION_NAME);
// Unix sockets are not natively supported in Java, so it is necessary to use the Cloud SQL
// Java Connector to connect. When setting INSTANCE_UNIX_SOCKET, the connector will
// call an external package that will enable Unix socket connections.
// Note: For Java users, the Cloud SQL Java Connector can provide authenticated connections
// which is usually preferable to using the Cloud SQL Proxy with Unix sockets.
// See https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory for details.
if (INSTANCE_UNIX_SOCKET != null) {
config.addDataSourceProperty("unixSocketPath", INSTANCE_UNIX_SOCKET);
}
// ... Specify additional connection properties here.
// ...
// Initialize the connection pool using the configuration object.
return new HikariDataSource(config);
}
}
Node.js
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
const mysql = require('promise-mysql');
// createUnixSocketPool initializes a Unix socket connection pool for
// a Cloud SQL instance of MySQL.
const createUnixSocketPool = async config => {
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
return 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'
socketPath: process.env.INSTANCE_UNIX_SOCKET, // e.g. '/cloudsql/project:region:instance'
// Specify additional properties here.
...config,
});
};
C#
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
using MySql.Data.MySqlClient;
using System;
namespace CloudSql
{
public class MySqlUnix
{
public static MySqlConnectionStringBuilder NewMysqlUnixSocketConnectionString()
{
// Equivalent connection string:
// "Server=<INSTANCE_UNIX_SOCKET>;Uid=<DB_USER>;Pwd=<DB_PASS>;Database=<DB_NAME>;Protocol=unix"
var connectionString = new MySqlConnectionStringBuilder()
{
// The Cloud SQL proxy provides encryption between the proxy and instance.
SslMode = MySqlSslMode.Disabled,
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
Server = Environment.GetEnvironmentVariable("INSTANCE_UNIX_SOCKET"), // e.g. '/cloudsql/project:region:instance'
UserID = Environment.GetEnvironmentVariable("DB_USER"), // e.g. 'my-db-user
Password = Environment.GetEnvironmentVariable("DB_PASS"), // e.g. 'my-db-password'
Database = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'
ConnectionProtocol = MySqlConnectionProtocol.UnixSocket
};
connectionString.Pooling = true;
// Specify additional properties here.
return connectionString;
}
}
}
Go
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
package cloudsql
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/go-sql-driver/mysql"
)
// connectUnixSocket initializes a Unix socket connection pool for
// a Cloud SQL instance of MySQL.
func connectUnixSocket() (*sql.DB, error) {
mustGetenv := func(k string) string {
v := os.Getenv(k)
if v == "" {
log.Fatalf("Fatal Error in connect_unix.go: %s environment variable not set.", k)
}
return v
}
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
var (
dbUser = mustGetenv("DB_USER") // e.g. 'my-db-user'
dbPwd = mustGetenv("DB_PASS") // e.g. 'my-db-password'
dbName = mustGetenv("DB_NAME") // e.g. 'my-database'
unixSocketPath = mustGetenv("INSTANCE_UNIX_SOCKET") // e.g. '/cloudsql/project:region:instance'
)
dbURI := fmt.Sprintf("%s:%s@unix(%s)/%s?parseTime=true",
dbUser, dbPwd, unixSocketPath, dbName)
// dbPool is the pool of database connections.
dbPool, err := sql.Open("mysql", dbURI)
if err != nil {
return nil, fmt.Errorf("sql.Open: %w", err)
}
// ...
return dbPool, nil
}
Ruby
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
unix: &unix
adapter: mysql2
# Configure additional properties here.
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
username: <%= ENV["DB_USER"] %> # e.g. "my-database-user"
password: <%= ENV["DB_PASS"] %> # e.g. "my-database-password"
database: <%= ENV.fetch("DB_NAME") { "vote_development" } %>
# Specify the Unix socket path as host
socket: "<%= ENV["INSTANCE_UNIX_SOCKET"] %>"
PHP
웹 애플리케이션의 컨텍스트에서 이 스니펫을 보려면 GitHub의 README를 참조하세요.
namespace Google\Cloud\Samples\CloudSQL\MySQL;
use PDO;
use PDOException;
use RuntimeException;
use TypeError;
class DatabaseUnix
{
public static function initUnixDatabaseConnection(): PDO
{
try {
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
$username = getenv('DB_USER'); // e.g. 'your_db_user'
$password = getenv('DB_PASS'); // e.g. 'your_db_password'
$dbName = getenv('DB_NAME'); // e.g. 'your_db_name'
$instanceUnixSocket = getenv('INSTANCE_UNIX_SOCKET'); // e.g. '/cloudsql/project:region:instance'
// Connect using UNIX sockets
$dsn = sprintf(
'mysql:dbname=%s;unix_socket=%s',
$dbName,
$instanceUnixSocket
);
// Connect to the database.
$conn = new PDO(
$dsn,
$username,
$password,
# ...
);
} catch (TypeError $e) {
throw new RuntimeException(
sprintf(
'Invalid or missing configuration! Make sure you have set ' .
'$username, $password, $dbName, ' .
'and $instanceUnixSocket (for UNIX socket mode). ' .
'The PHP error was %s',
$e->getMessage()
),
(int) $e->getCode(),
$e
);
} catch (PDOException $e) {
throw new RuntimeException(
sprintf(
'Could not connect to the Cloud SQL Database. Check that ' .
'your username and password are correct, that the Cloud SQL ' .
'proxy is running, and that the database exists and is ready ' .
'for use. For more assistance, refer to %s. The PDO error was %s',
'https://cloud.google.com/sql/docs/mysql/connect-external-app',
$e->getMessage()
),
(int) $e->getCode(),
$e
);
}
return $conn;
}
}
연결 열기 및 닫기
연결 풀을 사용할 때는 연결을 제대로 열고 닫아야 합니다. 그래야 사용을 마쳤을 때 항상 연결이 풀로 반환됩니다. 반환되지 않거나 '유출'된 연결은 재사용되지 않으므로 리소스가 낭비되고 애플리케이션에서 성능 병목 현상이 발생할 수 있습니다.
Python
# Preparing a statement before hand can help protect against injections.
stmt = sqlalchemy.text(
"INSERT INTO votes (time_cast, candidate) VALUES (:time_cast, :candidate)"
)
try:
# Using a with statement ensures that the connection is always released
# back into the pool at the end of statement (even if an error occurs)
with db.connect() as conn:
conn.execute(stmt, parameters={"time_cast": time_cast, "candidate": team})
conn.commit()
except Exception as e:
# If something goes wrong, handle the error in this section. This might
# involve retrying or adjusting parameters depending on the situation.
# ...
자바
// Using a try-with-resources statement ensures that the connection is always released back
// into the pool at the end of the statement (even if an error occurs)
try (Connection conn = pool.getConnection()) {
// PreparedStatements can be more efficient and project against injections.
String stmt = "INSERT INTO votes (time_cast, candidate) VALUES (?, ?);";
try (PreparedStatement voteStmt = conn.prepareStatement(stmt);) {
voteStmt.setTimestamp(1, now);
voteStmt.setString(2, team);
// Finally, execute the statement. If it fails, an error will be thrown.
voteStmt.execute();
}
} catch (SQLException ex) {
// If something goes wrong, handle the error in this section. This might involve retrying or
// adjusting parameters depending on the situation.
// ...
}
Node.js
try {
const stmt = 'INSERT INTO votes (time_cast, candidate) VALUES (?, ?)';
// Pool.query automatically checks out, uses, and releases a connection
// back into the pool, ensuring it is always returned successfully.
await pool.query(stmt, [timestamp, team]);
} catch (err) {
// If something goes wrong, handle the error in this section. This might
// involve retrying or adjusting parameters depending on the situation.
// ...
}
C#
using MySql.Data.MySqlClient;
using System;
namespace CloudSql
{
public class MySqlTcp
{
public static MySqlConnectionStringBuilder NewMysqlTCPConnectionString()
{
// Equivalent connection string:
// "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<INSTANCE_HOST>;Database=<DB_NAME>;"
var connectionString = new MySqlConnectionStringBuilder()
{
// Note: Saving credentials in environment variables is convenient, but not
// secure - consider a more secure solution such as
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
// keep secrets safe.
Server = Environment.GetEnvironmentVariable("INSTANCE_HOST"), // e.g. '127.0.0.1'
// Set Host to 'cloudsql' when deploying to App Engine Flexible environment
UserID = Environment.GetEnvironmentVariable("DB_USER"), // e.g. 'my-db-user'
Password = Environment.GetEnvironmentVariable("DB_PASS"), // e.g. 'my-db-password'
Database = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'
// The Cloud SQL proxy provides encryption between the proxy and instance.
SslMode = MySqlSslMode.Disabled,
};
connectionString.Pooling = true;
// Specify additional properties here.
return connectionString;
}
}
}
Go
insertVote := "INSERT INTO votes(candidate, created_at) VALUES(?, NOW())"
_, err := db.Exec(insertVote, team)
Ruby
@vote = Vote.new candidate: candidate
# ActiveRecord creates and executes your SQL and automatically
# handles the opening and closing of the database connection.
if @vote.save
render json: "Vote successfully cast for \"#{@vote.candidate}\" at #{@vote.time_cast} PST!"
else
render json: @vote.errors, status: :unprocessable_entity
end
PHP
// Use prepared statements to guard against SQL injection.
$sql = 'INSERT INTO votes (time_cast, candidate) VALUES (NOW(), :voteValue)';
try {
$statement = $conn->prepare($sql);
$statement->bindParam('voteValue', $value);
$res = $statement->execute();
} catch (PDOException $e) {
throw new RuntimeException(
'Could not insert vote into database. The PDO exception was ' .
$e->getMessage(),
$e->getCode(),
$e
);
}
연결 수
모든 데이터베이스 연결은 클라이언트 및 서버 측 리소스를 사용합니다. 게다가 Cloud SQL에서는 초과하면 안 되는 전체 연결 한도를 부과합니다. 연결을 적게 만들어 사용하면 오버헤드를 줄이고 연결 한도를 유지하는 데 도움이 됩니다.
Python
# Pool size is the maximum number of permanent connections to keep.
pool_size=5,
# Temporarily exceeds the set pool_size if no connections are available.
max_overflow=2,
# The total number of concurrent connections for your application will be
# a total of pool_size and max_overflow.
자바
// maximumPoolSize limits the total number of concurrent connections this pool will keep. Ideal
// values for this setting are highly variable on app design, infrastructure, and database.
config.setMaximumPoolSize(5);
// minimumIdle is the minimum number of idle connections Hikari maintains in the pool.
// Additional connections will be established to meet this value unless the pool is full.
config.setMinimumIdle(5);
Node.js
// 'connectionLimit' is the maximum number of connections the pool is allowed
// to keep at once.
connectionLimit: 5,
C#
// MaximumPoolSize sets maximum number of connections allowed in the pool.
connectionString.MaximumPoolSize = 5;
// MinimumPoolSize sets the minimum number of connections in the pool.
connectionString.MinimumPoolSize = 0;
Go
// Set maximum number of connections in idle connection pool.
db.SetMaxIdleConns(5)
// Set maximum number of open connections to the database.
db.SetMaxOpenConns(7)
Ruby
# 'pool' is the maximum number of permanent connections to keep.
pool: 5
PHP
PDO는 연결 한도를 구성하는 기능을 현재 제공하지 않습니다.
지수 백오프
애플리케이션에서 데이터베이스 연결을 시도하지만 성공하지 못할 경우 데이터베이스를 일시적으로 사용하지 못할 수 있습니다. 이 경우 반복 연결 요청을 보내면 리소스가 낭비됩니다. 데이터베이스에 다시 액세스할 수 있도록 하려면 추가 연결 요청을 보내기 전에 기다리는 것이 좋습니다. 지수 백오프 또는 기타 지연 메커니즘을 사용하여 이 목표를 달성할 수 있습니다.
이 재시도는 처음 연결하거나 풀에서 처음 연결할 때만 의미가 있습니다. 트랜잭션 도중에 오류가 발생하면 애플리케이션에서 트랜잭션 시작부터 재시도해야 합니다. 따라서 풀이 올바르게 구성되어 있어도 연결이 끊어지면 애플리케이션에 오류가 표시될 수 있습니다.
Python
# SQLAlchemy automatically uses delays between failed connection attempts,
# but provides no arguments for configuration.
자바
// Hikari automatically delays between failed connection attempts, eventually reaching a
// maximum delay of `connectionTimeout / 2` between attempts.
Node.js
// The mysql module automatically uses exponential delays between failed
// connection attempts.
C#
Policy
.Handle<MySqlException>()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(5)
})
.Execute(() => connection.Open());
Go
database/sql 패키지는 지수 백오프를 구성하는 기능을 현재 제공하지 않습니다.
Ruby
# ActiveRecord automatically uses delays between failed connection attempts,
# but provides no arguments for configuration.
PHP
PDO는 지수 백오프를 구성하는 기능을 현재 제공하지 않습니다.
연결 시간 초과
연결 시도가 성공하지 못하는 데에는 여러 가지 이유가 있습니다. 네트워크 통신이 항상 보장되는 것은 아니며 데이터베이스가 일시적으로 응답하지 못할 수도 있습니다. 끊겼거나 실패한 연결을 애플리케이션에서 적절하게 처리해야 합니다.
Python
# 'pool_timeout' is the maximum number of seconds to wait when retrieving a
# new connection from the pool. After the specified amount of time, an
# exception will be thrown.
pool_timeout=30, # 30 seconds
자바
// setConnectionTimeout is the maximum number of milliseconds to wait for a connection checkout.
// Any attempt to retrieve a connection from this pool that exceeds the set limit will throw an
// SQLException.
config.setConnectionTimeout(10000); // 10 seconds
// idleTimeout is the maximum amount of time a connection can sit in the pool. Connections that
// sit idle for this many milliseconds are retried if minimumIdle is exceeded.
config.setIdleTimeout(600000); // 10 minutes
Node.js
// 'connectTimeout' is the maximum number of milliseconds before a timeout
// occurs during the initial connection to the database.
connectTimeout: 10000, // 10 seconds
// 'acquireTimeout' is the maximum number of milliseconds to wait when
// checking out a connection from the pool before a timeout error occurs.
acquireTimeout: 10000, // 10 seconds
// 'waitForConnections' determines the pool's action when no connections are
// free. If true, the request will queued and a connection will be presented
// when ready. If false, the pool will call back with an error.
waitForConnections: true, // Default: true
// 'queueLimit' is the maximum number of requests for connections the pool
// will queue at once before returning an error. If 0, there is no limit.
queueLimit: 0, // Default: 0
C#
// ConnectionTimeout sets the time to wait (in seconds) while
// trying to establish a connection before terminating the attempt.
connectionString.ConnectionTimeout = 15;
Go
database/sql 패키지는 연결 제한 시간을 구성하는 기능을 현재 제공하지 않습니다. 제한 시간은 드라이버 수준에서 구성됩니다.
Ruby
# 'timeout' is the maximum number of seconds to wait when retrieving a
# new connection from the pool. After the specified amount of time, an
# ActiveRecord::ConnectionTimeoutError will be raised.
timeout: 5000
PHP
// Here we set the connection timeout to five seconds and ask PDO to
// throw an exception if any errors occur.
[
PDO::ATTR_TIMEOUT => 5,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]
연결 종료
Cloud SQL에서 PROCESS
권한이 있는 사용자는 자신이 관리하지 않는 연결을 나열할 수 있습니다. MySQL 5.7.x에서는 사용자에게 SUPER
권한, MySQL 8.0.x에서는 사용자에게 CONNECTION_ADMIN
권한이 있어야 이러한 연결에 대해 KILL
문을 실행할 수 있습니다. KILL
문은 다른 mysql 사용자(Cloud SQL 관리 사용자 제외)의 연결을 종료합니다. 이러한 권한이 없는 사용자는 자신이 관리하는 연결만 나열하고 종료할 수 있습니다.
mysql 클라이언트를 사용하고 SHOW PROCESSLIST
명령어를 실행하여 인스턴스 연결을 나열할 수 있습니다. Id
를 사용하여 연결을 종료합니다.
예를 들면 다음과 같습니다.
mysql> SHOW PROCESSLIST;
mysql> KILL 6;
연결 기간
연결 수명을 제한하면 이탈한 연결이 누적되는 것을 막을 수 있습니다. 연결 수명은 연결 풀을 사용해 제한할 수 있습니다.
Python
# 'pool_recycle' is the maximum number of seconds a connection can persist.
# Connections that live longer than the specified amount of time will be
# re-established
pool_recycle=1800, # 30 minutes
자바
// maxLifetime is the maximum possible lifetime of a connection in the pool. Connections that
// live longer than this many milliseconds will be closed and reestablished between uses. This
// value should be several minutes shorter than the database's timeout value to avoid unexpected
// terminations.
config.setMaxLifetime(1800000); // 30 minutes
Node.js
'mysql' Node.js 라이브러리는 연결 기간을 제어할 수 있는 함수를 현재 제공하지 않습니다.
C#
// ConnectionLifeTime sets the lifetime of a pooled connection
// (in seconds) that a connection lives before it is destroyed
// and recreated. Connections that are returned to the pool are
// destroyed if it's been more than the number of seconds
// specified by ConnectionLifeTime since the connection was
// created. The default value is zero (0) which means the
// connection always returns to pool.
connectionString.ConnectionLifeTime = 1800; // 30 minutes
Go
// Set Maximum time (in seconds) that a connection can remain open.
db.SetConnMaxLifetime(1800 * time.Second)
Ruby
ActiveRecord는 연결 기간을 제어하는 기능을 현재 제공하지 않습니다.
PHP
PDO는 연결 기간을 제어하는 기능을 현재 제공하지 않습니다.
완전한 애플리케이션 보기
완전한 애플리케이션을 보려면 아래 링크를 클릭하세요.
Python
Python 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
자바
Java 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
Node.js
Node.js 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
C#
C# 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
Go
Go 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
Ruby
Ruby 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
PHP
PHP 프로그래밍 언어로 빌드된 완전한 애플리케이션을 확인하세요.
다음 단계
- 비공개 IP 자세히 알아보기
- Cloud SQL 및 App Engine의 할당량 및 한도 알아보기
- Cloud SQL 작업 권장사항 알아보기
- 외부 애플리케이션에서 연결에 대해 자세히 알아보기