カテゴリー「gcp」

MySQLあたりをよくさわっていたエンジニアにとって、

GCPのSpannerは非常に難しい。

難しいというより、MySQLの感覚でやると上手く行かないのです。

構文は割と似ていて、「`」なんかも使えるから、なおのこと油断しがちです。

銀の弾丸はないよね、という自戒を込めて、注意すべき点について書いておきます。

なお、「速くない」と表現していますが、同一ネットワーク内のMySQLのOLTPの場合と比較してとなります。

条件が変われば、MySQLもそこまでの速度はでないこともありますし、

分散の仕組みが入っていると事情は変わってくるので、その点は予めご了承ください。


●1回のクエリーのRTT(ラウンドトリップタイム)は速くない

MySQLだと、INDEXが聞いていれば(特に主キー)だと、同一ローカルネットワーク内であれば、

0.01秒もかからずデータが取得できますが、

Spannerだと0.01秒くらい平気でかかってしまいます。

そのため、アプリケーションが非同期IOをサポートしているなら、

非同期IOを使ったほうがアプリケーションのパフォーマンスは上がると思います。

とはいえ、1回のトランザクションで、クエリーの本数が多いとキツイので、

仕様でクエリー数を減らせるよう調整できればそれに越したことはないかと思います。

●Queryじゃない、Prepared Statementが大事

MySQLだと、アプリケーションでサーバサイドPrepared Statementをサポートしているライブラリって少ないはず。

「prepare」とか「bind」とかのメソッドがあっても、実はサーバに送るときはQueryになってたりします。

(いわゆるクライアントサイドPrepared Statementというやつですね)

でもMySQLだと、Queryでも全然問題ないほど、構文解析が速いので、

構文解析キャッシュの恩恵を受けられるPrepared Statementを使う必要性は低いのです。

※Prepared Statementを使うと、バイナリプロトコルになるという話もありますが、ここでは割愛。

しかし、Spannerでは、構文解析の負荷は高く、

Prepared Statementを使って、構文解析キャシュの恩恵を受けに行かないと、パフォーマンスがでません。

これは以下にも書いてあるとおりです。

https://cloud.google.com/spanner/docs/sql-best-practices?hl=ja

Queryだと、本当にびっくりするぐらいパフォーマンスでないです。

●1回のSELECTで効果的にデータを取得する

「INTERLEAVE」と「ARRAY STRUCT」が重要です。

「INTERLEAVE」で親と子のテーブルをできるだけ同じノードに閉じ込め、

「ARRAY STRUCT」でまとめてとってくるのがポイントです。

以下に書いてあるとおりです。

https://medium.com/google-cloud-jp/cloud-spanner-%E3%81%A7%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%AA%E3%83%BC%E3%83%96%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E9%AB%98%E9%80%9F%E3%81%AB%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B-2a955b061d3

とはいえ、ARRAY STRUCTでとってきたデータを、オブジェクトにマッピングするのは結構難しいです。

GO言語なんかはライブラリレベルでサポートされているようですが、

他の言語では、自前で解析する必要があります。

上記3つが大きなポイントとなるかと思います。

それ以外にも注意すべきは、「Writeが速くない」ということでしょうか。

UPDATEやDELETEはある意味仕方ないですが、

BULK INSERTについては、UNNESTを上手く使うことで、パフォーマンス向上は可能かと思います。

UNNESTはWHERE INの文脈で使われることが多いかと思いますが、INSERTでも利用できるようです。

※すいません、自分がこれは試してないです。

PostgreSQLでサポートされているので、対応されているのでしょうか。。

他には最近リリースされたINSERT OR UPDATE構文なんかも使えるかもしれません。

ただし、INSERT OR UPDATEについては、ユニークキーがある場合の挙動について、

↓のドキュメントには記載されていません。

https://cloud.google.com/spanner/docs/reference/standard-sql/dml-syntax#insert-or-update

なので、ちょっと試してみました。

まず、こんなテーブルを作ります。

CREATE TABLE  UsersUnique
  ( Id STRING(255) NOT NULL,
    Name STRING(255) NOT NULL,
    Age INT64 NOT NULL,
    )
PRIMARY KEY  (Id);
  CREATE UNIQUE INDEX uk_UsersUnique_Name ON  UsersUnique(Name);

以下のようなデータを入れておきます。

Id  Name  Age
0123456789  Aさん  20
9876543210  Bさん  40 

次に、以下のようなINSERTを流します。

insert or update UsersUnique (Id, Name, Age) values ('0123456789', 'Bさん', 30);

流した結果、

Unique index violation on index uk_UsersUnique_Name at index key [B343201225343202223,9876543210]. It conflicts with row [9876543210] in table UsersUnique.

となりました。

つまり、主キーで置き換えようとしたが、ユニーク制約で引っ掛かった形となりました。

MySQLでは「replace into」といういわゆるUPSERTがあるのですが、

これを使うと、ユニーク制約で削除され、主キーが置き換えられます。

つまり、以下のような結果になります。

Id  Name  Age
0123456789  Bさん  30

DBMSによって、挙動は違いますが、ユニーク制約がある場合はUPSERTには注意を払いましょう。

あれこれ書いてきましたが、

Spannerは簡単にスケールアウト・スケールインできるのは、本当にすごいなと思いました。

とはいえ、やはり特性をよく知って使わないといけないなということは痛感しています。

(謝辞)

本件のSpanner検証にあたっては、ArmadaSuit さんに尽力いただきました。

ありがとうございました。

彼が作った、cgoによるMySQL/PostgreSQLのUDFは、非常に素晴らしいので、紹介させていただきます。

https://github.com/ArmadaSuit/udf-go

これは、新しいバージョンでのGO言語での書き方で、以前私が作っていたようなUDFより、

洗練されたものとなっています。

以上

投稿日時:2024年03月10日 00:12   カテゴリー:gcp, mariadb, mysql   [コメントがあればどうぞ]

Google Computer Cloud(以下、GCP)で、

グローバルロードバランサの背後にnginxを置く場合は、

keepaliveをしておこう。

 

(参考)

https://blog.percy.io/tuning-nginx-behind-google-cloud-platform-http-s-load-balancer-305982ddb340

 

これやっておかないと、結構502がでる。

ちなみに、650秒をkeepalive_timeoutにするなら、

ロードバランサのタイムアウトは600秒程度、つまり少し短めがよいとのこと。

 

実は、AWSのELBも同様。

 

とはいえ、結構な高負荷にならないと、本事象は目立ってこないので、

なかなか難しいところである。

 

以上

投稿日時:2018年04月09日 23:07   カテゴリー:gcp, nginx   [コメントがあればどうぞ]

Google Computer Engineにおいて、

いつの間にか、google-cloud-sdkのインストール方法に変更があった。

古いインスタンスと、新しいインスタンスで操作方法が異なってしまったので、

備忘録として残しておく

 

(古いインスタンス)

  • OS:CentOS Linux release 7.2.1511 (Core)
  • 構築日時:2016年3月ごろ

最初から、google-cloud-sdkがはいっており、

gcloudコマンド等が使えた。

そして、

# gcloud components update

が実行できた。

→ おそらく、これはマニュアルにある、install.shを実行したやつなのだろう。

 

(新しいインスタンス)

  • OS:CentOS Linux release 7.2.1511 (Core)
  • 構築日時:2016年12月ごろ

gcloudコマンドが最初から使えない代わりに、

yumでインストール可能となっていた。

このインストール方法だと、

# gcloud components update

が実行できなくなっていた。

→ いつの間にか、/etc/yum.repos.d/google-cloud.repoファイルに、

google-cloud-sdkのセクションが追加されていた。

 

というわけで、

古いインスタンスの/etc/yum.repos.d/google-cloud.repoファイルを以下のように変更。

[google-cloud-compute]
name=Google Cloud Compute
baseurl=https://packages.cloud.google.com/yum/repos/google-cloud-compute-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

[google-cloud-sdk]
name=Google Cloud SDK
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

 

そして、

# yum install -y google-cloud-sdk

を実行し、最新のsdkをインストール。

 

・・・すれば行けるはず。

↑はまだ実行してないんだけどね。。

ひょっとしたら、古いgcloudを削除する必要ありそう。。

 

GCPは変更があっても、

マニュアルの反映が遅かったりして、ちょっとわかりづらいわ。。

stackdriverだって、2016年10月にGAになったのに、

日本語マニュアルを見ると未だにベータ版って記述残ってるし。。

このあたりしっかりやって欲しいわ。。

 

投稿日時:2016年12月11日 00:06   カテゴリー:gcp   [コメントがあればどうぞ]

ここ最近、インフラ寄りの話ばかりであるが、

GooglePlatformで使えるCloudCDNについて書いておく。

 

CloudCDNはawsのcloud frontなどとは違い、

ロードバランサーの一機能として利用できる。

特徴としては、

ロードバランサーと同一ドメインで利用できるところである。

イメージ的には以下のようになる(実際は違いますけど。。)

 


    user <--> load balancer <--> cloud cdn <--> vm instance 

 

この構成のよいところは、オリジンであるVMインスタンス(awsでいえばEC2)に置いてあるキャッシュさせたいコンテンツを、

ロードバランサーと同じドメインで取得できるところである。

そのため、VMインスタンスに画像等を丸々配備できるため、開発者がインフラを意識する必要がなくなるということだ。

 

これに対し、他CDNの場合、キャッシュさせたいコンテンツを他ドメインから取得させるよう、

HTMLをコーディングする必要がある。

しかし、CloudCDNなら、それを意識する必要はない。

これは開発者から見ると非常に大きな利点である。

(awsのcloud frontのL7機能でキャッシュの有無を調整することは可能だが、キャッシュさせないコンテンツでも瞬間的にはキャッシュされるので、

一意URLによるGETなどはあらかじめ注意して開発する必要がある)

 

ただし、HTTP/1.1の場合、同一ドメインから同時にアクセスできるURL数というのはブラウザで制御しているため、

実際には様々なドメインから取得させた方がユーザへの体感速度の向上が図れるのは周知の事実である。

(HTTP/2ではこの問題も多少はマシになるとは期待してますが、、)

 

ただ、CloudCDNの残念なところは、現状キャッシュされているものの情報や、ヒット率等の統計が取れないところである。

しかし、何度も書いたように、開発者(もっといえばコンテンツ開発者)にありがたいインフラ構成というのは、特筆すべき点かと思われる。

 

以上

投稿日時:2016年10月17日 00:54   カテゴリー:cdn, gcp   [コメントがあればどうぞ]

GCPからのメール送信というと、

  • 外部サービス(SendGrid)に接続してのSMTP通信
  • GoogleAppsへのSMTPリレー

などがよく出てくるが、

SendGridを使うほどではなく、

たまにアラートなどで使いたい場合に、

上記どちらの方法もやりにくい。

 

実際にrubyスクリプトから、SMTP接続してメール送信をするケースにおいて、

どうもSMTPリレーが上手くいかなかった(Postfixでちゃんとリレー設定しないと難しいのかな?)ので、

アプリパスワードを発行して、GoogleAppsへSMTP接続すれば、無事送信できることが確認できた。

詳しくは以下。

https://support.google.com/mail/answer/185833?hl=ja

 

最近はwebhookなども通知に使われるが、

やはり入れておきたいメール通知。

 

以上

投稿日時:2016年08月15日 23:14   カテゴリー:gcp   [コメントがあればどうぞ]

GCPとAWSで、拠点(リージョン)間の通信速度を簡単に図ってみた。

正確ではないし、3回程度しか実施していないので、その点は考慮ください。

 

■ComputerEngineのインスタンス(ASIA)から(AMERICA東部)への230MBのSCP

24秒

 

■EC2のインスタンス(TOKYO)から(AMERICA東部)への230MBのSCP

23秒

 

ほとんど同じ。

GCPはネットワークの強さをうたっているが、AWSと変わらないケースもある。

 

GCPの場合、ローカルネットワーク上で、異なるリージョンのインスタンスをまとめられるので、

データベースなどを複数リージョンで準同期レプリケーションできるとよいと思っていたが、

その目論見は成立しそうにないことがわかった。

 

ただし、GCPはグローバルロードバランサーとか、CloudStorageがめちゃくちゃ優秀だから、

実際にサービスとしてユーザの体感速度的なものは、広域範囲で考えればAWSより優秀なのではないか。

 

投稿日時:2016年05月27日 23:47   カテゴリー:aws, gcp   [コメントがあればどうぞ]

GCP(Google Cloud Platform)における、

Google Cloud Storage(以下、GCS)がすごい。

 

AWSでいうところのS3にあたるものですが、

バケット間同期が、

25,000ファイル、8GBを転送(同期)するのに、約5分。

驚異的。。

 

JAVAの並列処理(4CORE)で、

S3に同じ量をアップするのに、8分だったから、

ちょっと負けた気分。

 

なお、GCSはgsutilというツールを使うのがよい。

JAVAなどはSDKが出ているが、とてもめんどくさい。

 

gsutilは、gcloudの認証に影響を受けるようなので、

予めサービスアカウントを発行して、gcloudでの認証処理をしておくのがよい。

 

追記

ちなみに、上記の5分という数字は、

バケットのリージョンが異なっていても、同じでも変わらない。

つまり、AsiaからAmericaのバケット間転送でも超高速。

驚異的。。。

 

投稿日時:2016年05月27日 23:30   カテゴリー:gcp   [コメントがあればどうぞ]