Suche senden
Hochladen
マルチテナントのアプリケーション実装〜実践編〜
•
3 gefällt mir
•
5,003 views
Y
Yoshiki Nakagawa
Folgen
マルチテナントのアプリケーション実装〜実践編〜 2022.04.20 SaaS.tech #2
Weniger lesen
Mehr lesen
Software
Melden
Teilen
Melden
Teilen
1 von 36
Jetzt herunterladen
Downloaden Sie, um offline zu lesen
Empfohlen
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのこと
Amazon Web Services Japan
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
Redisの特徴と活用方法について
Redisの特徴と活用方法について
Yuji Otani
RLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for Django
Takayuki Shimizukawa
Istioサービスメッシュ入門
Istioサービスメッシュ入門
Yoichi Kawasaki
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
増田 亨
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)
mosa siru
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
Empfohlen
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのこと
Amazon Web Services Japan
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
Redisの特徴と活用方法について
Redisの特徴と活用方法について
Yuji Otani
RLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for Django
Takayuki Shimizukawa
Istioサービスメッシュ入門
Istioサービスメッシュ入門
Yoichi Kawasaki
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
増田 亨
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)
mosa siru
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
NTT DATA Technology & Innovation
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Kohei Tokunaga
3分でわかるAzureでのService Principal
3分でわかるAzureでのService Principal
Toru Makabe
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
Spanner移行について本気出して考えてみた
Spanner移行について本気出して考えてみた
techgamecollege
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
NTT DATA Technology & Innovation
超実践 Cloud Spanner 設計講座
超実践 Cloud Spanner 設計講座
Samir Hammoudi
そんなトランザクションマネージャで大丈夫か?
そんなトランザクションマネージャで大丈夫か?
takezoe
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
Amazon Web Services Japan
Ingress on Azure Kubernetes Service
Ingress on Azure Kubernetes Service
Toru Makabe
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
A AOKI
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Platform - Japan
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
Hiroshi Ito
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
NTT DATA Technology & Innovation
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
NTT DATA Technology & Innovation
Azure API Management 俺的マニュアル
Azure API Management 俺的マニュアル
貴志 上坂
webエンジニアのためのはじめてのredis
webエンジニアのためのはじめてのredis
nasa9084
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
Tetsutaro Watanabe
Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版
Takuya Matsunaga
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
Insight Technology, Inc.
Weitere ähnliche Inhalte
Was ist angesagt?
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
NTT DATA Technology & Innovation
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Kohei Tokunaga
3分でわかるAzureでのService Principal
3分でわかるAzureでのService Principal
Toru Makabe
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
Spanner移行について本気出して考えてみた
Spanner移行について本気出して考えてみた
techgamecollege
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
NTT DATA Technology & Innovation
超実践 Cloud Spanner 設計講座
超実践 Cloud Spanner 設計講座
Samir Hammoudi
そんなトランザクションマネージャで大丈夫か?
そんなトランザクションマネージャで大丈夫か?
takezoe
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
Amazon Web Services Japan
Ingress on Azure Kubernetes Service
Ingress on Azure Kubernetes Service
Toru Makabe
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
A AOKI
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Platform - Japan
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
Hiroshi Ito
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
NTT DATA Technology & Innovation
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
NTT DATA Technology & Innovation
Azure API Management 俺的マニュアル
Azure API Management 俺的マニュアル
貴志 上坂
webエンジニアのためのはじめてのredis
webエンジニアのためのはじめてのredis
nasa9084
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
Tetsutaro Watanabe
Was ist angesagt?
(20)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
3分でわかるAzureでのService Principal
3分でわかるAzureでのService Principal
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Spanner移行について本気出して考えてみた
Spanner移行について本気出して考えてみた
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
超実践 Cloud Spanner 設計講座
超実践 Cloud Spanner 設計講座
そんなトランザクションマネージャで大丈夫か?
そんなトランザクションマネージャで大丈夫か?
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
Ingress on Azure Kubernetes Service
Ingress on Azure Kubernetes Service
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
「実践ドメイン駆動設計」 から理解するDDD (2018年11月)
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
Knative Eventing 入門(Kubernetes Novice Tokyo #11 発表資料)
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
Azure API Management 俺的マニュアル
Azure API Management 俺的マニュアル
webエンジニアのためのはじめてのredis
webエンジニアのためのはじめてのredis
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
Ähnlich wie マルチテナントのアプリケーション実装〜実践編〜
Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版
Takuya Matsunaga
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
Insight Technology, Inc.
Tech Dojo 02/09 IBM Japan CSM
Tech Dojo 02/09 IBM Japan CSM
勇 黒沢
[db tech showcase Tokyo 2015] D35:高トランザクションを実現するスケーラブルRDBMS技術 by 日本電気株式会社 並木悠太
[db tech showcase Tokyo 2015] D35:高トランザクションを実現するスケーラブルRDBMS技術 by 日本電気株式会社 並木悠太
Insight Technology, Inc.
株式会社waja 安藤様 登壇資料
株式会社waja 安藤様 登壇資料
leverages_event
20151029 ヒカラボ講演資料
20151029 ヒカラボ講演資料
Daisuke Ando
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
Yuta Matsumura
Node.jsアプリの開発をモダン化するために取り組んできたこと
Node.jsアプリの開発をモダン化するために取り組んできたこと
bitbank, Inc. Tokyo, Japan
The Twelve-Factor Appで考えるAWSのサービス開発
The Twelve-Factor Appで考えるAWSのサービス開発
Amazon Web Services Japan
技術選択とアーキテクトの役割
技術選択とアーキテクトの役割
Toru Yamaguchi
Cosmos DB 入門 multi model multi API編
Cosmos DB 入門 multi model multi API編
Takekazu Omi
CSI Driverを開発し自社プライベートクラウドにより適した安全なKubernetes Secrets管理を実現した話
CSI Driverを開発し自社プライベートクラウドにより適した安全なKubernetes Secrets管理を実現した話
Katsuya Yamaguchi
『これからの.NETアプリケーション開発』セミナー .NET用アプリケーション フレームワーク Open 棟梁 概説
『これからの.NETアプリケーション開発』セミナー .NET用アプリケーション フレームワーク Open 棟梁 概説
Daisuke Nishino
Mvc conf session_2_shibamura
Mvc conf session_2_shibamura
Hiroshi Okunushi
Prometheus超基礎公開用.pdf
Prometheus超基礎公開用.pdf
勇 黒沢
Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Kazumi IWANAGA
AWS Dev Day Tokyo 2018 | Amazon DynamoDB Backed なテレコムコアシステムを構築・運用してる話
AWS Dev Day Tokyo 2018 | Amazon DynamoDB Backed なテレコムコアシステムを構築・運用してる話
SORACOM,INC
QuickDemo HashiCorp Terraform with Microsoft Azure and VMware vSphere
QuickDemo HashiCorp Terraform with Microsoft Azure and VMware vSphere
Wataru Unno
Software Development with Symfony
Software Development with Symfony
Atsuhiro Kubo
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
和弘 井之上
Ähnlich wie マルチテナントのアプリケーション実装〜実践編〜
(20)
Dalvikバイトコードリファレンスの読み方 改訂版
Dalvikバイトコードリファレンスの読み方 改訂版
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
[db tech showcase Tokyo 2015] A26:内部犯行による漏えいを防ぐPostgreSQLの透過的暗号化機能に関する実装と利用方法...
Tech Dojo 02/09 IBM Japan CSM
Tech Dojo 02/09 IBM Japan CSM
[db tech showcase Tokyo 2015] D35:高トランザクションを実現するスケーラブルRDBMS技術 by 日本電気株式会社 並木悠太
[db tech showcase Tokyo 2015] D35:高トランザクションを実現するスケーラブルRDBMS技術 by 日本電気株式会社 並木悠太
株式会社waja 安藤様 登壇資料
株式会社waja 安藤様 登壇資料
20151029 ヒカラボ講演資料
20151029 ヒカラボ講演資料
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
Node.jsアプリの開発をモダン化するために取り組んできたこと
Node.jsアプリの開発をモダン化するために取り組んできたこと
The Twelve-Factor Appで考えるAWSのサービス開発
The Twelve-Factor Appで考えるAWSのサービス開発
技術選択とアーキテクトの役割
技術選択とアーキテクトの役割
Cosmos DB 入門 multi model multi API編
Cosmos DB 入門 multi model multi API編
CSI Driverを開発し自社プライベートクラウドにより適した安全なKubernetes Secrets管理を実現した話
CSI Driverを開発し自社プライベートクラウドにより適した安全なKubernetes Secrets管理を実現した話
『これからの.NETアプリケーション開発』セミナー .NET用アプリケーション フレームワーク Open 棟梁 概説
『これからの.NETアプリケーション開発』セミナー .NET用アプリケーション フレームワーク Open 棟梁 概説
Mvc conf session_2_shibamura
Mvc conf session_2_shibamura
Prometheus超基礎公開用.pdf
Prometheus超基礎公開用.pdf
Azure でサーバーレス、 Infrastructure as Code どうしてますか?
Azure でサーバーレス、 Infrastructure as Code どうしてますか?
AWS Dev Day Tokyo 2018 | Amazon DynamoDB Backed なテレコムコアシステムを構築・運用してる話
AWS Dev Day Tokyo 2018 | Amazon DynamoDB Backed なテレコムコアシステムを構築・運用してる話
QuickDemo HashiCorp Terraform with Microsoft Azure and VMware vSphere
QuickDemo HashiCorp Terraform with Microsoft Azure and VMware vSphere
Software Development with Symfony
Software Development with Symfony
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
マルチテナントのアプリケーション実装〜実践編〜
1.
© 2022 LayerX
Inc. 1 マルチテナントのアプリケーション実装 〜実践編〜 SaaSにおけるマルチテナント設計の悩みと勘所 SaaS.tech #2 2022.04.20
2.
© 2022 LayerX
Inc. 2 自己紹介 株式会社LayerX 中川佳希 @yyoshiki41 バクラク請求書のテックリード バックエンドからフロントエンドまで. SaaS が扱う業務ドメインへの好奇心と サービスの成長に日々ワクワクを感じています. Gopher.
3.
© 2022 LayerX
Inc. 3 1. 導入 a. マルチテナントSaaS 2. データベース設計 a. 設計パターン 3. アプリケーション側での実装 a. テーブルスキーマ b. 型(Type)の実装 c. コンテキスト(Request-scoped Data) d. ORM e. バリデーション f. ロギング / モニタリング g. テスト 章立て
4.
© 2022 LayerX
Inc. 4 マルチテナント SaaS マルチテナント SaaS は・・・ 同質のソフトウェアを全テナントのユーザーへ提供. リソースの一部またはすべてをテナント間で共有. SaaS 提供側のメリット(シングルテナントアプリケーションと比較) ● 機能提供アウトカムの最大化 ● サービス運用の効率化 ● インフラコストの削減
5.
© 2022 LayerX
Inc. 5 開発者を悩ますポイント 1. テナント毎に安全にデータを分離した状態で、アプリケーションを実装できるか? 2. テナント境界線をどのレイヤで実装するか? 3. テナント間のシステムリソース共有をどこまで行うか? マルチテナント SaaS が絶対に防ぐべきこと => データが他のテナントにも共有されてしまうこと(漏洩) マルチテナント SaaS
6.
© 2022 LayerX
Inc. 6 マルチテナント SaaS での安全なデータ分離の実装 安全にテナント毎のデータを分離するには? ● データベース ● ミドルウェア ○ アプリ => ミドルウェア => データベース のような Proxy を想定 ● アプリケーション ● テスト 以降では低レイヤの部分から順にみていきます.
7.
© 2022 LayerX
Inc. 7 SaaS 開発における最初の分岐点 1. データベースをテナント毎に作成 => データ所有者(テナント)を データベース名 で表現 2. データベースは共有、スキーマをテナント毎に作成 => データ所有者(テナント)を スキーマ で表現 3. データベースは共有、テーブルをテナント毎に作成 => データ所有者(テナント)を テーブル名 で表現 4. データベースは共有、テーブルも共有、 各テーブルがテナント識別カラムを持ち、レコード値で識別・分離 => データ所有者(テナント)を テーブルのカラム値 で表現 データベース設計 Isolated Shared
8.
© 2022 LayerX
Inc. 8 1. データベースをテナント毎に作成 メリット 1. データの持ち方としては、もっとも堅牢 デメリット 1. マイグレーション(テーブルスキーマ変更)コスト 2. アプリからのデータベース接続コスト a. データベースユーザーが異なる場合, セッションも異なる 3. テナント作成時に、毎回データベースの初期化処理が必要 a. テーブル作成、データベースユーザーの認証設定 4. テナントとデータベースのリレーションが別途必要 Tenant B Tenant A
9.
© 2022 LayerX
Inc. 9 スキーマとは... PostgreSQL などで名前空間を作成できる仕組み. データベースオブジェクト(テーブル、関数など)を 同じオブジェクト名でもスキーマが異なれば作成可能になる. MySQL ではオブジェクトを論理的に分ける (グルーピングする)仕組みに相当するものは見当たらず. 2. データベースは共有、スキーマをテナント毎に作成 Global Tables Tenant A Tables Tenant B
10.
© 2022 LayerX
Inc. 10 2. データベースは共有、スキーマをテナント毎に作成 Global Tables Tenant A Tables Tenant B メリット 1. スキーマ単位で所有者を決めれる デメリット 1. マイグレーション(テーブルスキーマ変更)コスト 2. アプリからのデータベース接続コスト a. スキーマ所有者が異なる場合, セッションも異なる 3. テナント作成時に、毎回スキーマの初期化処理が必要 a. テーブル作成、スキーマ所有者の認証設定 4. テナントとスキーマのリレーションが別途必要
11.
© 2022 LayerX
Inc. 11 メリット 1. 1つのデータベース内でテナントのデータを保持できる デメリット 1. マイグレーション(テーブルスキーマ変更)コスト 2. テナント作成時に、毎回テーブルの初期化処理が必要 a. テーブル作成 3. テナントとテーブル名のリレーションが別途必要 4. テナントのテーブル間で外部キーが煩雑になる 3. データベースは共有、テーブルをテナント毎に作成 Global Tenant A tables Tenant B tables
12.
© 2022 LayerX
Inc. 12 ID TenantID Name 1 A Foo 2 B Bar メリット 1. マイグレーション(テーブルスキーマ変更)コストが低い 2. データベース側での設定コストが低い デメリット 1. 他テナントのレコードへアクセスが容易 a. 同一テーブルの為, 最もカジュアルにアクセス可能 2. ロジックを実装する必要がある a. アプリ側で制御する場合 i. WHERE 句 b. データベース側で制御する場合 i. Row-Level Security での制御 ii. ストアドプロシージャを実装しての制御 4. テーブルにテナント識別カラムを持ち, 行単位で制御 Global tables
13.
© 2022 LayerX
Inc. 13 テーブルに識別カラムを持ち, テーブルへのポリシー × データベースユーザーで制御するをデータベース側で実装す る例 データベースユーザーのセッション管理などが一定ネックになる. ● PostgreSQL Row Level Security ○ PostgreSQL ネイティブの機能 ● Implementing row level security in MySQL / SQL Maestro ○ Trigger や View テーブルを使って, MySQL で RLS を実現する例 4. テーブルにテナント識別カラムを持ち, 行単位で制御
14.
© 2022 LayerX
Inc. 14 アプリ => ミドルウェア => データベース のようなプロキシを想定. ● ProxySQL ○ mysql_query_rules: WHERE 句に TenantID がないクエリをはじく ● MariaDB MaxScale ○ Deny ルールを作る: WHERE 句に TenantID がないクエリをはじく 上記のような SQL を解釈できるプロキシミドルウェアで, ポリシー(とデータベースユーザーの掛け合わせ)での制御. ポリシーに沿わないレコードへのアクセスを拒否する. 実検証までは行っておらず 🙏 ミドルウェア(+α)
15.
© 2022 LayerX
Inc. 15 4. テーブルにテナント識別カラムを持ち, 行単位で制御 主な理由 ● データベース、マイグレーション運用コストが最も低い ○ デプロイ(マイグレーション)難易度が高いサービスは致命的 ○ テナント追加時, データベース側の初期化処理のサブシステム等が不要 ● データベース側にロジックを寄せることでのロックインを避けたい ○ ストアドプロシージャなどの実装への依存も持ちたくない ● テナント数のスケールに最も適している ○ テナント毎のデータベースユーザーと管理, アプリからの接続セッションの管 理なども不要 ● ロジックのテストの行いやすさ バクラクでのデータベース設計
16.
© 2022 LayerX
Inc. 16 4. テーブルにテナント識別カラムを持ち, 行単位で制御 テナント毎にデータを(論理的に)識別・分離して扱うことは, 至上命題. 実際の取り組み(ここからが本題) 1. テーブルスキーマ 2. 型(Type)の実装 3. コンテキスト(Request-scoped Data) 4. ORM 5. バリデーション 6. ロギング / モニタリング 7. テスト アプリケーション実装〜実践編〜 ID TenantID Name 1 A Foo 2 B Bar
17.
© 2022 LayerX
Inc. 17 全テーブルへ冗長に TenantID (テナント識別カラム)を付ける (中間テーブル、子テーブルでも同様) 親テーブルにはマストで必要. 子テーブルでは従来, 親テーブルへの外部キー制約だけで充分. 冗長にカラムを付ける理由は, 1. ORM などで, WHERE句に TenantID を機械的に付けれる a. カラム有無を考えなくて良い 2. JOIN 時にも TenantID を機械的に付けれる 3. 子テーブルから自テナントデータのみを取得可能 4. 親, 子テーブルで異なる TenantID のデータを排除 5. シャーディングが必要になった際, キーに使える テーブルスキーマ ID TenantID Name 1 A Foo 2 B Bar parents ID ParentID TenantID Name 11 1 A Foo 22 2 B Bar children
18.
© 2022 LayerX
Inc. 18 JOIN 時にも TenantID を機械的に付けれる 通常, 起きてはいけない不整合データを取得時に排除可能. ※ INSERT時に検知すべきかつ, 従来のリレーショナルモデル では考慮しなくてもよい問題ではある... 例.リレーションのあるテーブル間で異なる TenantID のレコード テーブルスキーマ ID TenantID Name 1 A Foo 2 B Bar parents ID ParentID TenantID Name 11 1 A Foo 22 2 XXX Bar children SELECT * FROM parents INNER JOIN children ON parents.ID = children.ParentID AND parents.TenantID = children.TenantID WHERE parents.TenantID = "B";
19.
© 2022 LayerX
Inc. 19 子テーブルから自テナントレコードのみを取得可能 アプリの処理単位もテナント単位なので, 利用しやすいデータモデル. API 等から ID 指定でリソース取得するケースでも, 機械的に TenantID を付けてバリデーションできる. テーブルスキーマ ID TenantID Name 1 A Foo 2 B Bar parents ID ParentID TenantID Name 11 1 A Foo 22 2 B Bar children SELECT * FROM children WHERE TenantID = "B"; SELECT * FROM children WHERE TenantID = "B" AND ID IN ("ID1", "ID2", ...);
20.
© 2022 LayerX
Inc. 20 シャーディングが必要になった際には, キーとして使用できる. Google’s F1 paper で, 分散データベースの階層型のデータモデル(The Cluster Hierarchical Model)が触れられている. リレーショナルモデルでは, 親テーブルへの外部キーを持つカラムだけでリレーションを表 現可能. しかし, 分散データベース環境化では従来のリレーショナルモデルの外部キーだ けではトランザクション, ジョインなどのコストが高価になる. 先祖(親)の ID をプライマリキーに含めることで, 物理的にも同じマシンでの処理が行え る. ● Google F1 ● Designing your SaaS Database for Scale with Postgres / Citus Data ● Sharding a multi-tenant app with Postgres / Citus Data テーブルスキーマ
21.
© 2022 LayerX
Inc. 21 従来のリレーショナルモデルとの比較 テーブルスキーマ
22.
© 2022 LayerX
Inc. 22 ユニークキーやインデックスも TenantID を軸に設計する 例えば name カラムにユニークキー制約をつけたい場合, TenantID を先頭(プレフィックス)に付けた複合キー にする. テーブルスキーマ CREATE TABLE `table_a` ( `id` int(11) NOT NULL, `tenant_id` varchar(36) NOT NULL, `name` varchar(36) NOT NULL, PRIMARY KEY `id`, UNIQUE KEY (`tenant_id`,`name`), CONSTRAINT `fk_tenant_id` FOREIGN KEY (`tenant_id`) REFERENCES `tenants` (`id`) ) ENGINE=InnoDB; ID TenantID Name 1 A Foo 2 B Bar
23.
© 2022 LayerX
Inc. 23 複合キーは列挙したカラム順に連結して, 内部値としてインデックスされる. WHERE tenant_id = “B” (インデックスのプレフィックス) だけでも既知の範囲に絞るイ ンデックスとして機能する. アプリが使用するテナントのレコードへの効率的なクエリになる. PrimaryKey を用いないクエリでは, 必須のインデックスになる. ※ PrimaryKey を用いる場合も, 後述する Context が持つ TenantID と一致している か検証するため, WHERE 条件として使用している tips:複合キーのカラムを ForeignKey として使用する際の話 MySQL 外部キー制約とインデックスに必要な知識 - LayerX エンジニアブログ テーブルスキーマ
24.
© 2022 LayerX
Inc. 24 A defined type in Go TenantID という型を新たに定義して使用 underlying type は, プリミティブな string 型 A defined type の主なメリット ● 関数引数, 返り値の間違いや代入ミスをコンパイル時にエラーにできる ● 独自メソッドを実装できる 型(Type)の実装 type TenantID string
25.
© 2022 LayerX
Inc. 25 Generate go model from a database table schema テーブル定義から, Go の Struct 生成を行う. xo というツールで自動生成. TenantID カラム生成時には, 独自定義した型を使用している. 型(Type)の実装 type TableA struct { ID string TenantID TenantID Name string }
26.
© 2022 LayerX
Inc. 26 リクエストを受け取ったAPIサーバーは, コンテキストに TenantID を入れる ユーザーの認証後に特定されたテナント情報をアプリのMiddleware層でセット. 以降は, この TenantID をもとにレスポンスまで処理を行っていく. コンテキスト(Request-scoped Data) func ContextWithTenantID(ctx context.Context, tenantID TenantID) context.Context { return context.WithValue(ctx, ctxKeyTenantID, tenantID) }
27.
© 2022 LayerX
Inc. 27 バッチ処理などの実装 テナント毎に処理を実行するように関数を実装する ※ テナントをまたいで処理を行う関数を極力実装しない コンテキスト(Request-scoped Data) func ProcessPerTenant(ctx context.Context, input string) context.Context { // do stuff… }
28.
© 2022 LayerX
Inc. 28 ORM gorm の Callback plugin を実装. WHERE 句に自動で TenantID 条件がつくようにしている. func NewGlobalDB(conf *mysql.Config) { … // Register callback functions db.Callback().Query().Before("gorm:query").Register("my_plugin:before_query", callbackTenantID) db.Callback().Update().Before("gorm:update").Register("my_plugin:before_update", callbackTenantID) db.Callback().Delete().Before("gorm:delete").Register("my_plugin:before_delete", callbackTenantID) db.Callback().RowQuery().Before("gorm:row_query").Register("my_plugin:before_row_query", callbackTenantID) }
29.
© 2022 LayerX
Inc. 29 ORM 登録する Callback 関数の実装は, Struct 内の TenantID フィールドを検出して, WHERE 句をセットする. (SELECT / CREATE / UPDATE / DELETE) アプリから呼び出す際には, TenantID を引数に渡してコールバック関数が登録された DBインスタンスを仕様する. err := app.NewDB(db, tenantID).First(&model).Error
30.
© 2022 LayerX
Inc. 30 一部のメソッド(Raw, Exec)では, callback 関数では対応出来ない.. ※ Raw, Exec は, 記述したSQLをそのまま実行できる機能 ● 基本的に使用させない.(CIでの検知) ● 管理画面など, 例外的には使用可能 ORM var result Result err := db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)
31.
© 2022 LayerX
Inc. 31 callback 関数が発火せずに実行されたクエリに対しては, ログを出力するようにもしている. 意図せずに, TenantID を指定しないクエリを発見出来るようにする. ORM
32.
© 2022 LayerX
Inc. 32 バリデーション APIサーバーの終端でレスポンスデータのバリデーションを実行 RDS含め Redis, ElasticSearch, DynamoDB などデータソース全体で, 他のテナントデータが含まれていないことを検証する最後の砦. 関数内で再帰的にレスポンスオブジェクトの TenantID フィールドが一致していることを 検証. Go で書くには骨が折れる reflect での処理. func ValidateTenantID(tenantID TenantID, obj interface{}) { // do validation… }
33.
© 2022 LayerX
Inc. 33 ログには常に TenantID を含めて出力 logger 側で Context 内の TenantID 自動で出力するように実装 アプリからの呼び出し: モニタリングツール(Datadog)上でも, Log Facets としてフィルタも可能. トラブルシュート時にデータソース特定や カスタマー連絡に役立ちます. ロギング / モニタリング app.LogError(ctx, err).Send()
34.
© 2022 LayerX
Inc. 34 TenantID がついていないSQLクエリログをモニタリングツールで監視 正規表現でのチェックが必要なため, まだまだ調整中 (理想はSQLパーサーでアラート条件を作れること) ロギング / モニタリング
35.
© 2022 LayerX
Inc. 35 単体テスト毎にテナントを作成して, 並列に実行する ● 他テナントデータに影響を与える場合, テストで検知出来る ○ 他のテナントへ相互に影響を与える機能が存在しない ● パッケージ内の全テスト完了まで, テストデータをドロップ(削除)しない ● テスト/サブテスト並列度を上げる動機づけになる ● テナントセットアップは, ヘルパー関数を用意 テスト func TestA(t *testing.T) { helper.SetupTenant(t) t.Run(“Case1”, func(t *testing.T) { t.Parallel(t) // run tests… } }
36.
© 2022 LayerX
Inc. 36 ● アプリケーション実装でのテナントデータの論理的な分離を行う方針を取っていま す. ○ データベースやミドルウェアでの制御でも, ポリシー × ユーザーでのロジック 実装部分は避けられないと思います. ● 開発/テスト/デプロイのコストの低さやロックインを避けれるなどメリットはあります. ○ その反面, アプリ側でのガードレール実装の重要度は高くなります. ● 安全かつ開発スピードも落ちない仕組みの改善は進めていきます. まとめ
Jetzt herunterladen