Slide 1

Slide 1 text

Ϛϧνςφϯτɾ΢ΣϒΞϓ Ϧέʔγϣϯͷ࣮ફ #railsdm 2017/12/08 by @__gfx__ (FUJI Goro)

Slide 2

Slide 2 text

ࣗݾ঺հ • ౻ ޗ࿠ (@__gfx__) • Bit JourneyͰKibelaͱ͍͏৘ใڞ༗πʔϧΛ։ൃத • TypeScript, GraphQL, React Native͋ͨΓʹڵຯ͋ Γ • ࠓճ࿩͢ͷ͸Kibelaͷཪଆʹ͍ͭͯ

Slide 3

Slide 3 text

͜͜ͰҰݴ: GraphQL͸͍͍ͧ • RESTful API ͷ୅ସͱͯ͠࡞ΒΕͨRPC࢓༷ • RESTfulϥΠΫͳϦιʔεࢦ޲ͱRPCͷܕ҆શੑͷ͍͍ͱ͜ͲΓ • υΩϡϝϯτγεςϜ΋಺แ͍ͯͯ͠API console͕࠷ߴͷ࢓্͕Γ • KibelaͷWeb API͸GraphQLΛ࠾༻ • ಺෦API͸ঃʑʹஔ͖׵͑த • ެ։API΋GraphQLʹ͢Δ༧ఆ

Slide 4

Slide 4 text

Kibela

Slide 5

Slide 5 text

Kibelaʹ͍ͭͯ

Slide 6

Slide 6 text

αʔϏεͱͯ͠ͷKibela • BtoBͷSaaS: Software as a Service • BlogʢʹݸਓͷΞΠσΞʣͱWikiʢʹ૊৫ͷͨΊͷ৘ใʣͱ͍ ͏̎ͭͷੑ࣭ͷυΩϡϝϯτΛॻ͚Δͷ͕ಛ௃ͷ৘ใ ڞ༗πʔϧ • GitHubޓ׵ͷMarkdown (≒CommonMark)Ͱॻ͚Δ • ڝ߹: Confluence, Google Docs

Slide 7

Slide 7 text

Ϛϧνςφϯτɾ΢ΣϒΞϓϦ • ࠓճͷςʔϚʮϚϧνςφϯτɾ΢ΣϒΞϓϦ (MTWA)ʯ͸ɺSaaSʹ͓͍ͯ1ͭͷγεςϜͰ෮਺ͷ૊৫ ʢ㲈اۀɾஂମʣͷνʔϜΛಉډͤ͞Δ΢ΣϒΞϓϦέʔ γϣϯ • ͜ͷτʔΫʹ͓͍ͯ͸ʮMTWAͰ͋Δ͜ͱʯΛ୯ʹʮϚ ϧνςφϯγʔʯͱ΋͍͏ • Kibela͸ςφϯτΛʮνʔϜʯͱݺͼ૊৫୯Ґͱ͍ͯ͠Δ

Slide 8

Slide 8 text

BtoBͷ΢ΣϒαʔϏε㲈MTWA • ͜ͷτʔΫͰMTWAͱ͍͏ͱ͖͸ “BtoBͷ΢Σϒ αʔϏε” ͱ΄΅౳Ձ • اۀͳͲͷஂମͷ୯ҐͰ͋Δςφϯτʹ෮਺ͷ ϢʔβʔΞΧ΢ϯτ͕ॴଐ͢Δܥ͸͢΂ͯMTWA • গ਺ͷαʔόʔΠϯελϯεͰଟ਺ͷސ٬ʹαʔ ϏεΛఏڙͰ͖ΔͨΊίεύ͕Α͍

Slide 9

Slide 9 text

Ϛϧνςφϯγʔͷڞ༗Ϩϕϧ • Ҿ༻: Web ΞϓϦέʔγϣϯΛϚϧνςφϯτܕ SaaS ιϦϡʔγϣϯʹม׵͢Δ - IBM https://www.ibm.com/developerworks/jp/cloud/library/cl-multitenantsaas/ 1. ϋʔυ΢ΣΞͱϏδωεϩδοΫͷΈͷڞ༗ 2. (1)ʹՃ͑ͯΞϓϦέʔγϣϯϓϩηεͷڞ༗ 3. (2)ʹՃ͑ͯσʔλϕʔεͷڞ༗

