Skip to main content
Download free for 30 days
Sign in
Upload
Language (EN)
Support
Business
Mobile
Social Media
Marketing
Technology
Art & Photos
Career
Design
Education
Presentations & Public Speaking
Government & Nonprofit
Healthcare
Internet
Law
Leadership & Management
Automotive
Engineering
Software
Recruiting & HR
Retail
Sales
Services
Science
Small Business & Entrepreneurship
Food
Environment
Economy & Finance
Data & Analytics
Investor Relations
Sports
Spiritual
News & Politics
Travel
Self Improvement
Real Estate
Entertainment & Humor
Health & Medicine
Devices & Hardware
Lifestyle
EN
Upload
Download free for 30 days
Sign in
YN
Uploaded by
Yoshiki Nakagawa
PDF, PPTX
6,987 views
マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜 2022.04.20 SaaS.tech #2
Software
◦
Read more
3
Save
Share
Embed
Save to Drive
Download now
Download as PDF, PPTX
1
/ 36
2
/ 36
3
/ 36
4
/ 36
5
/ 36
6
/ 36
7
/ 36
8
/ 36
9
/ 36
10
/ 36
11
/ 36
12
/ 36
13
/ 36
14
/ 36
15
/ 36
16
/ 36
17
/ 36
18
/ 36
19
/ 36
20
/ 36
More Related Content
PDF
マルチテナント化で知っておきたいデータベースのこと
by
Amazon Web Services Japan
55 slides
15.7K views
PDF
20200630 AWS Black Belt Online Seminar Amazon Cognito
by
Amazon Web Services Japan
81 slides
17.7K views
PDF
Serverless時代のJavaについて
by
Amazon Web Services Japan
90 slides
13.6K views
ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
by
pospome
119 slides
68.5K views
PPTX
初心者向けMongoDBのキホン!
by
Tetsutaro Watanabe
21 slides
53.4K views
PDF
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
by
Amazon Web Services Japan
73 slides
63.7K views
PDF
DevOps with Database on AWS
by
Amazon Web Services Japan
47 slides
42.8K views
PDF
マイクロにしすぎた結果がこれだよ!
by
mosa siru
32 slides
141K views
マルチテナント化で知っておきたいデータベースのこと
by
Amazon Web Services Japan
55 slides
15.7K views
20200630 AWS Black Belt Online Seminar Amazon Cognito
by
Amazon Web Services Japan
81 slides
17.7K views
Serverless時代のJavaについて
by
Amazon Web Services Japan
90 slides
13.6K views
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
by
pospome
119 slides
68.5K views
初心者向けMongoDBのキホン!
by
Tetsutaro Watanabe
21 slides
53.4K views
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
by
Amazon Web Services Japan
73 slides
63.7K views
DevOps with Database on AWS
by
Amazon Web Services Japan
47 slides
42.8K views
マイクロにしすぎた結果がこれだよ!
by
mosa siru
32 slides
141K views
What's hot
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
by
Takuto Wada
45 slides
174.7K views
PPTX
RLSを用いたマルチテナント実装 for Django
by
Takayuki Shimizukawa
49 slides
13.1K views
PPTX
Istioサービスメッシュ入門
by
Yoichi Kawasaki
52 slides
39.8K views
PPTX
分散システムについて語らせてくれ
by
Kumazaki Hiroki
45 slides
130.7K views
PDF
Where狙いのキー、order by狙いのキー
by
yoku0825
109 slides
44.9K views
PDF
イミュータブルデータモデル(入門編)
by
Yoshitaka Kawashima
24 slides
197.2K views
PPTX
KeycloakでAPI認可に入門する
by
Hitachi, Ltd. OSS Solution Center.
49 slides
5.1K views
PDF
シリコンバレーの「何が」凄いのか
by
Atsushi Nakada
77 slides
189.8K views
PDF
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
by
NTT DATA Technology & Innovation
84 slides
3.6K views
PDF
Dockerからcontainerdへの移行
by
Kohei Tokunaga
36 slides
19.4K views
PDF
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
by
Takuto Wada
89 slides
74.2K views
PDF
オンプレML基盤on Kubernetes 〜Yahoo! JAPAN AIPF〜
by
Yahoo!デベロッパーネットワーク
35 slides
2K views
PDF
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
by
NTT DATA Technology & Innovation
56 slides
7.8K views
PDF
イミュータブルデータモデルの極意
by
Yoshitaka Kawashima
28 slides
29.1K views
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
by
Masahito Zembutsu
96 slides
37.4K views
PPTX
え、まって。その並列分散処理、Kafkaのしくみでもできるの? Apache Kafkaの機能を利用した大規模ストリームデータの並列分散処理
by
NTT DATA Technology & Innovation
35 slides
14.3K views
PDF
分散トレーシング技術について(Open tracingやjaeger)
by
NTT Communications Technology Development
25 slides
24.2K views
PDF
AWSのログ管理ベストプラクティス
by
Akihiro Kuwano
57 slides
79.8K views
PDF
開発速度が速い #とは(LayerX社内資料)
by
mosa siru
18 slides
71.3K views
PDF
20190206 AWS Black Belt Online Seminar Amazon SageMaker Basic Session
by
Amazon Web Services Japan
71 slides
13.9K views
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
by
Takuto Wada
45 slides
174.7K views
RLSを用いたマルチテナント実装 for Django
by
Takayuki Shimizukawa
49 slides
13.1K views
Istioサービスメッシュ入門
by
Yoichi Kawasaki
52 slides
39.8K views
分散システムについて語らせてくれ
by
Kumazaki Hiroki
45 slides
130.7K views
Where狙いのキー、order by狙いのキー
by
yoku0825
109 slides
44.9K views
イミュータブルデータモデル(入門編)
by
Yoshitaka Kawashima
24 slides
197.2K views
KeycloakでAPI認可に入門する
by
Hitachi, Ltd. OSS Solution Center.
49 slides
5.1K views
シリコンバレーの「何が」凄いのか
by
Atsushi Nakada
77 slides
189.8K views
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
by
NTT DATA Technology & Innovation
84 slides
3.6K views
Dockerからcontainerdへの移行
by
Kohei Tokunaga
36 slides
19.4K views
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
by
Takuto Wada
89 slides
74.2K views
オンプレML基盤on Kubernetes 〜Yahoo! JAPAN AIPF〜
by
Yahoo!デベロッパーネットワーク
35 slides
2K views
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
by
NTT DATA Technology & Innovation
56 slides
7.8K views
イミュータブルデータモデルの極意
by
Yoshitaka Kawashima
28 slides
29.1K views
コンテナの作り方「Dockerは裏方で何をしているのか?」
by
Masahito Zembutsu
96 slides
37.4K views
え、まって。その並列分散処理、Kafkaのしくみでもできるの? Apache Kafkaの機能を利用した大規模ストリームデータの並列分散処理
by
NTT DATA Technology & Innovation
35 slides
14.3K views
分散トレーシング技術について(Open tracingやjaeger)
by
NTT Communications Technology Development
25 slides
24.2K views
AWSのログ管理ベストプラクティス
by
Akihiro Kuwano
57 slides
79.8K views
開発速度が速い #とは(LayerX社内資料)
by
mosa siru
18 slides
71.3K views
20190206 AWS Black Belt Online Seminar Amazon SageMaker Basic Session
by
Amazon Web Services Japan
71 slides
13.9K views
Similar to マルチテナントのアプリケーション実装〜実践編〜
PDF
AgentCoreで実現するマルチテナントAIエージェント
by
IgaHironobu
97 slides
648 views
PPT
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
by
lalha
45 slides
2.2K views
PDF
MongoDB概要:金融業界でのMongoDB
by
ippei_suzuki
52 slides
4.8K views
PPTX
Sharding with sql alchemy
by
Akira Matsuzaki
38 slides
1.5K views
PDF
ScalaMatsuri 2016
by
Yoshitaka Fujii
151 slides
7.2K views
PPTX
NoSQL Bigtable and Azure Table
by
Takekazu Omi
61 slides
9.2K views
PDF
Sansanがメッセージング (SQS) でスケーラビリティを手に入れた話
by
Atsushi Kambara
48 slides
12.1K views
PDF
Guide to Cassandra for Production Deployments
by
smdkk
85 slides
5.1K views
PDF
20120409 aws meister-reloaded-dynamo-db
by
Amazon Web Services Japan
83 slides
9.8K views
PDF
Application Architecture for Enterprise Win Store Apps with DDD Pattern
by
Atsushi Kambara
284 slides
3.1K views
PDF
単なるキャッシュじゃないよ!?infinispanの紹介
by
AdvancedTechNight
37 slides
16.8K views
PDF
DBP-016_NoSQL in Azure ~ドキュメント指向データベース Azure DocumentDB 徹底解説~
by
decode2016
54 slides
88 views
PDF
Webアプリを並行開発する際のマイグレーション戦略
by
Takayuki Shimizukawa
49 slides
5.9K views
PDF
業務システムにおけるMongoDB活用法
by
Yoshitaka Mori
33 slides
5.6K views
PDF
Lunch & Learn, AWS NoSQL Services
by
Insight Technology, Inc.
65 slides
469 views
PDF
Info talk #36
by
Hiroshi Bunya
92 slides
1.3K views
PDF
Synquery ja
by
EastCloud
22 slides
3K views
PDF
SAP HANAは 単なるインメモリーデータベースじゃなくて (賢い)アプリの開発・実行プラットフォーム
by
Makoto Sugishita
47 slides
12K views
PDF
マルチ テナント クラウド アプリケーションの設計手法
by
Kazuyuki Nomura
49 slides
6.3K views
PDF
Infinispan - Open Source Data Grid rev2
by
nekop
22 slides
1K views
AgentCoreで実現するマルチテナントAIエージェント
by
IgaHironobu
97 slides
648 views
【17-C-2】 クラウド上でのエンタープライズアプリケーション開発
by
lalha
45 slides
2.2K views
MongoDB概要:金融業界でのMongoDB
by
ippei_suzuki
52 slides
4.8K views
Sharding with sql alchemy
by
Akira Matsuzaki
38 slides
1.5K views
ScalaMatsuri 2016
by
Yoshitaka Fujii
151 slides
7.2K views
NoSQL Bigtable and Azure Table
by
Takekazu Omi
61 slides
9.2K views
Sansanがメッセージング (SQS) でスケーラビリティを手に入れた話
by
Atsushi Kambara
48 slides
12.1K views
Guide to Cassandra for Production Deployments
by
smdkk
85 slides
5.1K views
20120409 aws meister-reloaded-dynamo-db
by
Amazon Web Services Japan
83 slides
9.8K views
Application Architecture for Enterprise Win Store Apps with DDD Pattern
by
Atsushi Kambara
284 slides
3.1K views
単なるキャッシュじゃないよ!?infinispanの紹介
by
AdvancedTechNight
37 slides
16.8K views
DBP-016_NoSQL in Azure ~ドキュメント指向データベース Azure DocumentDB 徹底解説~
by
decode2016
54 slides
88 views
Webアプリを並行開発する際のマイグレーション戦略
by
Takayuki Shimizukawa
49 slides
5.9K views
業務システムにおけるMongoDB活用法
by
Yoshitaka Mori
33 slides
5.6K views
Lunch & Learn, AWS NoSQL Services
by
Insight Technology, Inc.
65 slides
469 views
Info talk #36
by
Hiroshi Bunya
92 slides
1.3K views
Synquery ja
by
EastCloud
22 slides
3K views
SAP HANAは 単なるインメモリーデータベースじゃなくて (賢い)アプリの開発・実行プラットフォーム
by
Makoto Sugishita
47 slides
12K views
マルチ テナント クラウド アプリケーションの設計手法
by
Kazuyuki Nomura
49 slides
6.3K views
Infinispan - Open Source Data Grid rev2
by
nekop
22 slides
1K views
マルチテナントのアプリケーション実装〜実践編〜
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 ● アプリケーション実装でのテナントデータの論理的な分離を行う方針を取っていま す. ○ データベースやミドルウェアでの制御でも, ポリシー × ユーザーでのロジック 実装部分は避けられないと思います. ● 開発/テスト/デプロイのコストの低さやロックインを避けれるなどメリットはあります. ○ その反面, アプリ側でのガードレール実装の重要度は高くなります. ● 安全かつ開発スピードも落ちない仕組みの改善は進めていきます. まとめ