Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
マルチテナント・ウェブアプリケーションの実践
Search
FUJI Goro
December 09, 2017
Technology
14
9.5k
マルチテナント・ウェブアプリケーションの実践
Kibelaのマルチテンシーを解説します。 #railsdm 2017 の資料です。
FUJI Goro
December 09, 2017
Tweet
Share
More Decks by FUJI Goro
See All by FUJI Goro
How to Boost Your Code with WebAssembly
gfx
2
2.8k
AssemblyScriptでライブラリコードの高速化をしてみる
gfx
5
3k
実践TypeScriptトークバトル
gfx
1
1.1k
歴史的経緯の説明 as code
gfx
7
2.7k
Elasticsearchによる 全文検索の実装 in Rails
gfx
6
9.4k
すばらしきGraphQLのSEKAIへようこそ
gfx
20
9.2k
How to choose the ORM on Android
gfx
1
4.2k
How Do We Get Along With Static Types
gfx
5
3.3k
"OSSにコントリビュート" なんてしてる場合じゃない!
gfx
21
15k
Other Decks in Technology
See All in Technology
Snykで始めるセキュリティ担当者とSREと開発者が楽になる脆弱性対応 / Getting started with Snyk Vulnerability Response
yamaguchitk333
2
180
【re:Invent 2024 アプデ】 Prompt Routing の紹介
champ
0
140
20241220_S3 tablesの使い方を検証してみた
handy
3
220
生成AIをより賢く エンジニアのための RAG入門 - Oracle AI Jam Session #20
kutsushitaneko
4
210
LINE Developersプロダクト(LIFF/LINE Login)におけるフロントエンド開発
lycorptech_jp
PRO
0
120
ハイテク休憩
sat
PRO
2
120
LINEスキマニにおけるフロントエンド開発
lycorptech_jp
PRO
0
330
ゼロから創る横断SREチーム 挑戦と進化の軌跡
rvirus0817
2
260
新機能VPCリソースエンドポイント機能検証から得られた考察
duelist2020jp
0
210
ガバメントクラウドのセキュリティ対策事例について
fujisawaryohei
0
530
OpenShift Virtualizationのネットワーク構成を真剣に考えてみた/OpenShift Virtualization's Network Configuration
tnk4on
0
130
Snowflake女子会#3 Snowpipeの良さを5分で語るよ
lana2548
0
220
Featured
See All Featured
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2k
The Invisible Side of Design
smashingmag
298
50k
How to Ace a Technical Interview
jacobian
276
23k
How GitHub (no longer) Works
holman
311
140k
Thoughts on Productivity
jonyablonski
67
4.4k
Producing Creativity
orderedlist
PRO
341
39k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Raft: Consensus for Rubyists
vanstee
137
6.7k
The Cult of Friendly URLs
andyhume
78
6.1k
Facilitating Awesome Meetings
lara
50
6.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
Transcript
ϚϧνςφϯτɾΣϒΞϓ Ϧέʔγϣϯͷ࣮ફ #railsdm 2017/12/08 by @__gfx__ (FUJI Goro)
ࣗݾհ • ౻ ޗ (@__gfx__) • Bit JourneyͰKibelaͱ͍͏ใڞ༗πʔϧΛ։ൃத • TypeScript,
GraphQL, React Native͋ͨΓʹڵຯ͋ Γ • ࠓճ͢ͷKibelaͷཪଆʹ͍ͭͯ
͜͜ͰҰݴ: GraphQL͍͍ͧ • RESTful API ͷସͱͯ͠࡞ΒΕͨRPC༷ • RESTfulϥΠΫͳϦιʔεࢦͱRPCͷܕ҆શੑͷ͍͍ͱ͜ͲΓ • υΩϡϝϯτγεςϜแ͍ͯͯ͠API
console͕࠷ߴͷ্͕Γ • KibelaͷWeb APIGraphQLΛ࠾༻ • ෦APIঃʑʹஔ͖͑த • ެ։APIGraphQLʹ͢Δ༧ఆ
Kibela
Kibelaʹ͍ͭͯ
αʔϏεͱͯ͠ͷKibela • BtoBͷSaaS: Software as a Service • BlogʢʹݸਓͷΞΠσΞʣͱWikiʢʹ৫ͷͨΊͷใʣͱ͍ ͏̎ͭͷੑ࣭ͷυΩϡϝϯτΛॻ͚Δͷ͕ಛͷใ
ڞ༗πʔϧ • GitHubޓͷMarkdown (≒CommonMark)Ͱॻ͚Δ • ڝ߹: Confluence, Google Docs
ϚϧνςφϯτɾΣϒΞϓϦ • ࠓճͷςʔϚʮϚϧνςφϯτɾΣϒΞϓϦ (MTWA)ʯɺSaaSʹ͓͍ͯ1ͭͷγεςϜͰ෮ͷ৫ ʢ㲈اۀɾஂମʣͷνʔϜΛಉډͤ͞ΔΣϒΞϓϦέʔ γϣϯ • ͜ͷτʔΫʹ͓͍ͯʮMTWAͰ͋Δ͜ͱʯΛ୯ʹʮϚ ϧνςφϯγʔʯͱ͍͏ •
KibelaςφϯτΛʮνʔϜʯͱݺͼ৫୯Ґͱ͍ͯ͠Δ
BtoBͷΣϒαʔϏε㲈MTWA • ͜ͷτʔΫͰMTWAͱ͍͏ͱ͖ “BtoBͷΣϒ αʔϏε” ͱ΄΅Ձ • اۀͳͲͷஂମͷ୯ҐͰ͋Δςφϯτʹ෮ͷ ϢʔβʔΞΧϯτ͕ॴଐ͢Δܥͯ͢MTWA •
গͷαʔόʔΠϯελϯεͰଟͷސ٬ʹαʔ ϏεΛఏڙͰ͖ΔͨΊίεύ͕Α͍
Ϛϧνςφϯγʔͷڞ༗Ϩϕϧ • Ҿ༻: Web ΞϓϦέʔγϣϯΛϚϧνςφϯτܕ SaaS ιϦϡʔγϣϯʹม͢Δ - IBM https://www.ibm.com/developerworks/jp/cloud/library/cl-multitenantsaas/
1. ϋʔυΣΞͱϏδωεϩδοΫͷΈͷڞ༗ 2. (1)ʹՃ͑ͯΞϓϦέʔγϣϯϓϩηεͷڞ༗ 3. (2)ʹՃ͑ͯσʔλϕʔεͷڞ༗
MTWAͷઃܭͱ࣮
Ϛϧνςφϯγʔͷઃܭ • ΞΧϯτͷڞ༗Ϩϕϧͷઃܭ • URLͷ໊લۭؒͷઃܭ • ετϨʔδͷ໊લۭؒͷઃܭ • ໊લۭؒΛอূ͢ΔͨΊͷΈͷઃܭ
Kibela (3) DBͷڞ༗ • ڞ༗Ͱ͖ΔϦιʔεͯ͢ڞ༗ • ʮ࠷ޮతͳਅͷϚϧνςφϯγʔʯ • by IBM
• ͨͩ͠Kibelaͷ߹ɺPostgreSQLͷschemaʹ ΑͬͯRDBMSͷ໊લۭ͍ؒͯ͠Δʢޙड़ʣ
MTWAͷΞΧϯτϞσϧ • Ϛϧνςφϯγʔʹ͓͍ͯΞΧϯτϞσϧ2छྨ͋Δ • αʔϏεશମͰΞΧϯτΛڞ༗͢Δ • ྫ: GitHub, npmjs.org •
ςφϯτ͝ͱʹΞΧϯτΛ࡞͢Δ • ྫ: Slack, G Suite, Kibela
GitHubܕ - ΞΧϯτάϩʔόϧ • GitHubܕʮਓʯʹϑΥʔΧεͨ͠ΞΧϯτϞσϧ • ݸਓΞΧϯτͱࣄΞΧϯτͷ۠ผ͕ᐆດʹͳΓ͕ͪ • GitHubͷ߹ɺࣄͷ࣮Λݸਓͷ࣮ʹඥ͚͍͢ϝ Ϧοτ͋Δ
• ϋϯυϧωʔϜ͔͠ެ։ͯ͠ͳ͍ΞΧϯτ͕୭͔ͩΘ͔Βͳ ͘ͳΓ͕ͪ • ཧா…
Slackܕ - ςφϯτ͝ͱʹΞΧϯτΛ࡞ • Ϛϧνςφϯγʔͱͯͪ͜͠Β͕ඪ४త • ΞΧϯτཧ͕ϢʔβʔʹҕͶΒΕͯࡶʹͳΓ͕ͪ • ྫ: ͍·ௐͨΒ1passwordͷதʹslack
account͕20 ݸҎ্͋ͬͨ • G Suite SSOͳͲͰҰݩཧ͢Εݸਓ͕ΞΧϯτ ཧ͢Δඞཁͳ͘ͳΔ
Kibelaͷܾఆ: Slackܕ • GitHubܕͷʮ୭͔ͩΘ͔Βͳ͍ʯ͕հ͗͢Δ • ͲͷςφϯτͰಉ໊͡લʢ㲈ຊ໊ʣ͕ڧཁ͞ΕΔ ͷ·͘͠ͳ͍ͱߟ͑ͨ • झຯ༻ͱࣄ༻Ͱ໊લΛม͍͑ͨ͜ͱ͋Δ •
SlackܕϢʔβʔʹ෮ͷΞΧϯτཧΛڧ͍Δ ͜ͱʹͳΔ͕ɺͦ͜SSOͰ͋ΔఔղܾͰ͖Δ
URLͷ໊લۭؒ: domain vs path • URLͷ໊લۭؒ: subdomainϨϕϧͰ • $team.kibe.la ͱ͍͏υϝΠϯʹνʔϜ໊ΛؚΉܗ
• ηογϣϯCookieνʔϜ͝ͱʹಠཱ͠ɺڞ༗͠ͳ͍ • ϩʔΧϧͰͷ։ൃϧʔϓόοΫυϝΠϯΛར༻ • $team.lvh.me:3000 ͳͲ
ετϨʔδͷ໊લۭؒ • RDBMSKVSͰςφϯτ͝ͱͷσʔλʹ໊ લۭؒΛ͚ͭͯଞͷςφϯτͷσʔλͱࠞ͡ Βͳ͍Α͏ʹ͢Δ • PostgreSQL, memcached, Redis, Elasticseach,
S3, CloudFront, temporary files ͳͲετϨʔδʹؔΘΔͯ͢ͷ໘Ͱ໊લ ۭؒʹΑΔ͕ඞཁ
RDBMSͷ໊લۭؒ • PostgreSQL database - schema - table ͱ͍͏ ֊ߏ
• ҟͳΔschemaಉ໊͡લͷtableΛ࣋ͯΔ • schemaͷ୳ࡧڥมPATHͷΑ͏ʹߦΘΕΔ • ࢀߟ: https://www.postgresql.org/docs/current/static/ddl-schemas.html
PostgreSQLͷschemaͷઃఆ • apartment gemΛར༻ • RackϛυϧΣΞͱͯ͠ಈ͖ɺαϒυϝΠϯΛPg schemaͱΈͳ ͯ͠ `SET search_path
TO $subdomain,public` ͢Δ • subdomain = schema nameͱ͢Δ͜ͱͰɺDBଓͳ͠ʹ search_pathͷઃఆ͕Ͱ͖Δ • ͦͷ͔ΘΓsubdomain (≒team name) ͷϦωʔϜ࣌ʹschema nameม͑Δඞཁ͕͋Δ
Schema͕૿͖͑ͯͯ • team͕૿͑Δͱmigrationʹ͕͔͔࣌ؒΔΑ͏ʹ ͳ͖ͬͯͨ • σʔλྔతʹશવେͨ͜͠ͱͳ͍͕ͣͩ… • ·ͩಛʹରॲ͢Δ΄ͲͰͳ͍ͷͰ์ஔ • ͍ͣΕDBΠϯελϯεͷׂ͕ඞཁ͔
͜͜·Ͱ͍͍Μͩ ͜͜·Ͱ…
KVS, S3, શจݕࡧΤϯδϯ, etc. • DBͷ໊લۭؒঢ়ଶͱಉظ͠ͳ͍ • search_pathPgͷίωΫγϣϯ͝ͱͷઃఆ ͷͨΊ •
ϛυϧΣΞʹΑͬͯඞ໊ͣ͠લۭؒΛ αϙʔτ͍ͯ͠ͳ͍
ૉͳൃ # models/team.rb def self.switch!(name) Apartment::Tenant.switch!(name) MemcachedNamespace.switch!(name) RedisNamespace.switch!(name) AwsS3Namespace.switch!(name) ElasticsearchNamespace.switch!(name)
end
ݱࡏͷKibela • apartment gem͕ A::T.switch! ͚͔ͩ͠ݟͳ ͍͜ͱ͕͋ͬͯϛεΛ༠ൃ͕ͪͩͬͨ͠ • ϚϧνεϨουԽͰόάΛ༠ൃ͕ͪ͠ #
models/team.rb def self.switch!(name) Apartment::Tenant.switch!(name) end
Memcached for Rails Cache • namespaceϦΫΤετ͝ͱʹҟͳΔͷͰɺProcͱ ໊ͯ͠લۭؒߏஙϧʔνϯΛ͢ඞཁ͕͋Δ • Rails.cacheͷૢ࡞ͷͨͼʹຖճnamespace callback
͕ݺΕͯจࣈྻߏங͕Δ # config/environments/production.rb config.cache_store = :dalli_store, elasticache, { namespace: -> { “k-#{Team.current_subdomain}” }, }
Redis by redis-namespace • Redis.current = Redis::Namespace.new(…) ͕switchͩͬͨ • ͔͠͠redis.rbΛΈΔͱRedis.current͕Ϋϥεมͩʂʂʂ
• JobQueue͕sidekiqͳͷͰεϨουηʔϑͰͳ͍ͱ͍͚ ͳ͍ • ϞϯΩʔύονΛ͋ͯͯRedis.currentΛ࠶ఆٛ͢Δ͜ͱʹ ͨ͠
monekey_patches/redis.rb class Redis INSTANCE = Redis.new # @return [Redis] def
self.current RequestStore.fetch(”Redis.current/#{Team.current_subdomain}”) do if Team.current.present? Namespace.new(Team.current_subdomain, redis: INSTANCE) else INSTANCE end end def self.current=(_redis) raise "Don't use Redis.current=" end end
Elasticsearch • શจݕࡧΤϯδϯ • KibelaͰϚωʔδυαʔϏεΛར༻ • e.g. Amazon Elasticserach Service
• ༻ޠ: index = DBͷtable, document = row
Elasticsearch namespacing v1 • ॳindexΛteam͝ͱʹ࡞͍ͬͯͨ • e.g “kibela-#{Rails.env}-#{team_id}-blog” • team͕૿͑ΔʹͭΕindexͷ࠶ߏங
ʢ㲈migrationʣʹ࣌ؒʢۙͩͱ9࣌ؒʣ͔͔ΔΑ ͏ʹ…
Elasticsearch namespacing v2 • Railsͷ̼odel͝ͱʹͨͩ1ͭͷindexΛ࡞ • documentͷteam_idͰϑΟϧλϦϯά͢Δ filtered aliasΛ࡞ͬͯࢀর͢ΔΑ͏ʹͨ͠ •
index࠶ߏஙരʢ2࣌ؒʣͰऴΘΔΑ͏ʹ • ͔͠͠ϦΫΤετܹʹॏ͘ͳͬͨͷͰௐࠪத
ͦͷଞS3ͳͲ • ॳ subdomain (team name) Ͱ໊લۭؒΛ ࡞͍ͬͯͨ • renameʹରԠ͢ΔͨΊ్தͰ
team id Ͱ໊લ ۭؒΛ࡞ΔΑ͏ʹมߋ
Analytics • schema͕େྔʹ͋ΔDBʹੳΫΤϦଧͯͳ ͍ • team_id Λ༩ͨ͠ੳDBΛόονͰ࡞͢ Δ͜ͱʹͨ͠
Testing • rspecͷbefore/afterͰςφϯτͷsetup/teardownΛ͍ͯͨ͠ Βܹʹॏ͔ͬͨʢ͋ͨΓ·͑ʣ • before(:suite) / after(:suite) Ͱςφϯτͷ४උΛ͢ΔΑ͏ʹ •
namepsacingͷςετͳ͔ͳ͔͍͠ • ଞͷςφϯτΛ࡞ͬͯΞΫηεՄೳੑΛςετͨ͠Γ͢Δ • Ϛϧνςφϯγʔ x ϚϧνεϨουఘΊ…
ࠓޙͷల։ • ςφϯτΛ·͙ͨΞΧϯτใඞཁͬΆ͍ • ͝ͱʹॴଐνʔϜͯ͢ʹϩάΠϯ͢Δ ͷ͕ඇৗʹ໘ͳͨΊ • ϚϧνεϨου x Ϛϧνςφϯτͷςετ
• ·ͨϚϧνεϨουΛશʹఘΊΔҰख
·ͱΊ • Ϛϧνςφϯγʔ༷ΛܾΊΔͷ͕େม • URLɾΞΧϯτɾετϨʔδͳͲߟ͑Δ͜ͱ͕ଟ͍ • ಛʹετϨʔδͷ໊લۭ͕ؒͰָ͍͠ʢͭΒ͍ʣ • Ϛϧνςφϯγʔʹڵຯ͋Ε @__gfx__
ʹDM͍ͩ͘͞ • We are hiring!