Slide 10

Slide 10 text

MTWAͷઃܭͱ࣮૷

Slide 11

Slide 11 text

Ϛϧνςφϯγʔͷઃܭ • ΞΧ΢ϯτͷڞ༗Ϩϕϧͷઃܭ • URLͷ໊લۭؒͷઃܭ • ετϨʔδͷ໊લۭؒͷઃܭ • ໊લۭؒΛอূ͢ΔͨΊͷ࢓૊Έͷઃܭ

Slide 12

Slide 12 text

Kibela͸ (3) DBͷڞ༗ • ڞ༗Ͱ͖ΔϦιʔε͸͢΂ͯڞ༗ • ʮ࠷΋ޮ཰తͳਅͷϚϧνςφϯγʔʯ • by IBM • ͨͩ͠Kibelaͷ৔߹ɺPostgreSQLͷschemaʹ ΑͬͯRDBMSͷ໊લۭؒ͸෼཭͍ͯ͠Δʢޙड़ʣ

Slide 13

Slide 13 text

MTWAͷΞΧ΢ϯτϞσϧ • Ϛϧνςφϯγʔʹ͓͍ͯΞΧ΢ϯτϞσϧ͸2छྨ͋Δ • αʔϏεશମͰΞΧ΢ϯτΛڞ༗͢Δ • ྫ: GitHub, npmjs.org • ςφϯτ͝ͱʹΞΧ΢ϯτΛ࡞੒͢Δ • ྫ: Slack, G Suite, Kibela

Slide 14

Slide 14 text

GitHubܕ - ΞΧ΢ϯτ͸άϩʔόϧ • GitHubܕ͸ʮਓʯʹϑΥʔΧεͨ͠ΞΧ΢ϯτϞσϧ • ݸਓΞΧ΢ϯτͱ࢓ࣄΞΧ΢ϯτͷ۠ผ͕ᐆດʹͳΓ͕ͪ • GitHubͷ৔߹ɺ࢓ࣄͷ࣮੷Λݸਓͷ࣮੷ʹඥ෇͚΍͍͢ϝ Ϧοτ͸͋Δ • ϋϯυϧωʔϜ͔͠ެ։ͯ͠ͳ͍ΞΧ΢ϯτ͕୭͔ͩΘ͔Βͳ ͘ͳΓ͕ͪ • ؅ཧ୆ா…

Slide 15

Slide 15 text

Slackܕ - ςφϯτ͝ͱʹΞΧ΢ϯτΛ࡞੒ • Ϛϧνςφϯγʔͱͯ͠͸ͪ͜Β͕ඪ४త • ΞΧ΢ϯτ؅ཧ͕ϢʔβʔʹҕͶΒΕͯ൥ࡶʹͳΓ͕ͪ • ྫ: ͍·ௐ΂ͨΒ1passwordͷதʹslack account͕20 ݸҎ্͋ͬͨ • G Suite SSOͳͲͰҰݩ؅ཧ͢Ε͹ݸਓ͕ΞΧ΢ϯτ؅ ཧ͢Δඞཁ͸ͳ͘ͳΔ

Slide 16

Slide 16 text

Kibelaͷܾఆ: Slackܕ • GitHubܕͷʮ୭͔ͩΘ͔Βͳ͍໰୊ʯ͕໽հ͗͢Δ • ͲͷςφϯτͰ΋ಉ໊͡લʢ㲈ຊ໊ʣ͕ڧཁ͞ΕΔ ͷ΋޷·͘͠ͳ͍ͱߟ͑ͨ • झຯ༻ͱ࢓ࣄ༻Ͱ໊લΛม͍͑ͨ͜ͱ͸͋Δ • Slackܕ͸Ϣʔβʔʹ෮਺ͷΞΧ΢ϯτ؅ཧΛڧ͍Δ ͜ͱʹͳΔ͕ɺͦ͜͸SSOͰ͋Δఔ౓ղܾͰ͖Δ

Slide 17

Slide 17 text

