GKEからCloud SQLに接続する2つの方法のレイテンシを調べてみた

Yuki Nagae
google-cloud-jp
Published in
13 min readSep 2, 2019

--

※本記事の内容および環境構築用のrepositoryは実用レベルの構成・実装ではなく、あくまでも「GKEからCloud SQLにつながった」+「接続方法によってレイテンシに差があるよね」というだけですのでご注意ください。また検証結果も参考値ですので、もし気になる方は自分で試してみることをオススメします(以下が環境構築用repoです)(`・ω・´)

TL;DR

  • GKEからCloud SQLに接続する方式は主にPrivate IPとCloud SQL Proxyがある
  • パフォーマンスを求めるならやはりPrivate IP接続
  • Public IPを使いたい場合にはCloud SQL Proxyを使う

結果

だいたい10〜15分程度検証しただけですが、当然Private IPの方が低レイテンシですね。Proxyの場合にはPublic IP経由(※regionはus-central1を使用。GKEおよびCloud SQLともに同一region)なのでもちろんPrivate IPよりもネットワーク的に遅くなります。そう考えると20msは割とよい方かもしれません。

  • Private IP: 平均7ms
  • Cloud SQL Proxy: 平均20ms
Private IP
Cloud SQL Proxy

ここからは再現手順などの具体的な内容です。

背景

GKEを使う際のデータベースは様々選択肢あるかもしれませんが、一番馴染み深いRDBをまず使ってみたくなると思います。GCPの中ではCloud SQLを使用することでMySQLもしくはPostgreSQLを選択することができます(※本記事ではMySQLを選んでいますが、PostgreSQLも同様の方法で接続できると思います)

公式ドキュメントによると、GKEからCloud SQLに接続する方式は主に以下の2つあります。

  • Private IP: 同一ネットワーク内のGKEクラスタから直接接続する
  • Cloud SQL Proxy: サイドカーのDockerイメージからプロキシ経由で接続

接続方式の使い分けに関してはドキュメントにある程度の方針が書いてあります。

Private IP is the easiest way to connect from Google Kubernetes Engine if your cluster meets the requirements.

To connect securely to Cloud SQL from Google Kubernetes Engine using a public IP address, you must use the Cloud SQL Proxy.

  • Private IP: もし要件が合うなら最も簡単な方法
  • Cloud SQL Proxy: Public IPを使用する場合にはCloud SQL Proxyを使う

簡単に言うと、Private IPとPublic IPのどちらで接続したいかという使い分けになります。ネットワーク遅延を考えると当然Private IPの方を使うべきですが、外部プロジェクトのデータベースにPublic IPで接続したい場合もあると思います。その場合には同一regionであればPublic IPを使用してもそこまで遅延しないかもしれません。

考えてみても答えがでないので実際に検証してみましょう。

Private IPとCloud SQL Proxyで接続した場合にどれくらいレイテンシに差があるか簡易的に検証してみます。

検証してみる

手動で環境を作るのは面倒なので、terraform + k8sで環境構築できるrepositoryを用意したのでこちらを使って説明します。

前提条件

  • プロジェクトの用意(既存のプロジェクトを利用することもできますが、試した後に削除しやすいので新規にプロジェクト作成をオススメします)
  • プロジェクトのbillingが有効であること
  • gcloud がインストール済みであること(※もし未インストールであれば Cloud SDK Quickstarts を参考にインストールしてください)
  • tfenv をインストール済みであること(※もし未インストールであれば、ここの手順を見てください。Macであれば brew install tfenv でインストールできます)
  • kubectl をインストール済みであること(※もし未インストール済みであれば、ここの手順を見てください。Macであれば brew install kubernetes-cli でインストールできます)

gcloudのアップデートをします

gcloud components update

作成済みのGCPプロジェクトの認証をします

gcloud auth application-default login
gcloud config set project [Your Project ID]

必要なサービスのenableをします

gcloud services enable container.googleapis.com
gcloud services enable sqladmin.googleapis.com
gcloud services enable servicenetworking.googleapis.com

検証環境を構築する

環境構築用のrepositoryをcloneします

git clone git@github.com:yukinagae/latency-comparison-of-cloud-sql-connection.git
cd latency-comparison-of-cloud-sql-connection

repository内のファイル内容は以下のとおりです。

[latency-comparison-of-cloud-sql-connection]
├── README.md: 環境の構築手順などを記載
├── flask-api
│ └── 検証用のPythonファイルなど
├── images
│ └── *.png: 検証結果のキャプチャ画像など
├── k8s
│ ├── k8s_private_ip.yaml: Private IP接続用のk8sファイル
│ └── k8s_proxy.yaml: Cloud SQL Proxy接続用のk8sファイル
└── terraform
└── *.tf: GKEやCloud SQLなどの環境構築用

DockerイメージをビルドしてCotainer Regisgryにプッシュする

cd flask-api
docker build -t gcr.io/[Your Project ID]/flask-api:latest .

gcloud auth configure-docker
docker push gcr.io/[Your Project ID]/flask-api:latest

APIサーバの実装は、以下のようにただ指定のホストに接続してすぐにcloseしているだけです(※実際の実装とは微妙に異なりますが、やっていることは一緒です)

@app.route('/readiness')
def readiness():
# 接続して
conn = pymysql.connect(user=DB_USER,
password=DB_PASS,
host=DB_HOST,
port=3306, db='mysql')
# クローズするだけ
conn.close()
return jsonify(status="OK", route="readiness")

Terraformのセットアップ

cd terraform
tfenv install
terraform init

terraform apply のあとに [Your Project ID] を入力し、最後に yes と入力するとCloud SQLおよびGKE周りのすべての環境がセットアップされます(※10分程度かかったりするので気長に待ちます)

$ terraform apply
var.project
Your Project ID
Enter a value:

Kubernetesのセットアップ

作成したGKEクラスタに接続します(`・ω・´)

