免責事項 †
概要 †
目次 †疑問 †
基本構成 †
用語 †
一般的なクラウドサービスの知識 †
サービス †Google App Engine †
Google Compute Engine (GCE) †GCEのホストマシンが死んだりメンテに入った場合(プリエンプティぶも含む) gcloud compute instances set-schedulingによって他のマシンに移したり、終了したりする。普通にサービす稼働させたいものをterminateでデプロイしない!(リファレンスのアドレス好き) https://cloud.google.com/sdk/gcloud/reference/compute/instances/set-scheduling managed instance-groupにはautohealingという機能がある。 文字通り、ヘルスチェックの結果によってインスタンスを自動修復(再作成)する機能だ。 負荷分散におけるヘルスチェックは、ロードバランサの振り先がHEALTHYかどうかを見るだけで、インスタンスの再作成は行わないが、マネージドインスタンスグループに適用されるヘルスチェックはインスタンスがUNHEALTHYになったら、削除して再作成する。 Datastore †
射影クエリ 要するにSQLのselectで一部だけ撮ってくるみたいなやつ エンティティの特定のプロパティだけにアクセスする場合は、射影クエリを使用します。射影クエリでは、エンティティ全体を取得する場合よりも低いレイテンシとコストで結果が返されます。 多くの場合、アプリケーションが必要とするのはエンティティのプロパティの一部分だけです。 射影クエリを使用すると、エンティティのプロパティの中で本当に必要なものだけをクエリできるため、エンティティ全体を取得する場合よりもレイテンシとコストを低く抑えられます。 射影クエリで指定するプロパティには、インデックスが必要です。 カーソル、制限、オフセット クエリに対して制限を指定することで、1 バッチで返される結果の最大数を制御できます。次の例では、最大で 5 つの Task エンティティを取得します。 これによって、100万人のうち200000-2000100人を撮ってくる、みたいな処理をオーバヘッドなしでおこなえる。課金もされない。 同じような機能をオフセットで行うことができるが、計算量的に悪いし遅いし課金される。Datastore モードのデータベースでは整数のオフセットをサポートしていますが、使用は避けてください。その代わりにカーソルを使用します。オフセットを使用するとスキップされたエンティティがアプリケーションに返されなくなりますが、そのようなエンティティも内部的には引き続き取得されています。スキップされたエンティティはクエリのレイテンシに影響するだけでなく、そのようなエンティティの取得に必要な読み取りオペレーションに対してアプリケーションが課金されます。このようなコストは、オフセットの代わりにカーソルを使用することですべて回避できます。 この記事がめちゃくちゃ面白い https://cloud.google.com/datastore/docs/articles/fast-and-reliable-ranking-in-datastore/#olog-n- これがめちゃくちゃよいエンティティグループの解説。結局のところ、やっぱり連結されていれば全部強整合性を保つため、1op/sの制限がかかってかなりヤバい。組織全体で木にするというよりは、本当に強性合成が必要だと思ったところだけを木にして連結させるという発想のほうが良い。安心(強整合性)は高いということを知れ。 https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/ 重要な問題の 1 つは、各エンティティ グループに更新(またはトランザクション)の回数を保管するようにシステムを設計する必要があることです。エンティティ グループごとに 1 秒間に 1 回の更新に制限されます[2]。 更新の回数がこの制限を超える必要がある場合、そのエンティティ グループはパフォーマンスのボトルネックとなるおそれがあります。 上記の例では、各組織内のどの人のレコードも更新が必要になる可能性があります。「ateam」内に 1,000 人含まれていて、それぞれの人物のいずれかのプロパティを 1 秒間に 1 回更新する可能性があるとします。その結果、このエンティティ グループでは 1 秒間に最大 1,000 回の更新がありえますが、これは更新の制限により実現できません。これにより、パフォーマンス要件を考慮した適切なエンティティ グループの設計の選択が重要であることがわかります。これは、結果整合性と強整合性の最適なバランスを求める際の課題の 1 つです。 読み取り、書き込み、削除には、単一のオペレーションではなくバッチ オペレーションを使用します。バッチ オペレーションでは、単一オペレーションと同じオーバーヘッドで複数のオペレーションが実行されるため効率的です。 トランザクションが失敗した場合はロールバックを試行してください。ロールバックを使用すると、トランザクション内で同じリソースを使用する別のリクエストの再試行レイテンシが最小限に抑えられます。ロールバック自体が失敗する可能性もあるため、ロールバックはベスト エフォート型の試行である点に注意してください。 可能な場合は、同期呼び出しではなく非同期呼び出しを使用します。非同期呼び出しでは、レイテンシの影響が最小限に抑えられます。たとえば、同期 lookup() の結果とクエリの結果に従ってレスポンスをレンダリングするアプリケーションについて考えてみましょう。lookup() とクエリにデータの依存関係がない場合、lookup() が完了するまでクエリの開始を同期的に待機する必要はありません。 Datastoreのデータ構造。森がある。全ての頂点には必ず、キーと呼ばれる数字もしくは文字列が書き込まれおり、何らかの色が塗られている。各頂点には、数字もしくは文字列の任意長のタプルが書かれている。以下のクエリを高速に行え。 (1) 色を一つ選んで、同じ色のものを全列挙する (2) 頂点を一つ選んで、その頂点を根とする部分木に含まれる頂点を全列挙する https://cloud.google.com/appengine/docs/standard/python/datastore/transactions Databaseでキーをランダムではなく文字列で管理している場合、同じ文字列 ID を持つエンティティを別のユーザーが作成または更新しようとする状況を処理するには、前の例と同様、ここでもトランザクションが必要です。トランザクションを使用しない場合は、エンティティがまだ存在していない時点で 2 人のユーザーが同時にこれを作成しようとすると、1 人目のユーザーが知らないうちに 2 人目のユーザーが作成したエンティティが 1 人目のエンティティを上書きしてしまいます。 トランザクションのもう 1 つの一般的な用法は、名前付きキーによってエンティティを取得することです。名前付きキーがまだ存在しない場合は、新規に作成します。 実はキーに対応する実態がなくても大丈夫(Noteに人のIDを突っ込んでputしていないし、実際にconsoleでみるとそれはないみたいな) HTTPリクエストから来ているやつらは基本的に文字列だから注意!!!Keyはnameだったりidだったりするので、とくにidの場合キャストせずに突っ込むとまずい。 ndbのkeyを作るときは、kindを文字列としても渡しても良いし、ndbのEntityのクラスを渡してもよいらしい。 sandy_key = ndb.Key(Account, 'sandy@example.com') ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '1') Keyを得るためには、これは本当に(S, S cup N)+の配列なので、自分で構築してしまったほうが早い。Keyはちゃんと設計して自分で作るもの。Entityから得るものというよりは。なのでfrom_pathを使っている時点でなんかおかしいと思ったほうが良さそう。 Cloud Storage †
Google Cloud SQL †
gcloud sql instances create myinstance2-replica2 --master-instance-name=myinstance2 を走らせた後にctrl-Cを押してもインスタンス作成はキャンセルされずに作られる。 SQLはstart timeというコンフィグが会って、 start of a 4-hour backup windowでバックアップが取られる。そのためコネクションが4時間に一回増える。 リードレプリカは全然削除を気軽にしても大丈夫。なぜならリードレプリカだから。最悪管理コマンドで消しても作り直せばよいし、再起動くらいなら全然やってよい。 MySQLの MySQL 5.6以降ではデフォルトでONに設定されるようになったパフォーマンススキーマですが、MySQL 5.5時代をご存知の方は明示的にOFFにしているかも知れません(MySQL 5.5のパフォーマンススキーマはパフォーマンスへのオーバーヘッドが非常に大きかった上に、大量にメモリーを利用した)。最近のパフォーマンススキーマはON/OFFに再起動が必要な点こそ変わりませんが、パフォーマンスオーバーヘッド、メモリー使用量ともに大幅に改善されています。また、取得できる情報も「ステートメント(ダイジェスト)単位での各種待ち状態の統計」、「各ステージでの経過時間」、「トランザクション単位での統計」などが追加され、さらに「スキーマ単位、テーブル単位で記録するか否か」、「ユーザー単位、ホスト単位で記録するか否か」を設定できるようになっています。 Cloud Launcher †https://qiita.com/NagaokaKenichi/items/41ee9d8ba40555eaf2b7 Cloud Launcherというサービスがあって、これをつかうとpredefinedのjenkinsなどをGCE上に立ち上げることができる。 BigTable? †HBase BigTable?のapache版。こっちからBigTable?に移行したい、あるいはベンダーロックを嫌うためにHBaseっぽいクライアントライブラリが提供されている(ちょっとの差はあるけど) com.google.cloud.bigtable.hbase.BigtableConfiguration?が全てのhaddp系と全く同じインターフェースの関数群を提供しており、それから先はほぼhadoop.hbaseと同じように操作できるよ!という感じ。 このナレッジベースがかなりよいので一読の価値がある 数については知らないのでページの機能をいい感じに実装するのは厳しそう Filter filter = new PageFilter?(pageSize); BTでもない BigTable? Cloud Bigtable は行をアトミックに読み取ります。このため、一回の更新が1行で収まるようにする努力が大切で、1 行に格納するデータ量の合計を制限することは非常に重要です。1 つのセルに格納するデータを 10 MB 以下にし、1 行のデータを 100 MB 以下にするのがベスト プラクティスです。 BigTable?は二次主キーを作ることができないが、列ファミリーをいくつか作ってその中では辞書順ソートされるようにできる。 Java+BigTable? githubのcloud-bigtable-examples/java/hello-worldのgithub上のREADMEに従ったら一瞬でできた。mavenを一から書くにはたいへんだな… put.addColumnみたいなのをやると、Bigtableの各列はector<map<string, multiset<string>>>みたいなものなので、その列ファミリーが指定するsetにappendされる mvn package mvn exec:java -Dbigtable.projectID=wakataberyo-sandbox2 -Dbigtable.instanceID=bigtable-test BigTable?の列ファミリーって何 BigQuery? †
# 半角数値 x を全角文字列に変換する関数 CREATE TEMP FUNCTION TO_MULTI_BYTE(x INT64) AS ( CODE_POINTS_TO_STRING(array(select c + 65248 from UNNEST(TO_CODE_POINTS(CAST(x as STRING))) as c)) ); # 全角文字列 x を半角数値に変換する関数 CREATE TEMP FUNCTION TO_SINGLE_BYTE(x STRING) AS ( CAST(CODE_POINTS_TO_STRING(array(select c - 65248 from UNNEST(TO_CODE_POINTS(x)) as c)) as INT64) ); BQの配列アクセスarr[1]は arr[OFFSET(1)] BQの一時テーブル作成において、以下のようにすると楽。 FROM UNNEST([1, 2, 3, 4, 5]) AS numbers; To convert an ARRAY into a set of rows, also known as "flattening," use the UNNEST operator. UNNEST takes an ARRAY and returns a table Pub/Sub †
Dataproc †
Kubernetes †https://knowledge.sakura.ad.jp/16082/ GKEを理解したい Docker: コンテナとイメージというのがあって、イメージからコンテナを作る感じ。コンテナをイメージにするコマンドもあるし、どのようにそのコンテナを作ったかを記録しておいてそれをスクリプト的に走らせて再現性高くコンテナを作ることもできる(Dockerfile)。DockerではDockerネットワークという仮想的なコンテナ間通信を行うことができる。 複数ホストでコンテナを起動して、コンテナ間通信するには、今回説明したことの他にも必要な設定があります。そこで活躍するのが、KubernetesやDocker Swarmなどのコンテナオーケストレーションツールになります(今はKubernetesがデファクトスタンダードとなっています)。 k8sはこれがわかりやすかった https://news.mynavi.jp/itsearch/article/devsoft/4097 1つ目は高い抽象度です。Dockerコンテナは通常一台のサーバ内に閉じて構築されます。複数台のサーバにまたがるコンテナ環境を構築するためには、ネットワークにおけるNAT設定など、さまざまな設定が必要になります。 こういった問題にアプローチするのがKubernetesです。Kubernetesを使うとコンテナのクラスタ化が容易になります。クラスタはサーバ単位でコンテナを管理するPodと、サーバをまたがるPodを管理するReplicaSet?の組み合わせで構築されます。 2つ目は高い信頼性・回復性です。セルフヒーリングと呼ばれ、障害により設定された台数を下回った場合には、自動的にコンテナが再起動されます。これにより、ゼロダウンタイムを実現します。 3つ目は中立性です。Kubernetesを実現するサービスはGoogle Cloud PlatformやOpenStack?などさまざまに存在します。CNCF(Cloud Native Computing Foundation)により標準化されており、Kubernetesが各クラウドを抽象化する層を担うことで、ベンダーロックインを防ぎます。 ハイパバイザ 従来のホストOS型は、HW->OS->仮想化->ゲストOS ハイパバイ座敷は、HW->ハイパバイザ仮想化->ゲストOSとなっている。 ハイパバイザの一つの例としては、Linux自体をハイパバイザにしたQEMUというのが有名(発表して二週間でLinuxにマージされたので)。これはLinuxだからホスト型じゃない?と思うかも知れないけど、ハイパバイザの上で通常のプロセスを走らせることなく、ゲストOSをのせるという点で少し異なる 技術的な差異は主に3つある。(1) 仮想化支援機能を有するCPUを前提としていること。通常ソフトだけで仮想化してx86の上でarmなどの違うアーキテクチャを動かすとその計算のエミュレートが大変だったのだが、CPUがその機能を提供するようなCPUが販売されるようになったので、パフォーマンスがよくなった(CPUを限定してゲストOS側を最適化・改造が必要な準仮想化に比べると遅いけど)。(2) KVMは独自にハイパバイザを開発するのではなく、Linuixのデバドラを流用できるのでハードウェア対応が容易 (3) KVMでのゲストOSはプロセスとして管理される(!)ので、killとかCtrl-CによるゲストOSの削除が可能になる KVMは完全仮想化に際して仮想化支援機能を有するCPUを要求する(HWに対する制約がある)。使用している機器にCPUの仮想化支援機能があるかどうか分からない場合は、/proc/cpuinfoを見てみるとよいでしょう。Intel VTの場合はvmxが、AMD-Vの場合はsvmがあるか否かが1つの判断基準となります。 apt-get install kvm bridge-utilsみたいなやつをやって、kvm-img create -fとかいうかなりお手軽間を醸し出していることをすることによってkvmがインストールできたりOSがインストールできたりしてすごい KVMはただでさえ仮想化していて物理的なサーバの位置がよくわからないのに、物理サーバの位置が多くなってくると本当にわけわからなくなってしまう。なので、こういうときに使うためのKVM運用ツールoVirtというものがある。 Cloud tasks †HTTP PUTを定期的に投げるだけのサービス(タスク:このHTTPリクエストをここに投げといてという依頼) 「POSTを積む、POSTを投げる」 投げる先はオンプレでもGCEでもApp Engineでもありえる。Google内部だといろいろ楽なので楽(例としてHTTPリクエストを…と言ったときにターゲットがApp Engineだったらprojectからの相対パスで指定できるので)。 ターゲットはPOSTに対して200台を返す義務がある。返さないとリトライとかされる。 Cloud Tasksからのリクエストには、どのキューからPOSTされたのかなどのヘッダーが書かれている。 こういうタスク系は非常に重くて特殊なものを使いがちだと思うので、GAEではなくGCEがそれを受けるというのが現実的になりそう 数百万または数十億のような多数のタスクを追加する必要がある場合、二重注入パターンが便利です。1 つのジョブからタスクを作成する代わりに、インジェクタ キューを使用します。 このTask Queueには、キューに追加した処理がGAEにより自動実行されない Pull Queue という種類があり、これを使うとGAEではない外部のプラットフォームからキューに入っている処理を引き出す事ができます。 StandardはTask queue, FlexはCloud tasks/PubSub?を使うべき(本当?StandardもCloud tasksのほうが良くない?) 言語 †Java †JavaでLocalをチェックするための方法として、以下のものがある。要するに、環境変数的な感じでSystemからappengine.appid private static final String APP_ID = System.getProperty("appengine.appId"); private static final String APP_VERSION = System.getProperty("appengine.version"); private static final boolean LOCAL_TEST = null == APP_ID || null == APP_VERSION; app.yamlにそうとうするものは、javaのばあいsrc/main/webapp/WEB-INF/appengine-web.xmlになっているっぽい。ここの部分でランタイムをxmlとして入力し、 Javaのweb-??.xmlみたいなやつ(app.yamlのJava ver)では、serviceが何故かmoduleという表現になっている あと、appIdって見たらプロジェクトIDのことだと思う必要がある インスタンス設定 †
デプロイ †
初期設定 †
curl https://sdk.cloud.google.com | bash exec -l $SHELL gcloud init # ちゃんとログインページに飛ばしてくれないので、リンクを手でコピペする ssh †gcloud compute ssh instance-1 --zone us-central1-c GCPでコマンドが無い時に自動終了するスクリプト †https://twitter.com/imos/status/923551881166602240 月2ドルとかで超安くサーバが使えるように鳴るらしい Googleクラウド お金がクレジットある状態だと不明瞭なのまじね。試しに使って見て、これくらいかーとなるもんじゃないの Logging †Stackdriver Logging †
Stackdriver Trace †https://cloudplatform-jp.googleblog.com/2018/05/viewing-trace-spans-and-request-logs-in-multi-project-deployments.html また、トレースの一部となっている全プロジェクトからのリクエストに関するログ エントリの表示も可能です。これには関連するプロジェクト側に “logging.logEntries.list” の権限が必要で、ログを Stackdriver Logging に書き込む際は、“projects/[PROJECT-ID]/traces/[TRACE-ID]” というフォーマットで LogEntry? オブジェクトの trace フィールドを設定する必要があります。LogEntry? の span_id フィールドを、16 文字の 16 進数でエンコードされたスパン ID として設定し、ログを特定のトレース スパンと関連づけることも可能です。詳細はこちらのドキュメントを参照してください。 Fluentd を介して Google Kubernetes Engine もしくは Stackdriver Logging エージェントを利用する場合は、“logging.googleapis.com/trace” や “logging.googleapis.com/span_id” というキーを使って構造化ログを書き込むことで、LogEntry? オブジェクトの trace や span_id フィールドを設定できます。詳細はこちらのドキュメントを参照してください。 トレース スパンに関連づけられたログ エントリを表示するには、“Show logs” をクリックしてください。 ということは、これはStackdriver Traceと同等の機能なのか。 Cloud Activity †パーミッションチェンジみたいなやつは、Cloud Activityで得ることができる。Cloud ActivityはもともとStackdriverのAdmin操作のみを取り出したもので、 Cloud Activity (Home > My Activity) of your "snap-crackle-proxy" project and then filter for resources "GCS bucket". gcloud †gcloud app logs read gcloud app logs tail Appengineのstackdriver logging的なものが得られる。各サービス、HTTPリクエスト、loggingが割と読みやすい形式で撮ってくれる。 結構遅延がある (30分) 言語別比較 †
|