URLͷ໊લۭؒ: domain vs path • URLͷ໊લۭؒ: subdomainϨϕϧͰ෼཭ • $team.kibe.la ͱ͍͏υϝΠϯʹνʔϜ໊ΛؚΉܗ • ηογϣϯCookie͸νʔϜ͝ͱʹಠཱ͠ɺڞ༗͠ͳ͍ • ϩʔΧϧͰͷ։ൃ͸ϧʔϓόοΫυϝΠϯΛར༻ • $team.lvh.me:3000 ͳͲ

Slide 18

Slide 18 text

ετϨʔδͷ໊લۭؒ • RDBMS΍KVSͰ͸ςφϯτ͝ͱͷσʔλʹ໊ લۭؒΛ͚ͭͯଞͷςφϯτͷσʔλͱࠞ͡ Βͳ͍Α͏ʹ͢Δ • PostgreSQL, memcached, Redis, Elasticseach, S3, CloudFront, temporary files ͳͲετϨʔδʹؔΘΔ͢΂ͯͷ৔໘Ͱ໊લ ۭؒʹΑΔ෼཭͕ඞཁ

Slide 19

Slide 19 text

RDBMSͷ໊લۭؒ෼཭ • PostgreSQL͸ database - schema - table ͱ͍͏ ֊૚ߏ଄ • ҟͳΔschema͸ಉ໊͡લͷtableΛ࣋ͯΔ • schemaͷ୳ࡧ͸؀ڥม਺PATHͷΑ͏ʹߦΘΕΔ • ࢀߟ: https://www.postgresql.org/docs/current/static/ddl-schemas.html

Slide 20

Slide 20 text

PostgreSQLͷschemaͷઃఆ • apartment gemΛར༻ • Rackϛυϧ΢ΣΞͱͯ͠ಈ͖ɺαϒυϝΠϯΛPg schemaͱΈͳ ͯ͠ `SET search_path TO $subdomain,public` ͢Δ • subdomain = schema nameͱ͢Δ͜ͱͰɺDB઀ଓͳ͠ʹ search_pathͷઃఆ͕Ͱ͖Δ • ͦͷ͔ΘΓsubdomain (≒team name) ͷϦωʔϜ࣌ʹschema name΋ม͑Δඞཁ͕͋Δ

Slide 21

Slide 21 text

Schema͕૿͖͑ͯͯ • team͕૿͑Δͱmigrationʹ͕͔͔࣌ؒΔΑ͏ʹ ͳ͖ͬͯͨ • σʔλྔతʹ͸શવେͨ͜͠ͱͳ͍͸͕ͣͩ… • ·ͩಛʹରॲ͢Δ΄ͲͰ͸ͳ͍ͷͰ์ஔ • ͍ͣΕDBΠϯελϯεͷ෼ׂ͕ඞཁ͔΋

Slide 22

Slide 22 text

͜͜·Ͱ͸͍͍Μͩ ͜͜·Ͱ͸…

Slide 23

Slide 23 text

KVS, S3, શจݕࡧΤϯδϯ, etc. • DBͷ໊લۭؒ෼཭ঢ়ଶͱಉظ͠ͳ͍ • search_path͸PgͷίωΫγϣϯ͝ͱͷઃఆ ͷͨΊ • ϛυϧ΢ΣΞʹΑͬͯ͸ඞͣ͠΋໊લۭؒΛ αϙʔτ͍ͯ͠ͳ͍

Slide 24

Slide 24 text

ૉ๿ͳൃ૝ # models/team.rb def self.switch!(name) Apartment::Tenant.switch!(name) MemcachedNamespace.switch!(name) RedisNamespace.switch!(name) AwsS3Namespace.switch!(name) ElasticsearchNamespace.switch!(name) end

Slide 25

Slide 25 text

ݱࡏͷKibela • apartment gem͕ A::T.switch! ͚͔ͩ͠ݟͳ ͍͜ͱ͕͋ͬͯϛεΛ༠ൃ͕ͪͩͬͨ͠ • ϚϧνεϨουԽͰόάΛ༠ൃ͕ͪ͠ # models/team.rb def self.switch!(name) Apartment::Tenant.switch!(name) end

Slide 26

Slide 26 text

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}” }, }

Slide 27

Slide 27 text