gcloud container clusters get-credentials my-gke-cluster

Cloud SQLへの接続用のサービスアカウントをSecretとして作成する

この手順はCloud SQL Proxy用です。Public IP経由で接続する際に対象のCloud SQLインスタンスに触るための権限を与えたサービスアカウントを作成します。

  • SA NAME: サービスアカウント名
  • SA DISPLAY NAME: サービスアカウント表示名

SA_NAMESA_DISPLAY_NAME も任意の文字列でよいです(例えば、proxy-db等)

gcloud beta iam service-accounts create [SA NAME] \
--display-name "[SA DISPLAY NAME]" \
--project [Your Project ID]

gcloud projects add-iam-policy-binding [Your Project ID] \
--member serviceAccount:[SA NAME]@[Your Project ID].iam.gserviceaccount.com \
--role roles/cloudsql.admin

gcloud iam service-accounts keys create ./k8s/credentials.json \
--iam-account [SA NAME]@[YOur Project ID].iam.gserviceaccount.com

作成したcredentialのJSONファイルをKubernetesのSecretとして登録します。

cd k8s
kubectl create secret generic cloudsql-instance-credentials --from-file=./credentials.json

Kubernetesのデプロイ

k8s ディレクトリ内に以下のファイルがあります。

  • k8s_private_ip.yaml: Private IP接続用のk8sファイル
  • k8s_proxy.yaml: Cloud SQL Proxyse接続用のk8sファイル

上記各ファイル内の [Your Project ID] などの変数をご自身の環境に合わせて変更してください。

Private IP接続するk8sのデプロイする場合

kubectl apply -f k8s_private_ip.yaml

Cloud SQL Proxy接続するk8sのデプロイする場合

kubectl apply -f k8s_proxy.yaml

以下のようにpodが動作していれば成功です!

$ kubectl get podsNAME                    READY   STATUS    RESTARTS   AGE
test-5dc9b4d885-84vs5 1/1 Running 0 10s

最後にコネクション接続時のレイテンシをStackdriver Traceで見てみましょう(´∀`*)

ブラウザ上のGCPプロジェクトから[Stackdriver Trace] -> [Trace List] で実際にコネクション接続にどれくらい時間がかかっているかわかります。

自分でブラウザやcurlでアクセスしなくても k8s_private_ip.yamlk8s_proxy.yaml の以下の設定の periodSeconds で1秒に1アクセスで死活監視をしているのでそのアクセスでレイテンシの結果を確認できます。

readinessProbe:
httpGet:
path: /readiness # `/readiness` というパスで死活監視する
port: 5000
initialDelaySeconds: 3
periodSeconds: 1 # 1秒に1アクセスで死活監視

Stackdriver Traceでレイテンシ確認

当然Private IPの方が平均レイテンシは低い。Proxyの場合にはPublic IP経由(※ただし同一region内)なのでもちろんPrivate IPよりもネットワーク的に遅くなります。そう考えると20msは割とよい方かも(`・ω・´)

  • Private IP: 平均7ms
  • Cloud SQL Proxy: 平均20ms
Private IP
Cloud SQL Proxy

備考

  • Cloud SQL Proxy接続時には、Cloud SQLへの接続用のサービスアカウントのcredentialの期限が切れた際に再接続するので時間がかかってしまう(らしい)のでconnection poolingなどを検討する必要がある(かも)

参考資料

--

--