Carpe Diem

備忘録

マイグレーションデータの完全性をチェックする方法

概要

オンプレからクラウドに移行(マイグレーション)した場合や、クラウド上でセルフホスティングしていたDBをマネージドDBに移行した場合に問題となるのが「データは欠損なく移行されたか」です。

データの数が少なければプログラミングで差分チェックなどを書けますが、億単位の数であったりTB単位のサイズといったオーダーでは自前でプログラミングして差分を出すのは現実的では有りません。

そこで分散処理に強いBigQueryを利用することで、大規模データのマイグレーションにおいても完全性のチェックが実現できます。

環境

  • mongoexport 100.5.0
  • gsutil 5.5
  • bq v2.0.72

アーキテクチャ

アーキテクチャとしては以下です。今回データベースはMongoDBを想定しています。

続きを読む

Cloud ArmorのAdaptive Protectionを使ってみる

概要

Cloud ArmorのようなWAFは通常ルールベースで不正なアクセスを制御するため、悪意あるユーザがIPアドレスやパラメータをコロコロ変えたりすると都度ルールを設定する必要が出てきてイタチごっこになりがちです。

そんなケースに対応できるよう、機械学習を用いて攻撃であるかどうかを判断してくれるマネージドサービスがAdaptive Protectionです。

イメージとしては以下の図のように悪意あるユーザの攻撃と判断されたらアラートで通知してくれて、適用すべきルールまで自動的に教えてくれます。

ref: https://cloud.google.com/armor/docs/adaptive-protection-use-cases?hl=ja

なのでサービス側としてはアラートを見て「これは攻撃だろう」と判断したら提案されたルールを適用するだけで防ぐことが可能になります。

つまりAdaptive Protectionを用いることで

  • 迅速な攻撃の検知ができる
  • 不正リクエストを弾くためのルール(パラメータ)を人が考えなくて良い

といったメリットを享受できます。

続きを読む

GoでネストしたMongoDBドキュメントの部分更新をする

概要

MongoDBが使っているbsonomitemptyというstructタグが利用可能で、これを使うことでそのフィールドがzero値の際は

  • insert時にフィールドを追加しない(容量の削減)
  • update時にフィールドを更新しない(部分アップデートの簡易化)

といったメリットがあります。

しかし以下のようにネストしたドキュメントについては期待する挙動をしないのでその対応方法を紹介します。

type User struct {
    ID      string  `bson:"_id"`
    Name    string  `bson:"name,omitempty"`
    Age     int     `bson:"age,omitempty"`
    Address Address `bson:"address,omitempty"`
}

type Address struct {
    Country string `bson:"country,omitempty"`
    State   string `bson:"state,omitempty"`
    City    string `bson:"city,omitempty"`
    Zipcode string `bson:"zipcode,omitempty"`
}

環境

  • Go v1.18.3
  • MongoDB v5.0.9
  • mongo-go-driver v1.9.1
  • flatbson v0.3.0
続きを読む

gRPCでFieldMaskを使う(更新編)

概要

christina04.hatenablog.com

前回はFieldMaskを使ってオーバーフェッチを避ける方法を説明しました。

今回はMutation(更新)におけるFieldMaskの活用方法を説明します。

環境

  • Go v1.18.3
  • protoc-gen-go v1.25.0
  • protoc v3.19.4
  • grpc-go v1.47.0
  • MongoDB 5.0.9
続きを読む

gRPCでFieldMaskを使う(取得編)

概要

クライアントデバイスが多様化する中、UIに必要なデータもそれぞれ異なるためAPIのオーバーフェッチ(不要なデータの取りすぎ)が課題になってきます。
またマイクロサービス間の通信でも、例えばマスタ系データのうち必要なデータだけ取得して利用したいケースは多々あります。

かと言ってその度に必要最低限のデータを取得するメソッドを用意するのは開発が大変ですし、逆に細かいデータばかりのgRPCを用意すると今度はアンダーフェッチ(データが足りなくて複数回コールが必要になる)が発生します。

GraphQLでは欲しいデータをクライアント側が明示的に要求するのでオーバーフェッチが発生しないというメリットがありますが、gRPCではFieldMaskという機能があります。

今回はFieldMaskを使って余分なデータを返さない方法を説明します。

環境

  • Go v1.18.3
  • protoc-gen-go v1.25.0
  • protoc v3.19.4
  • grpc-go v1.47.0
  • mennanov/fmutils v0.2.0
続きを読む

Envoyで自動リトライ

概要

ネットワーク越しの通信は基本的に不安定であるため、外部APIとの通信で発生したエラーを都度クライアントに返すとエラー率が上がってしまいユーザ体験が悪くなってしまします。

そこでクライアントに返す前に何度かリトライすることで、エラー率を下げるようにするという実装を行うことが多いです。
例えばGCPSDKではgax-goというライブラリがそこを保証してくれています。

google-cloud-go/invoke.go at 20e9b2acf7766594da827da62858d83cb03fed81 · googleapis/google-cloud-go · GitHub
gax-go/invoke.go at ce75229dd089591008bbaf03b1518474f9830646 · googleapis/gax-go · GitHub

しかしこういった処理は本来アプリケーションで表現したいドメイン部分ではないので、できればEnvoyやIstioといったソリューションで解決したいです。

今回はEnvoyでの設定方法を説明します。

環境

  • Envoy 1.22.0

構成

以下のように前段にEnvoyを挟んでバックエンドのリトライを自動化します。

続きを読む

Bazel で multiple copies of package passed to linker の対応方法

概要

Bazelでビルド時に

multiple copies of package passed to linker: @io_bazel_rules_go//proto/wkt:field_mask_go_proto @org_golang_google_genproto//protobuf/field_mask:field_mask

のようなエラーが出た時の対応です。

環境

  • Bazel 5.0.0
  • gazelle 0.25.0
  • grpc-gateway 2.10.3

原因

protobufのWKT(Well Known Types)は複数のルールで提供されています。

複数のライブラリが同じproto(今回だとgoogle.golang.org/genproto/protobuf/field_mask)に依存している状態で、けれど依存するルールが異なる場合にこの問題が発生します。

よく起きるケースとしては以下の両方を満たす場合です。

  • あるライブラリは事前に生成された.pb.goに依存している
  • 別のライブラリはBazelビルド時に.protoから生成される
続きを読む