Redis by redis-namespace • Redis.current = Redis::Namespace.new(…) ͕switchͩͬͨ • ͔͠͠redis.rbΛΈΔͱRedis.current͕Ϋϥεม਺ͩʂʂʂ • JobQueue͕sidekiqͳͷͰεϨουηʔϑͰͳ͍ͱ͍͚ ͳ͍ • ϞϯΩʔύονΛ͋ͯͯRedis.currentΛ࠶ఆٛ͢Δ͜ͱʹ ͨ͠

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Elasticsearch • શจݕࡧΤϯδϯ • KibelaͰ͸ϚωʔδυαʔϏεΛར༻ • e.g. Amazon Elasticserach Service • ༻ޠ: index = DBͷtable, document = row

Slide 30

Slide 30 text

Elasticsearch namespacing v1 • ౰ॳindexΛteam͝ͱʹ࡞͍ͬͯͨ • e.g “kibela-#{Rails.env}-#{team_id}-blog” • team͕૿͑ΔʹͭΕindexͷ࠶ߏங ʢ㲈migrationʣʹ਺࣌ؒʢ௚ۙͩͱ9࣌ؒʣ͔͔ΔΑ ͏ʹ…

Slide 31

Slide 31 text

Elasticsearch namespacing v2 • Railsͷ̼odel͝ͱʹͨͩ1ͭͷindexΛ࡞੒ • documentͷteam_idͰϑΟϧλϦϯά͢Δ filtered aliasΛ࡞ͬͯࢀর͢ΔΑ͏ʹͨ͠ • index࠶ߏங͸ര଎ʢ2࣌ؒʣͰऴΘΔΑ͏ʹ • ͔͠͠ϦΫΤετ͸ܹ྽ʹॏ͘ͳͬͨͷͰௐࠪத

Slide 32

Slide 32 text

ͦͷଞS3ͳͲ • ౰ॳ͸ subdomain (team name) Ͱ໊લۭؒΛ ࡞͍ͬͯͨ • renameʹରԠ͢ΔͨΊ్தͰ team id Ͱ໊લ ۭؒΛ࡞ΔΑ͏ʹมߋ

Slide 33

Slide 33 text

Analytics • schema͕େྔʹ͋ΔDBʹ෼ੳΫΤϦଧͯͳ ͍໰୊ • team_id Λ෇༩ͨ͠෼ੳDBΛόονͰ࡞੒͢ Δ͜ͱʹͨ͠

Slide 34

Slide 34 text

Testing • rspecͷbefore/afterͰςφϯτͷsetup/teardownΛ͍ͯͨ͠ Βܹ྽ʹॏ͔ͬͨʢ͋ͨΓ·͑ʣ • before(:suite) / after(:suite) Ͱςφϯτͷ४උΛ͢ΔΑ͏ʹ • namepsacingͷςετ͸ͳ͔ͳ͔೉͍͠ • ଞͷςφϯτΛ࡞ͬͯΞΫηεՄೳੑΛςετͨ͠Γ͸͢Δ • Ϛϧνςφϯγʔ x ϚϧνεϨου͸ఘΊ…

Slide 35

Slide 35 text

ࠓޙͷల։ • ςφϯτΛ·͙ͨΞΧ΢ϯτ৘ใ΋ඞཁͬΆ͍ • ୺຤͝ͱʹॴଐνʔϜ͢΂ͯʹϩάΠϯ͢Δ ͷ͕ඇৗʹ໘౗ͳͨΊ • ϚϧνεϨου x Ϛϧνςφϯτͷςετ • ·ͨ͸ϚϧνεϨουΛ׬શʹఘΊΔҰख

Slide 36

Slide 36 text

·ͱΊ • Ϛϧνςφϯγʔ͸࢓༷ΛܾΊΔͷ͕େม • URLɾΞΧ΢ϯτɾετϨʔδͳͲߟ͑Δ͜ͱ͕ଟ͍ • ಛʹετϨʔδͷ໊લۭ͕ؒ೉໰Ͱָ͍͠ʢͭΒ͍ʣ • Ϛϧνςφϯγʔʹڵຯ͋Ε͹ @__gfx__ ʹDM͍ͩ͘͞ • We are hiring!