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
スケール可能で運用しやすいWebSocketサーバ設計の課題と工夫 / The develop...
Search
mackee
August 23, 2018
20k
11
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
スケール可能で運用しやすいWebSocketサーバ設計の課題と工夫 / The development of scalable and operating friendly WebSocket Server
CEDEC 2018
mackee
August 23, 2018
More Decks by mackee
See All by mackee
Go1.27で導入されるジェネリクスメソッドでできること
mackee
0
140
perlをWebAssembly上で動かすと何が嬉しいの??? / Where does Perl-on-Wasm actually make sense?
mackee
0
990
Agentに至る道 〜なぜLLMは自動でコードを書けるようになったのか〜
mackee
6
5.9k
今!ソフトウェアエンジニアがハードウェアに手を出すには
mackee
14
7.1k
ワンバイナリWebサービスのススメ
mackee
10
8.8k
tanukistack ライブコーディング / tanukistack live-coding
mackee
0
680
range over funcの使い道と非同期N+1リゾルバーの夢 / about a range over func
mackee
0
1.2k
perl for shell, awk and sed programmers
mackee
3
2.8k
今更GoのWebフレームワークを作ろうとしているワケ / Why am I trying to create a Go web framework now?
mackee
1
1.1k
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.3k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
200
SEO for Brand Visibility & Recognition
aleyda
0
4.6k
Marketing to machines
jonoalderson
1
5.5k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Limits of Empathy - UXLibs8
cassininazir
1
360
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
580
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Paper Plane
katiecoart
PRO
1
51k
Typedesign – Prime Four
hannesfritz
42
3.1k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Transcript
εέʔϧՄೳͰ ӡ༻͍͢͠ WebSocketαʔόઃܭͷ ՝ͱ CEDEC 2018 ໘ന๏ਓΧϠοΫɹ୩ ਅۏ
͜ͷηογϣϯͰ͢͜ͱ • ैདྷͷWebΞϓϦέʔγϣϯͷ࡞ΓํͷԆઢ্Ͱ • ϛυϧΣΞΛ͚Ճ͑ΔܗͰWebSocketʹΑΔϦΞϧ λΠϜ௨৴Λ༻͍Δ • ήʔϜαʔόΛ։ൃɾӡ༻ͯ͠Έͨ ͦͷ࣌ͷͱۤ࿑Λ͠·͢ɻ
͜ͷηογϣϯͰ͞ΕΔ͜ͱ ౦ژϓϦζϯ1ͱ͍͏ϞόΠϧήʔϜͷࣄྫͰ͢ 1 https://tokyo-prison.kayac.com/
ήʔϜͷಛੑ • λʔϯ੍ɻλʔϯҰఆඵ͕ܦա͢Δͱऴྃ͢Δɻλʔϯ ͋Δఔࣗ༝ʹಈ͚Δ
ήʔϜͷಛੑ • ϓϨΠϠʔ3ਓ vs ϓϨΠϠʔ3ਓ
ߨԋऀͷόοΫάϥϯυ • ໘ന๏ਓΧϠοΫ ιʔγϟϧήʔϜࣄۀ෦ • αʔόαΠυΛઐͰ୲ɻΞϓϦέʔγϣϯίʔυΛॻ͕͘ ΠϯϑϥߏஙΓɺӡ༻Δ • झຯPerlͱ3DϓϦϯλվͱϛυϧΣΞ։ൃ
ैདྷͷWebΞϓϦͰ ΞʔΩςΫνϟͰ WebSocketΛ༻͍Δͱ͖ͷ՝
આ໌ͷॱ൪ 1. ैདྷͷWebΞϓϦͷߏ 2. WebSocketΛ࢝Ίͱͨ͠ੜଘ࣌ؒͷ͍ηογϣϯΛѻ͏্Ͱ ͷ 3. ղܾํ๏(kuiperbeltͷհ)
͜͜Ͱ͍͏WebΞϓϦͱ • ΠϯλʔωοτΛ௨ͬͯओʹHTTPΛ͏ ΞϓϦέʔγϣϯ • HTTP·ͣϦΫΤετ͋Γ͖
ͳͥHTTPΛ͏ͷ͔ • ͍͍ͩͨͷWebϑϨʔϜϫʔΫHTTPΛѻ͏ͨΊʹ࡞ΒΕ͍ͯ Δ • curlΛ͡Ίͱͨ͠HTTPΛσόοά͢ΔͨΊͷπʔϧݟ͕ ੈͷதʹ͋;Ε͍ͯΔ • HTTPεςʔτϨε͕લఏͷϓϩτίϧͳͷͰεέʔϧͤ͞Δ ͷʹ༗ར(ޙड़)
εςʔτϨε͔ͩΒԣʹ૿ͤΔ Keep-AliveͰTCPଓ͍ճ͠Λߦ͏߹͋Δ͕ɺHTTPͷ͔ΒݟΕಉ͡
εςʔτϨε͔ͩΒԣʹ૿ͤΔ
Ϣʔβಉ࣌ʹϦΫΤετΛड͚͍ͯΔ͜ ͱͳ͍
WebΞϓϦέʔγϣϯͷੈք • HTTP͕εςʔτϨεͳͷͰԣʹಉ͡ΞϓϦΛฒͯLBʹೖΕ Δ • ෛՙࢄͱHAత • Lightweight Language(PHPRuby2ͳͲ)͕ΘΕΔ͜ͱ͕͋Δ •
͜ΕΒϚϧνϓϩηεϞσϧ͕ओྲྀ 2 ͪΖΜJavaC#ͰΉͱ͜Ζ͋ΓɺͦΕΒϚϧνεϨου
ϦΞϧλΠϜ௨৴ΛWebͷԆͰΔબࢶ • Long Polling • WebSocket • WebRTC DataChannel •
͋Δ͍ੜιέοτ
ͳͥWebSocketΛ͏ͷ͔ => ͍ͷʹר͔Εͨ΄͏ָ͕͕Ͱ͖Δ • 2011ʹඪ४ࡦఆ͞Ε͔ͯΒ͕࣌ؒܦͪϥΠϒϥϦ͕ރΕ͍ͯ Δ • ੜιέοτͱҧͬͯϥΠϒϥϦΛࣗͰॻ͔ͳͯ͘Α͍ • wscatΛ࢝Ίͱͨ͠σόοάπʔϧ๛
• TCPͳͷͰ࠶ૹͳͲͷ໘ݟͯ͘ΕΔ
ͦͦͳͥඪ४Webٕज़ʹͩ͜ΘΔͷ͔ • Web։ൃऀίϛϡχςΟʹ͔ͬΕΔ • ϥΠϒϥϦݟΛٵऩͰ͖Δ • (͜ΕޙͰ͕͢)PWAήʔϜΞϓϦ࣌Λݟਾ͑ͯͷબ • ϒϥβ͑Δϓϩτίϧ͕ݶΒΕΔ
WebSocketεςʔτϑϧ௨৴ • ΫϥΠΞϯτWebAppʹରͯ͠ܨ͗ͬͺͳ͠ͷঢ়ଶʹͳΔ • WebSocketηογϣϯͷੜଘ͕͍࣌ؒͨΊͦͷؒϦ ιʔεΛઐ༗͢Δ
WebSocketଓΛҡ࣋͠ଓ͚Δඞཁ͕͋Δ
ϦΞϧλΠϜ௨৴εςʔτϑϧ௨৴ • 1ͭͷΫϥΠΞϯτ͕1WebAppΠϯελϯεͱີ݁߹͢Δ • গͳ͘ͱ1ηογϣϯͷؒॊೈͳεέʔϧΞτ(Λ ԣʹ૿͢)ϦΞϧλΠϜ௨৴͕ߦΘΕ͍ͯΔؒͷίʔυ ߋ৽(σϓϩΠ)͕͍͠
ϦΞϧλΠϜ௨৴εςʔτϑϧ௨৴ • εςʔτϑϧ௨৴ͱಉظܕPreforkͷ૬ੑͷѱ͞ • 1ݸͷϓϩηε͕1ͭͷϦΫΤετΛಉظతʹॲཧ • 1ϦΫΤετͷॲཧ͕͍࣌ؒ(ʙ1sec)͜ͱ͕લఏ • 1ϓϩηεͰ1WebSocketηογϣϯΛѲΔͱϓϩηε͠ ͔ΫϥΠΞϯτΛऩ༰Ͱ͖ͳ͍
٧·Δਤ
ࠓ·ͰͷWebΞϓϦ͕ͦͷ·· WebSocketΛΔ͜ͱ͍͜͠ͱ ͕Θ͔ͬͨ
͍͔ʹͯ͠զʑϦΞϧλΠϜ௨৴ʹཱͪ ͔͍͍͑ͷ͔ • ָͰ • Θ͔Γͯ͘͢ɺγϯϓϧͰ • εέʔϧՄೳͰ • ӡ༻͍͢͠ͷ͕΄͍͠
ͦΜͳ͏·͍ ιϦϡʔγϣϯ͋Δͷ͔
ैདྷͷWebΞʔΩςΫνϟ͕WebSocketΛ ѻ͏ͱ͖ͷ͍͠Λཧ • ࣌ؒੜ͖ଓ͚Δ௨৴ηογϣϯΛҡ࣋͢Δͷ͕͍͠ • ௨৴ͱϢʔβΛඥ͚Δͷ͕͍͠ => ͜ͷลϛυϧΣΞʹͤΔͷͲ͏͔ ֎ʹग़͢ͷϚΠΫϩαʔϏεͷߟ͑ํʹ͍͔ۙ͠Εͳ͍
WebSocketηογϣϯΛ ҡ࣋͢Δ͚ͩͷ ϛυϧΣΞ kuiperbeltͷ։ൃͱಋೖ
kuiperbeltͱ • OSSͰ͢3 • WebSocketͷηογϣϯΛड͚ͯҡ࣋͢Δ͚ͩͷ௨৴σʔϞϯ • ࠷ॳݸਓϓϩδΣΫτͰ͕ͨ͠ɺձࣾͰ͔ͳΓΘΕ͍ͯ· ͢ • ձࣾͷਓʹίϛοτͯ͠Β͍ͬͯ·͢
3 https://github.com/kuiperbelt/kuiperbelt
None
None
໊લͷ༝དྷ ఱจֶͷΤοδϫʔεɾΧΠύʔϕϧτ*͔Β * photo by NASA
kuiperbelt͕ग़དྷΔ͜ͱ • WebSocketηογϣϯͷҡ࣋ • HTTP-APIͰͷಛఆηογϣϯͷϝοηʔδͷྲྀ͠ࠐΈ • ্Γ(ΫϥΠΞϯτ->αʔό)ඇରԠ7 7 ରԠ༧ఆ͋Γ
͢͜ͱͷྲྀΕ 1. ౦ژϓϦζϯͰͷαʔόߏͷུ֓ 2. kuiperbeltΛͬͨWebSocketηογϣϯͷೝূɾϝοηʔδ ৴ 3. ઃܭࢥ 4. ࣮ࡍͷӡ༻ࣄྫ
5. ౦ژϓϦζϯͰͷ࣮ࡍͷΘΕํ
౦ژϓϦζϯͷαʔόߏ8 8 ຊ17:50ΑΓฐࣾ౻ݪͷৄ͍͠ߏͷղઆ͕͋Γ·͢
HTTPͷதͷΈͷதͰೝূΛ͢Δ • ೝূWebSocketͷΞοϓάϨʔυલʹWebAppଆʹϓϩΩ γΛߦ͏ • ϓϩΩγ࣌ʹkuiperbeltࣗͷղܾՄೳͳϗετ໊ΛՃ͢ Δ -> εέʔϧΞτʹ༻͍Δ •
WebAppଆϨεϙϯεͷϔομʹࣝผࢠΛՃ͑Δ
HTTPͷதͷΈͷதͰೝূΛ͢Δ
HTTPͷதͷΈͷதͰϝοηʔδ৴Λ ͢Δ • ΫϥΠΞϯτͷϝοηʔδϔομͰࣝผࢠΛࢦఆͯ͠ɺϘ σΟͷ༰ͦͬ͘Γͦͷ··WebSocketͷηογϣϯʹྲྀ͠ ࠐΉ • தͷϝοηʔδͷܗࣜkuiperbeltؔ༩͠ͳ͍ • ౦ژϓϦζϯόΠφϦΛྲྀͯ͠·͢
HTTPͷதͷΈͷதͰϝοηʔδ৴Λ ͢Δ
kuiperbeltࣗͷઃܭࢥ • ୯७ͳ͜ͱ͔͠Βͳ͍ͷͰམͪͳ͍ɾ࠶ىಈ͠ͳͯ͘ྑ͍ • ήʔϜϩδοΫΒͳ͍ͷͰσϓϩΠ͕ඞཁͳ͍ • Ҏ্ӡ༻͍ͯ͠Δ͕ϝϞϦϦʔΫى͖͍ͯͳ͍ • ಛఆϓϩτίϧɾϛυϧΣΞʹґଘ͠ͳ͍
ผλΠτϧͰͷোࣄྫ ͏͔ͬΓHTTP/2ࣄ݅ ݱࡏҰఆִؒͰίωΫγϣϯΛഁغ͢Δ࣮͕ೖ͍ͬͯ·͢
kuiperbeltࣗͷઃܭࢥ • GoͰॻ͔Ε͍ͯΔͷͰίΞ͚ͩͪΌΜͱεέʔϧ͢Δ • 1ίΞ͋ͨΓඵؒ10,000ϝοηʔδ͙Β͍(1ϝοηʔδ͋ͨΓ ฏۉ150bytes) • ϝϞϦྔΫϥΠΞϯτʹൺྫ͠ɺϝοηʔδͷ༰ͳͲ ʹࠨӈ͞ΕΔ͕1ສଓͰ1GBʙ1.8GB
࣮ࡍͷӡ༻Ͱ • ࣮ෛՙࢼݧͰϝοηʔδྲྀྔͱϝοηʔδαΠζ͕େ͖͍͜ͱ ͕໌ͨͨ͠Ίɺ1Πϯελϯε5000ଓఔʹ͑ͨ • m3.large4ͱr4.large5ͷspot fleetʹ͍ͯͨ͠Βm3.largeͷpps ্ݶ͕ͯ͘ภΓ͕ग़ͨͷͰr4.largeͷΈͷӡ༻ʹ͍ͯ͠Δ 5 2core
15.25GBϝϞϦ 4 2core 7.5GBϝϞϦ
ύέοτ٧·ΓΛىͯ͜͠࠶ૹ͕ߦΘΕ͍ͯ Δϩά 21:00:47 plack.1 | 1019.259 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send
| Furl:40 21:00:47 plack.1 | 3017.341 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send | Furl:40 21:00:47 plack.1 | 1017.801 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send | Furl:40 21:00:47 plack.1 | 7174.359 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send | Furl:40 21:00:47 plack.1 | 1025.966 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send | Furl:40 21:00:47 plack.1 | 10010.330 ms [Furl::HTTP] POST http://XX.XX.XX.XX:9180/send | Furl:40 1, 3, 7, 10...ͱԆ͍ͯ͠ΔͷͰ࠶ૹͰ٧·͍ͬͯΔͷͰʁ ͱ ͳͬͨ
͍ͬͯΔ͜ͱ͕γϯϓϧͳͷͰ༷ʑͳΞʔΩςΫνϟʹରԠͰ͖Δ MO͖ͷதܧ͚ͩߦ͏ΞʔΩςΫνϟ
͍ͬͯΔ͜ͱ͕γϯϓϧͳͷͰ༷ʑͳΞʔΩςΫνϟʹରԠͰ͖Δ MMOϚονϯά͖ͷαʔόͰήʔϜϩδοΫΛ࣮ߦ͢ΔΞʔΩςΫνϟ
ϦΞϧλΠϜ௨৴αʔόΛϩʔυόϥϯαʔʹΈࠐΉ Q: ෳͷαʔόΛܦ༝͢Δ͔ΒϨΠςϯγ͕ݫ͍͠ͷͰʁ A1: ϞόΠϧʹ͓͍ͯͦͷݶΓͰͳ͍ A2: λʔϯ੍ͳΒ͋Δఔڐ༰Ͱ͖Δ
A1: ϞόΠϧʹ͓͍ͯͦͷݶΓͰͳ͍ HTTP-APIΛଧ͔ͬͯΒWebSocketͰԠ͕͔͑ͬͯ͘Δ·Ͱͷ RTTΛܭଌ6 6 JavaScriptͳͷͰspectreͷӨڹͰ2msఔͷؙΊ͕ଘࡏ͍ͯ͠Δͷཹҙ
A1: ϞόΠϧʹ͓͍ͯͦͷݶΓͰͳ͍ • લ͕ݻఆޫճઢܦ༝ͷWiFi, ޙ͕4G • WiFiͩͱ20 ʙ 30ms, 4Gͩͱ75msʙ
• LBΛܦ༝͢Δ͜ͱʹΑΔϨΠςϯγ1ܻmsఔ • ϞόΠϧʹ͓͍ͯLBʹΑΔϨΠςϯγࢧతͰͳ͍
A2: λʔϯ੍ͳΒ͋Δఔڐ༰Ͱ͖Δ • ͜Ε͕PCίϯγϡʔϚͰΔΑ͏ͳFPS֨ήʔͰ͋Ε1ܻ msͷԆͰ͢Βॖ͍ͨ͠ • ڐ༰͞ΕΔԆ෯ήʔϜγεςϜʹΑͬͯมΘΔ • ཁ݅ʹΑͬͯૹΓͬͺͳ͠ʹͰ͖Δ/Φʔόʔϔου͕গͳ ͍UDPͳͲΛબ͢Δ
ݱঢ়LBʹೖΕΔϝϦοτ͕Ͱ͔͍ • TLS TerminationΛͤΔ͜ͱ͕ग़དྷΔ • ݸผʹTerminationΛ͍ͬͯΔͱূ໌ॻͷཧ͕໘ • ࠷ۙ௨Βͳ͍ϑΥϫʔυϓϩΩγ͕ݮͬͨͱ͍͑ੜ WebSocketૄ௨͢Δ͔Ͳ͏͔ͷϦεΫ͕͋Δ
ݱঢ়LBʹೖΕΔϝϦοτ͕Ͱ͔͍ • ࣗಈͰ༙͍ͨԾϚγϯ/ίϯςφʹ౸ୡՄೳͳIPΞυϨε/ϗ ετΛͲ͏ͬͯΫϥΠΞϯτʹ௨͢Δ͔ • ैདྷಉ͡ϧʔϜΛݻΊΔΑ͏ʹϚονϯά࣌ʹଓ͖͢ ΞυϨεΛࣔͨ͠Γ • LBͳΒೖΕΔ͚ͩͰ౸ୡՄೳʹͳΔɺϧʔϜͰݻΊΔΈ͍ͨ ͳͷग़དྷͳ͍͕
࣮ࡍʹΈࠐΜͰΈͯ౦ژϓϦζϯ ͲͷΑ͏ʹήʔϜΛਐߦ͍ͯ͠Δ ͔
kuiperbeltΛΈࠐΜͩ౦ژϓϦζϯͷॲཧ
kuiperbeltΛΈࠐΜͩ౦ژϓϦζϯͷॲཧ
ήʔϜϩδοΫ͕αʔόଆʹ͋Δ͜ͱͷϝ Ϧοτ • ήʔϜϩδοΫͷมߋ͕͋Δఔ༰қ ετΞਃ͕ཁΒͳ͍ • ΫϥΠΞϯτੑೳʹҾͬுΒΕͳ͍ • ΫϥΠΞϯτ։ൃऀֆΛग़͢͜ͱʹूதͰ͖Δ •
νʔτ͞Εʹ͍͘ • ϩΪϯά༰қͳͷͰղੳͳͲͰ͖Δ
ήʔϜϩδοΫ͕αʔόଆʹ͋Δ͜ͱͷσϝ Ϧοτ • ΫϥΠΞϯτ͕αʔόͷॲཧΛͭͨΊϨεϙϯγϏϦςΟ͕ ѱ͍ • αʔόͷϨεϙϯεΛͨͳ͍ͳͲͷରࡦΛߨ͍ͯ͡Δ(ඇಉ ظԽ)
ήʔϜϩδοΫ͕αʔόଆʹ͋Δ͜ͱͷσϝ Ϧοτ • αʔόͷෛՙରࡦΛेʹߦ͏ඞཁ͕͋ΔɹϦιʔε֬อ͢ Δඞཁ͕͋Δ • ఆ࣮ෛՙࢼݧͱνϡʔχϯάΛ܁Γฦ͠·͕ͨ͠ඇৗʹۤ ࿑͠·ͨ͠
ͦͷଞkuiperbeltΛಋೖͨ͜͠ͱͰݟ͖͑ͯͨ 1. ϝοηʔδ౸ୡॱ 2. αʔόؒϝοηʔδܽଛ
ϝοηʔδ౸ୡॱ kuiperbeltͷதͰϩοΫऔΕͨॱ൪ʹྲྀΕΔ
ϝοηʔδ౸ୡॱ ղ๏ • γʔέϯε൪߸Λ্ͨͤͨͰ 1. ΫϥΠΞϯτଆͰόοϑΝϦϯάͭͭ͠ฒ͢ 2. kuiperbeltଆͰόοϑΝϦϯάͭͭ͠ฒ͢
ϝοηʔδ౸ୡॱ ΫϥΠΞϯτଆͰฒ͢ͷΛ࠾༻ • kuiperbeltͰΔͱϝϞϦ༻ྔ͕૿͑Δ, ঢ়ଶ͕૿͑ͯίϯς φ͕མͪͨͱ͖ʹϝοηʔδܽଛ͕૿͑Δ • ඈͦ͏ͱͨ͠ϝοηʔδͬ͞͞ͱૹͬͯঢ়ଶΛͳ͘͢ • kuiperbeltதʹྲྀΕΔσʔλʹؔ༩͠ͳ͍ϧʔϧ
αʔόؒϝοηʔδܽଛ • HTTPͰૹΔͱܽଛ͢ΔΜ͡Όͳ͍ʁʁʁ • DC௨৴, Ϧʔδϣϯ௨৴ͳͷͰܦ࿏ͰམͪΔ͜ͱͳ͔ ͳ͔ͳ͍ • ϦτϥΠ&ΫϥΠΞϯτଆͰͷॏෳݕͳͲೖΕ͍ͯΔ •
ࠓޙcircuit breakerೖΕΔ
ͦͯ͠ӡ༻͍ͯ͠Δࠓ • αʔόͷਓ͕͋Μ·ΓWebSocketͷ͜ͱΛߟ͑ͣʹࠓ·ͰͲ͓ ΓίʔυΛॻ͚Δ • WebSocketαʔό͕ίϯςφͱϩʔυόϥϯαʔʹΑͬͯϊʔ ϝϯςͰಈ͍͍ͯΔ • ͍ͭͰίϚϯυҰൃͰεέʔϧΞτՄೳ •
WebSocketͷ͜ͱΛ͋·Γߟ͑ͣʹσϓϩΠ͕ग़དྷΔ
εέʔϧՄೳͰ ӡ༻͍͢͠ WebSocketαʔό ͕ಈ͍͍ͯΔ
·ͱΊ • ैདྷͷWebΞϓϦέʔγϣϯΞʔΩςΫνϟʹൺֱత༰қʹಋ ೖͰ͖ΔϦΞϧλΠϜ௨৴༻ϛυϧΣΞΛ࡞࣮ͬͯࡍʹຊ൪ ಋೖ͠·ͨ͠ • ଞͷطʹӡ༻தͷήʔϜʹಋೖ͢Δχʔζ͕͋ΔΑ͏ͳͷͰ ͜Ε͔Β͍͖ͬͯ·͢ • ຊ൪ӡ༻ͯ͠ΈͯɺղܾՄೳͰ͋Δ͕ɺͦͦ͜͜ͷ͍
͔ͭ͘߹ͬͨͷͰڞ༗͍͖ͤͯͨͩ͞·ͨ͠
Any Questions?