Yuki Takei(noppoMan) @Tokyo-Server-Side Swift Meetup#5 Dec, 19, 2016
Swiftʹదͨ͠αʔόʔΞʔΩςΫνϟΛ࠶ߟ࣮ͯ͠·Ͱͯ͠ΈΔYuki Takei(noppoMan) @Tokyo-Server-Side Swift Meetup#5 Dec, 19, 2016
View Slide
TSSS MeetupɺͳΜͱͿΓͷ։࠵Ͱ͢ʂ
ࣗݾհ
Swift͕OpenԽ͔ͯ͠Βɺ৭ʑͳϥΠϒϥϦΛ࡞ͬͯެ։͍ͯ͠·͢ɻ
OSS• Slimane -> Web Framework• Skelton -> Event Driven HTTP Server• Suv -> Async Net, I/O Platform (libuv based)
Slimaneͷ։ൃணख͔Βૣ͍͜ͱʹ͏1(࠷ۙ͋·Γͬͯͳ͍ͷͰ͕͢ɺɺ)
͔ͭͯɺSwift͕ຬʹLinuxͰಈ͔ͣ
Server-Side-SwiftͷΩʔϓϨΠϠʔͨͪϑϨʔϜϫʔΫͳͲͷେ෦ΛࣗલͰ࡞͍ͬͯ·ͨ͠ɻ
͔͠͠
Swift3͕ϦϦʔε͞ΕͯɺServer SideͰSwiftͷඪ४APIΛੵۃతʹ͍ͬͯ͜͏ͱ͍ͬͨྲྀΕʹͳ͖͍ͬͯͯ·͢ɻ
ͦ͜ͰɺࠓͷServe Side Swiftʹదͨ͠αʔόʔΞʔΩςΫνϟͱҰମͲΜͳͷͳͷ͔ʁ
ͦΕΛࣗͳΓʹ࠶ߟ͠ɺ࣮ͯ͠Έ·ͨ͠ɻͱ͍͏͓Ͱ͢ɻ
·ͣɺࠓճͷൃදͷωλͱͳΔϥΠϒϥϦͷ͝հͰ͢
• Swift3͕ඪ४Ͱఏڙ͢ΔAPIΛੵۃతʹͬͨωοτϫʔΫϥΠϒϥϦ• ϑϨʔϜϫʔΫͰͳ͘ɺ͋͘·ͰωοτϫʔΫϓϩάϥϛϯάڥ• جຊతʹಉظI/OͷAPIΛఏڙ (callbackΛۃྗഉআ)• ඇಉظϓϩάϥϛϯάಠࣗͷAPIΛར༻͢Δ(ޙड़)• ݱࡏHTTP(S)ɺTCPͷServer/ClientͱIP(v4, 6)ΛఏڙProrsumͱʁ
ͰૣɺSwiftʹదͨ͠αʔόʔΞʔΩςΫνϟͱԿͳͷ͔୳͍͖͍ͬͯͨͱࢥ͍·͢ɻ
ͦͷલʹɺͲΜͳछྨͷαʔόʔΞʔΩςΫνϟ͕͋ͬͨͷ͔ɺ͓͢͜͠͞Β͍Ͱ͢ɻ
දతͳαʔόʔΞʔΩςΫνϟ• ϚϧνεϨουϞσϧ• ϚϧνϓϩηεϞσϧ• Πϕϯτۦಈ• ϋΠϒϦουϞσϧ
ϚϧνεϨουϞσϧmainprocessworkerthreadworkerthreadworkerthreadclientclientclientthreadϦΫΤετຖʹthreadΛ࡞Γ(࠷ۙPool͕ओྲྀ)ɺͦͷthread্ͰϦΫΤετΛࡹ͘ɻϓϩηεͱҧ͍ϝϞϦΛڞ༗Ͱ͖ΔɻʢϩοΫʹΑΔഉଞ੍ޚඞਢʣC10K͕ʹͳͬͨɻthreadthread
ϚϧνϓϩηεϞσϧਤϚϧνεϨουʹࣅ͍ͯΔ͕ɺϓϩηεΛϑΥʔΫͯ͠ϝϞϦۭؒΛ͚ΔɻϑΥʔΫͨ͠ϓϩηεͰϦΫΤετΛࡹ͍͍ͯ͘ɻࢠؒͷ௨৴υϝΠϯιέοτΛ͏mainprocessworkerprocessforkworkerprocessworkerprocessclientclientclientforkfork
ΠϕϯτۦಈϞσϧγϯάϧίΞ্ʹΠϕϯτϧʔϓΛ࡞͠ɺιέοτϑΝΠϧγεςϜͷॻ͖ࠐΈ࣌ʹΠϕϯτ(callback)ΛൃՐ͢ΔɻγϯάϧίΞͷͨΊɺϨʔείϯσΟγϣϯdeadlockΛؾʹ͢Δඞཁ͕ແ͍͕ɺϚϧνίΞΛ׆͔͢͜ͱ͕ग़དྷͳ͍ɻC10KΛղܾͨ͠mainprocessselect, epoll, kqueueclientclientclient
ϋΠϒϦοτϞσϧΠϕϯτۦಈ+WorkerThread OR WorkerProcessϞσϧͳͲෳͷΞʔΩςΫνϟΛΈ߹Θͤͨͷ(͜ͷݴ༿͕࣮ࡏ͢Δ͔ෆ໌)Node.jsͰClusterϞδϡʔϧΛར༻͢Δ͜ͱͰɺΠϕϯτۦಈ+WorkerProcessϞσϧΛఏڙ͢Δɻ͜ΕʹΑΓɺϚϧνίΞΛ׆͔͢͜ͱ͕ՄೳͱͳΔɻmasterclientworkerworkeruv_loopuv_loopuv_looppassing fdspassing fdsforkforkclient
͜ͷɺSlimanelibuvϕʔεͷͨΊɺNode.jsͱશ͘ҰॹͷΠϕϯτۦಈ+WorkerProcessϞσϧΛ࠾༻͍ͯ͠·ͨ͠ɻ
ϋΠϒϦοτϞσϧΠϕϯτۦಈ+WorkerThread OR WorkerProcessϞσϧͳͲෳͷΞʔΩςΫνϟΛΈ߹Θͤͨͷ(͜ͷݴ༿͕࣮ࡏ͢Δ͔ෆ໌)Node.jsͰClusterϞδϡʔϧΛར༻͢Δ͜ͱͰɺΠϕϯτۦಈ+WorkerProcessϞσϧΛఏڙ͢Δɻ͜ΕʹΑΓɺϚϧνίΞΛ׆͔͢͜ͱ͕ՄೳͱͳΔɻmasterclientworkerworkeruv_loopuv_loopuv_looppassing fdspassing fdsforkforkclient͜ΕͰ͢Ͷ
ͰɺProrsumͱ͍͏ͱʁ
ProrsumͷΞʔΩςΫνϟΛඥղ͘લʹɺ·ͣSwiftͷඇಉظI/Oฒྻॲཧͷํ๏ΛֶͿඞཁ͕͋Γͦ͏Ͱ͢
SwiftͰɺiOSͳͲͰUIඳըΛࢭΊͯ͠·͏Α͏ͳॏ͍ॲཧΛॻ͘ࡍʹɺGCDͱ͍͏APIΛ͍͔ͬͯͨͱࢥ͍·͢
Grand Central Dispatch(GCD)• DispatchQueue• DispatchSource• DispatchGroup• DispatchSemaphore௨ৗΞϓϦέʔγϣϯதʹهड़͢ΔεϨουཧ༻ͷίʔυΛɺγεςϜϨϕϧͰ࣮ͨ͠ͷ (By Apple ฒߦϓϩάϥϛϯάΨΠυ)https://developer.apple.com/jp/documentation/ConcurrencyProgrammingGuide.pdfදతͳͷҎԼʁ
ཁɺThreadͷཧฒྻϓϩάϥϛϯάθϩ͔Β࣮͢ΔͱେมͳͷͰɺγεςϜଆʢLinuxͰ͋ΕϥΠϒϥϦଆʣͰ࣮ͨ͠ͷΛɺϓϩάϥϚʹ͍͘͢ఏڙ͠·͢Αͱ͍͏ͷɻ
Dispatch Queue• λεΫΛqueuingͯ͠ɺ͋ΔThread্Ͱඇಉظ/ಉظతʹ࣮ߦ͢Δ͜ͱ͕ग़དྷΔAPI• mainQueue, GlobalQueueɺϢʔβʔ࡞Queueʹ͔ΕΔ• SerialͱConcurrentͷattribute͕͋Δ• queueʹରͯ͠༏ઌॱҐͷίϯτϩʔϧ͕Մೳ• ҰͭͷQueue࣮ߦྃ·ͰϒϩοΫ͞ΕΔ
Dispatch QueueSerialTask Task TaskTask Taskqueue.async {}ConcurrentTask TaskTask TaskTask Task Task Taskqueue.async {}executingwaitingbalancing
Dispatch Source• ϑΝΠϧهड़ࢠͳͲΛࢹͯ͠ɺԿ͔ͷΠϕϯτΛػʹొࡁΈͷcallbackΛݺͼग़ͨ͢ΊͷAPI• ΠϕϯτυϦϒϯͳϓϩάϥϛϯά͕ॻ͚Δ• OSґଘͳඇಉظؔΛ͏·͘ϥοϓͯ͘͠Ε͍ͯΔ(libevʹ͍ۙ)• ίʔυΛಡΜͩΒɺMacͰkqueueΛͬͯϑΝΠϧهड़ࢠΛࢹ͍ͯͨ͠
Dispatch SourceͰࢹՄೳͳͷͷҰ෦• Timer• Signal• FileSystem• Socket• MemoryPressure
ͨͱ͑ɺϑΝΠϧͷॻ͖ࠐΈΛݕͯ͠ɺϓϩάϥϜΛ࠶ίϯύΠϧ͢ΔΑ͏ͳϓϩάϥϜͳͲ͕؆୯ʹॻ͚ΔΑ͏ʹͳΓ·͢ɻ(LinuxͰݱঢ়epoll͍ͬͯͳ͍ͨΊɺKituraࣗલͰepollΛॻ͍ͯ·ͨ͠স)
͜͜·ͰநԽ͞ΕͨAPI͕͋ΔͷͰɺGCDΛ׆͔ͨ͠ΞʔΩςΫνϟ͕SwiftͰྑͦ͞͏Ͱ͢
ͦΕΒΛ౿·͑ɺࠓճܾ·ͬͨΞʔΩςΫνϟ͕ͪ͜Β
ProrsumͷαʔόʔΞʔΩςΫνϟDispatchSource + DispatchQueueΛͬͨΠϕϯτۦಈ + WorkerThreadͷϋΠϒϦοτϞσϧmainthreadDispatchSourceͰɺlisteningSocketΛࢹQueueQueueQueueQueue QueueQueue QueueQueue QueueclientDispatchQueue(concurrent)nonblocking I/Oblocking I/O
GCDʹΑΓɺΠϕϯτۦಈϞσϧͷϚϧνίΞΛ׆͔ͤͳ͍Λ1ϓϩηε͚ͩͰղܾͰ͖·ͨ͠ɻ(CPUΛ͍Ε͍ͯͳ͍ͱ͍͏ผ͕·ͩ͋Δ…)
·ͨɺγϯάϧϓϩηεͱ͍͏͜ͱͰSlimaneʹൺͯϓϩηεཧඇৗʹ؆୯ʹ
͔͠͠ɺ·ͨ৽ͨͳ͕ൃੜ
SlimaneશͳΠϕϯτۦಈαʔόʔͩͬͨͷͰɺɺ
CallBack Hell!!
callbackͷ• ͦͦSwiftඪ४ͰඇಉظύϥμΠϜʹऑ͍ (PromiseFutureɺAsync/Await͕ݴޠػೳʹͳ͍)• ΤϥʔϋϯυϦϯά͕͍͠(callbackຖʹΤϥʔॲཧ͕ඞཁ)• try catchͱ૬ੑѱ͍• ॥ࢀরΛ࡞Γ͍͢ʢΩϟϓνϟϦετΛॻ͖ΕΔʣ• return͠Εͯcallback͕2ճݺΕΔ• @escapingͱ͔ɺ(T)->Voidͱ͔Կճॻ͘ͷ໘
͔͠͠ɺɺ
GCDɺඇಉظॲཧͷ݁ՌΛblockͰड͚औΔͱ͍͏ΞϓϩʔνΛ࠾༻͍ͯ͠·ͨ͠ɺɺʢͱ͍͑ɺ͜ΕʹΑΓɺϨʔείϯσΟγϣϯͳͲΛ͋·Γؾʹ͠ͳͯ͘ྑ͘ͳΓ·͢ɻʣ
block = callback
·ɺ·͔͞ww
͑ɺ݁ہwww
ͪΐͬɺͯΑ͒
SwiftͰαʔόʔॻ͘ͷ͖͋ΒΊΑ͏͔ͳ…) DispatchGroupDispatchSemaphoreͰ͋ΔఔcallbackΛແ͘͢͜ͱग़དྷ·͢
ͨͩɺΈ͞ͳΜࢥ͍ग़͍ͯͩ͘͠͞ɻ
ඇಉظͷϑϩʔ੍ޚΛcallbackҎ֎Ͱղܾͨ͋͠ͷݴޠΛ
……….
GoݴޠͩΑʔ
GoݴޠͱGoϓϩάϥϛϯάݴޠͷͻͱͭɻGoogleʹΑͬͯ։ൃ͞Ε͓ͯΓ[4]ɺઃܭʹϩϒɾύΠΫɺέϯɾτϯϓιϯΒ͕ؔΘ͍ͬͯΔɻओͳಛͱͯ͠ɺܰྔεϨοσΟϯάͷͨΊͷػೳɺPythonͷΑ͏ͳಈతܕ͚ݴޠͷΑ͏ͳϓϩάϥϛϯάͷ༰қੑɺͳͲ͕͋ΔɻGoॲཧܥͱͯ͠ίϯύΠϥͷΈ͕։ൃ͞Ε͍ͯΔɻWikipedia, Go (ϓϩάϥϛϯάݴޠ)ΑΓ
Goݴޠͷฒߦ/ฒྻॲཧGoݴޠͰGoroutineΛͬͯɺฒߦ/ฒྻॲཧΛ࣮ݱ͍ͯ͠·͢ɻฒߦ(Concurrent) ฒྻ(parallel)
GoroutineGoroutineෳThread্ʹଟॏԽ͞ΕͨCoroutineͷΑ͏ͳಈ࡞Λ͢ΔɻҰͭͷgoroutine͕͍࣌ؒϒϩοΫ͢Α͏ͳؔͰɺผͷgoroutineʹhand offͯ͠ॲཧΛଓߦ͢ΔͨΊɺCPUΛ༨ΒͤͣʹޮతʹϓϩάϥϜΛ࣮ߦͰ͖ΔG1G2G3G4 G5sleep(1)G6G4G5sleep(1)G6 G8G4G7G9thread1thread2thread3
ChannelGorotuineThreadؒΛ·͍ͨͰ࣮ߦ͞ΕΔͨΊɺGoroutineಉ࢜ͰҰͭͷมΞΫηε͢ΔͱRace Condition͕ൃੜͯ͠͠·͏ɻͦΕΛ͙ͨΊʹɺGoͰChannelͱ͍͏ػೳ͕ఏڙ͞Ε͓ͯΓɺͦΕΛͬͯΛૹड৴͢ΔG1G2G3sendsendsendmainthreadreceiveChannel
ίʔυ͜ͷϓϩάϥϜͷ݁ՌɺHello WorldͱWorld HelloͷͲͪΒ͔ʹͳΓ·͢
goroutineͰ͔֬ʹthreadΛͬͨฒྻॲཧʢඇಉظॲཧʣ͕ߦΘΕ͍ͯΔ͜ͱ͕Θ͔Γ·ͨ͠ɻ
ඇಉظͰ͋ΔͷʹɺίʔυͱͯಉظతͰ͢ΑͶɻ
ͳͥͳΒɺChannelͷૹड৴ϒϩοΫ͞ΕΔ͔ΒͰ͢ɻ
= ChannelΛͬͨഉଞ੍ޚͰ͢Ͷ
DispatchQueueThreadϕʔεͰͨ͠ɻ
ͱ͍͏͜ͱʂ
Goroutine+ChannelͷΠϯλʔϑΣʔεΛ͑ɺSwiftͰඇಉظॲཧ͕ಉظతʹॻ͚ͦ͏Ͱ͢ɻ(Context switchOSଆͰ͕͢..)
ͦ͜ͰɺProrsumʹGoroutineͱChannelͷΑ͏ͳػೳΛ࣮ͯ͠Έ·ͨ͠
ChannelʹΑΓɺϓϩάϥϚDispatchQueueؒͷͷڞ༗࣌ʹɺഉଞ੍ޚ͔Β։์͞Ε·͢
• ݱঢ়ͨͩͷDispatchQueue.asyncͷΤΠϦΞε• serial͔ɺconcurrent͔࣮ߦ࣌ʹબՄೳ• GoͷΑ͏ʹϒϩοΩϯάॲཧΛۭ͖εϨουʹcontext switch࣮ͤͯ͞ߦ͢ΔΑ͏ͳ࠷దԽ͞Ε͍ͯͳ͍• ThreadϕʔεͳͷͰɺGoroutineΑΓͪΖΜϦιʔεͷރׇૣ͍Prorsumͷgo()ʹؔͯ͠
• ࣮MutexLockΛͬͨ୯ͳΔδΣωϦοΫͳڞ༗ϝϞϦ• lock͕͔͔ΔͨΊɺ͍ա͗ͨΒੑೳྼԽ͢Δ• BufferLinkedListͰ࣮͞Ε͍ͯΔ• Buffer capacityΛӽ͑ͯૹ৴͢Δͱthrow͢Δ• Goͱҧ͍ɺtry catchͰΤϥʔͷัଊ͕Մೳ• Processؒͷ௨৴Ͱ͖ͳ͍(ErlangͷActorͳͲͱશʹผ)ProrsumͷChannelʹؔͯ͠
ͰɺProrsumͰΞϓϦέʔγϣϯΛॻ͍ͯɺGCDͱChannelͷΈ߹Θ͕࣮ͤ༻తͳͷ͔ݟͯΈ·͠ΐ͏
ࠓճɺJSON-RPC ServerΛॻ͍ͯΈ·ͨ͠
ಈ࡞σϞ
ιʔείʔυͷղઆ
ؾʹͳΔύϑΥʔϚϯε
ࠓճɺGoɺKituraɺNode.jsͦͯ͠ProrsumͰϕϯνϚʔΫରܾΛͯ͠Έ·ͨ͠ɻ
BenchmarkingRequest/sec017500350005250070000Prorsum Kitura Go 1.7 HTTP Server Express14,76964,76817,14429,436ɾwrk -d 30s -t 4 -c 20ɾResponded with the 10 length of random JSON arrayɾMachine: MacOS Sierra, 8 logical cores, 8GB RAM
• Go͗͢ (´ʀωʀʆ)ŲƄƂŕ• KituraͱExpressϑϨʔϜϫʔΫͳͷͰɺ͜ͷϕϯνϚʔΫࣗମશʹFairͰͳ͍• Prorsum2Ґͱ͍͏݁Ռ͕ͩɺϦΫΤετͷread/writeΛϊϯϒϩοΩϯάʹ͢ΕɺGOʹ͏গ͠ബͦ͠͏• Node.jsͱಉҎ্ͳύϑΥʔϚϯεɺ΄΅Swiftඪ४Ͱग़Δ• ࠓճ࠶ߟͨ͠ΞʔΩςΫνϟɺҰԠޭʁײ
࠷ޙʹ
swift-server/work-groupʹͯҎԼͷϥΠϒϥϦΛSwiftඪ४Ͱ͑ΔΑ͏ʹ༷ࡦఆதͰ͢ɻ• RFC 7230-7235(HTTP/1.1)• RFC 6455 (WebSocket)• RFC 7540(HTTP/2.0)• TCP/IP(v6,v4), UDP including I/O• TLS/Encryptionhttps://github.com/swift-server/work-group
• ͓ͦΒ͘ݱߦͷϑϨʔϜϫʔΫެࣜαʔόʔAPIʹ͔ͬͬͯ͘Δͱࢥ͍·͢ɻ• ؤுͬͯࣗ࡞ͯ͠ɺެ͕ࣜग़ͨλΠϛϯάͰ࣌ؒͷແବʹͳΔՄೳੑ͕͋Γ·͢ɻ• ಛʹTLSHTTPपΓRFCଟྔͰɺ࣮ෳࡶͳͨΊ·Ͱʹ݁ߏͳ͕͔͔࣌ؒΓ·͢ɻ
3rd partiyͷϥΠϒϥΛԼखʹ૿͢ΑΓɺServer-Work-GroupͷٞʹࢀՃͯ͠ɺ͍͍ඪ४ϥΠϒϥϦΛ࡞͍ͬͯ͘΄͏͕ݐઃతͰ͢ɻ(ͦͯ͠ɺૣ͘ຊ൪αʔϏεͰ͑ΔΑ͏ʹ…
ProrsumHTTPTLSपΓɺެࣜ൛ʹReplace͢Δ༧ఆͰ͢ɻ
͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