Slide 1

Slide 1 text

Hackers Champloo 2018 GoͱίϯςφͰ࡞Δ WebΞϓϦέʔγϣϯ ϕϯνϚʔΧʔ 2018.06.30 @fujiwara

Slide 2

Slide 2 text

@fujiwara ٕज़෦ github.com/fujiwara sfujiwara.hatenablog.com ISUCON 8 ग़୊νʔϜ

Slide 3

Slide 3 text

Game & Community

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

΍Γ͍ͨ͜ͱ Perl / Go + WebSocket Ͱߏ੒͞Εͨ ήʔϜαʔόʹରͯ͠ ϕϯνϚʔΫΛֻ͚͍ͨ

Slide 6

Slide 6 text

ͳͥ΍Δͷ͔ - ੑೳධՁ / ݶքଌఆ • XXXϢʔβ·ͰͷΞΫηεʹ଱͑ΒΕΔ͔ • ໨ඪϢʔβ਺ʹ଱͑ΒΕͳ͍ = ͓ۚʹͳΒͳ͍ • ΠϯελϯεαΠζɺ୆਺ = ͓ۚ͸͍͘Β͔͔Δͷ͔ • ίετֻ͕͔Γ͗ͯ͢͸͍͚ͳ͍ • ϨεϙϯελΠϜ • ϢʔβʹշదͳମݧΛͯ͠΋Β͑Δ͔

Slide 7

Slide 7 text

ͳͥ΍Δͷ͔ - ຊ൪ϦϦʔεͷ४උ ΞϓϦέʔγϣϯ / ϛυϧ΢ΣΞͷෆඋΛચ͍ग़͢ • ϘτϧωοΫݕग़ • DB ͷ index ͕ͳ͍ͱ͔ • ֤छઃఆ஋͕ద੾͔ • failover ͸ਖ਼ৗʹಈ࡞͢Δ͔

Slide 8

Slide 8 text

ͳͥ΍Δͷ͔ - ຊ൪ϦϦʔεͷ४උ ϞχλϦϯά͕ద੾͔Λચ͍ग़͢ • ΄͍͠ϝτϦΫε͕ऩूͰ͖͍ͯΔ͔ • ݟ͍ͨάϥϑ͕͙͢ݟΒΕΔ͔ • ϘτϧωοΫ͕ద੾ʹݕ஌Ͱ͖Δ͔ • Ξϥʔτͷᮢ஋ΛܾΊΔ

Slide 9

Slide 9 text

۩ମతʹ΍Γ͍ͨ͜ͱ REST API Λୟ͍ͯͦͷ݁ՌΛ࢖ͬͯ࣍ͷϦΫΤετ • ྫ / → /signup → /login → /mypage → /infomation ೝূ͕ಠࣗ • CookieͰ͸ͳ͍ HTTP ϦΫΤετϔομʹ token • ຖճ unique ͳ஋Λૹ৴ɺ࠶ૹʹΑΔଟॏϦΫΤετݕ஌ • Challenge & Response • ϦϓϨΠ߈ܸͳͲΛ๷͙

Slide 10

Slide 10 text

۩ମతʹ΍Γ͍ͨ͜ͱ ήʔϜͷਐߦʹ WebSocket ͕࢖ΘΕ͍ͯΔ • ଞͷϢʔβ͕ൃੜͤͨ͞Πϕϯτ͕ WebSocket Ͱ߱ͬͯ͘ Δ • Payload ͸ MessagePack • ͦͷΠϕϯτʹΑͬͯϦΫΤετΛม͑Δඞཁ͕͋Δ

Slide 11

Slide 11 text

ͳʹͰ΍Δͷ͔ طʹੈʹ͋Δෛՙࢼݧπʔϧ ApacheBench (ab) • Apache HTTPd ʹ෇ଐ • 1 URL ʹͻͨ͢ΒϦΫΤετ͢Δ $ ab -c 10 -n 1000 http://example.com/

Slide 12

Slide 12 text

ͳʹͰ΍Δͷ͔ wrk github.com/wg/wrk • ApachBench ΑΓߴػೳ $ wrk -c 10 -d 3 http://example.com/

Slide 13

Slide 13 text

wrk - ϦΫΤετΛ Lua ͰΧελϚΠζ wrk.method = "POST" wrk.body = "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

Slide 14

Slide 14 text

΋ͬͱߴػೳͳπʔϧ Apache JMeter - jmeter.apache.org • Java • GUI ͕͋Δ • γφϦΦ͸ GUI or XML (jmx)

Slide 15

Slide 15 text

Gatling - gatling.io • Scalar • γφϦΦ͸ Scala Ͱهड़

Slide 16

Slide 16 text

JMeter or Gatling ? ͲͪΒ΋ • WebSocket ͕ѻ͑Δ • JMeter͸ϓϥάΠϯ • γφϦΦϨίʔμʔ͕͋Δ • HTTP Proxy ͱͯ͠ಈ࡞ͯ͠ϒϥ΢βૢ࡞Λ capture ͢Δ

Slide 17

Slide 17 text

Go Ͱࣗ࡞͢Δ ձࣾͷڞ௨ݴޠ͕ Go / Perl / Ruby (ಛʹαʔό͕ Go ͷ৔߹) • JSON API / WebSocket Payload ͷߏ଄ମ͕ڞ௨ʹͰ͖Δ Ϩϙʔτ͕͖Ε͍Ͱ͋Δඞཁ͸ͳ͍ • αʔόଆͷϞχλϦϯάͰ࣮ݱ͞Ε͍ͯΔඞཁ͕͋Δ • req/sec, εςʔλείʔυͷׂ߹ ϨεϙϯελΠϜ

Slide 18

Slide 18 text

ͲͷΑ͏ʹ࡞Δ͔

Slide 19

Slide 19 text

ΞʔΩςΫνϟ

Slide 20

Slide 20 text

ϕϯνϚʔΫΫϥΠΞϯτ net/http.Client, gorilla/websocket.Dialer Λ࣋ͭ type Client struct { client *http.Client wsDialer *websocket.Dialer // ... }

Slide 21

Slide 21 text

γφϦΦΛ͋ΒΘ͢ struct Client Λ࣋ͭ type Scenario struct { client *bench.Client // ... }

Slide 22

Slide 22 text

࣮ࡍͷϕϯνϚʔΫࢼߦ func (s *Scenario) Run(ctx context.Context) (score int64) { // websocketܨ͙ conn, _, _ := s.client.ConnectWebsocket() defer conn.Close() // room ೖࣨ res, _ := s.client.Post("/api/room/join") EVENT: for { _, b, err := conn.ReadMessage() ev, _ := event.Decode(b) switch ev := ev.(type) { case event.RoomJoinEvent: // ...

Slide 23

Slide 23 text

γφϦΦΛ࠷େNฒྻͰಈ͔͢ channel Λ࢖ͬͨ semaphore ύλʔϯ func Run() { sem := make(chan struct{}, 100) // ࠷େ100ฒྻ for { sem <- struct{}{}: // 100 Ҏ্ʹͳΒͳ͍Α͏ʹηϚϑΥऔಘ go func() { sc := newScenario() // γφϦΦੜ੒ defer func() { <-sem // ऴΘͬͨͱ͜ΖͰηϚϑΥ։์ }() sc.Run() // ϕϯνϚʔΫ }() time.Sleep(spawnInterval) // ࣍ͷγφϦΦੜ੒͸ͪΐͬͱ଴ͭ } }

Slide 24

Slide 24 text

sem := make(chan struct{}, 4) // □□□□ // main scenario sem <- struct{}{} ■□□□ // (1) sem <- struct{}{} ■■□□ // (2) sem <- struct{}{} ■■■□ // (3) sem <- struct{}{} ■■■■ // (4) sem <- struct{}{} ■■■■◆ // (5) ■■■□ <- sem // (1) ■■■■ // (5) sem <- struct{}{} ■■■■◆ // (6) ■■■□ <- sem // (2) ■■■■ // (6)

Slide 25

Slide 25 text

࣮૷Ͱ஫ҙ͢Δ͜ͱ

Slide 26

Slide 26 text

Ұؾʹىಈ͠ͳ͍ 1msֻ͔͔͠Βͳ͍ϦΫΤετΛ1ඵ͝ͱʹ࣮ߦ͢ΔγφϦΦΛ × 1000ฒྻͰ࣮ߦ͠ଓ͚Δ৔߹ Ұؾʹىಈ͢Δͱຖඵ࠷ॳͷ਺msʹෛՙ͕ूத͢Δ ࣮ࡍͷϢʔβͷϦΫΤετঢ়گͱ͸ҟͳΔ (…ͱ͸ݶΒͳ͍͚Ͳ)

Slide 27

Slide 27 text

ద౰ʹ(෼ࢄͯ͠) Sleep ͢Δ ͖ͬͪΓ 100ms ͣͭͣΒͯ͠͠·͏ͱ ຖඵ 0, 100, 200, ... 900 ms ͷλΠϛϯάʹෛՙ͕ूத͢Δ ద౰ʹฏۉ100msͰ෼ࢄ͢Δ஋ΛٻΊΔʹ͸…?

Slide 28

Slide 28 text

Go Ͱਖ਼نཚ਺ΛٻΊΔ - math/rand func NormFloat64() float64 returns a normally distributed float64 in the range [-math.MaxFloat64, +math.MaxFloat64] with standard normal distribution (mean = 0, stddev = 1) sample = NormFloat64() * desiredStdDev + desiredMean

Slide 29

Slide 29 text

rand.NormFloat64()*4 + 10 0 ########## 1 ############## 2 ############# 3 ############################ 4 ######################################## 5 ######################################################## 6 ############################################################## 7 ################################################################################### 8 ############################################################################################### 9 ############################################################################################## 10 ############################################################################################################ 11 ############################################################################################## 12 ################################################################################## 13 ###################################################################### 14 ############################################## 15 ######################################## 16 ##################### 17 #################### 18 ######### 19 #####

Slide 30

Slide 30 text

net/http.Get() ౳Λ࢖Θͳ͍ resp, err := http.Get("http://example.com/") ҉໧ʹ http.DefaultClient ͕࢖ΘΕΔ • ಉҰϗετ΁ͷϦΫΤετΛ KeepAlive ͍ͯ͠ΔίωΫγϣ ϯʹ·ͱΊͯ͠·͏ͷͰίωΫγϣϯ͕ݮΔ • ࣮ࡍʹϢʔβͷ୺຤͕ͦΕͧΕ઀ଓΛுΔঢ়گͷγϛϡϨʔ γϣϯʹͳΒͳ͍

Slide 31

Slide 31 text

͏͔ͬΓ HTTP/2 ʹ஫ҙ AWS ALB ͸σϑΥϧτͰ HTTP/2 ରԠ͍ͯ͠Δ net/http.Client ΋σϑΥϧτͰ HTTP/2 Ͱܨ͛ΔͳΒܨ͙ ࣮ࡍͷΫϥΠΞϯτ͕ HTTP/1 ͷ৔߹ͷ γϛϡϨʔγϣϯʹͳΒͳ͍ ࣮ߦ࣌ʹ؀ڥม਺ GODEBUG=http2client=0 ͰແޮԽͰ͖Δ ৄ͘͠͸ godoc.org/net/http

Slide 32

Slide 32 text

઀ଓΛͪΌΜͱෳ਺ுΔ http.Client Λผʹ༻ҙͨ͠৔߹ c := &http.Client{} req, _ := http.NewRequest("GET", "https://example.com/", nil) resp, err := c.Do(req) //... • http1 ͳΒͦΕͧΕͷΫϥΠΞϯτ͕ผͷTCP઀ଓΛ࣋ͭ • http2 ͩͱͻͱͭͷίωΫγϣϯΛ࢖͍ճ͢(!!)

Slide 33

Slide 33 text

http.Transport Λผʑʹ࡞Ε͹ h2 Ͱ΋ผ઀ଓ c := &http.Client{ Transport: &http.Transport{}, } req, _ := http.NewRequest("GET", "https://example.com/", nil) resp, err := c.Do(req) //...

Slide 34

Slide 34 text

ϢʔβͷΞΫηεΛ໛ͨ͠ϕϯνϚʔΫʹ͢Δ ؾͮͨ͘Ίʹ͸ • αʔόଆͷίωΫγϣϯ਺ΛϞχλϦϯά͢Δ • ΞΫηεϩάʹΫϥΠΞϯτͷ IP ΞυϨε͚ͩͰ͸ͳ͘ɺ port ΋ग़ྗ͢Δ • ಉҰ port ͕࢖͍ճ͞Ε͍ͯΔ༷ࢠ͕෼͔Δ ϕϯνϚʔΫΛਖ਼֬ʹ͢Δ = ϞχλϦϯάେࣄ

Slide 35

Slide 35 text

࣮ࡍͷϢʔβ਺෼ϕϯνϚʔΫΛ࣮ߦ͢Δ 1ϓϩηε/ϗετ͔Β઀ଓͰ͖Δྔʹ͸੍໿͕͋Δ ͨͱ͑͹10ສಉ࣌Ϣʔβͷ݁Ռ͕΄͍͠ͱͯ͠ • CPU (32ίΞͩͱͯ͠ 0.00032 core/user ͔͠࢖͑ͳ͍) • Memory (1MB * 10ສ = 100GB) • ଳҬ (100Kbps * 10ສ= 10 Gbps) • IP source port (16bit = 65535 Ͳ͏ؤுͬͯ΋ແཧ) ෳ਺୆ʹ෼ࢄ͢Δඞཁ͕͋Δ

Slide 36

Slide 36 text

Amazon ECS Ͱ ϕϯνϚʔΫΛେྔ࣮ߦ

Slide 37

Slide 37 text

ϕϯνϚʔΫ༻ͷ ECS Ϋϥελ(EC2 Πϯελϯεͷଋ) Λ༻ҙ ͦ͜ʹλεΫ(ίϯςφ্Ͱಈ͘ϓϩηε)Λෳ਺࣮ߦ

Slide 38

Slide 38 text

ϕϯνΫϥΠΞϯτଆͷϝτϦΫεΛͲ͏औΔ͔ 1ϓϩηεͰ͋Ε͹ 1000ฒྻͰ࣮ߦ = 1000ฒྻ࣌ͷෛՙ ෳ਺ϓϩηεΛঃʑʹىಈͯ͠ɺঃʑʹෛՙΛ্͍͛ͯ͘৔߹ ݱࡏԿฒྻͰಈ͍ͯΔ? ͔ΛՄࢹԽ͢Δඞཁ͕͋Δ e.g. 1,000 → 10,000ฒྻ·Ͱ͸໰୊ͳ͠ɺ12,000ʹͨ͠Β XXX ͕ աෛՙʹͳͬͯΤϥʔൃੜɺͳͲΛه࿥͍ͨ͠

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Amazon CloudWatch ͰΧελϜϝτϦΫεΛه࿥͢Δ ϦιʔεͷϞχλϦϯάͷͨΊͷϚωʔδυαʔϏε AWS Ͱಈ࡞͍ͯ͠ΔαʔϏεɺίϯϙʔωϯτͷϝτϦΫε͕ େ఍͜͜ʹه࿥͞Ε͍ͯΔ EC2 CPU, ELB Request, RDS... ଞ͋ΒΏΔ΋ͷ

Slide 41

Slide 41 text

ΧελϜϝτϦΫεͷσʔλߏ଄ Namespace: benchmark # ໊લۭؒ MetricName: Concurrency # ϝτϦοΫ໊ Value: 1000 # ஋ (float) Timestamp: 1528075230 # ࣌ࠁ(UNIX time) Dimensions: - Name: Scenario Value: GvG

Slide 42

Slide 42 text

Dimensions? σʔλͷूܭͷͨΊͷϝλσʔλ ಉ࣌ؒ͡(ଳ)ʹొ࿥͞Εͨෳ਺ͷ஋ʹରͯ͠ Dimension ͝ͱʹ ߹ܭ, ࠷େ, ࠷খ, Percentile஋, σʔλݸ਺ Λूܭͨ݁͠ՌΛऔಘͰ͖Δ

Slide 43

Slide 43 text

ͳͥ CloudWatch ͕ίϯςφ؀ڥͷϝτϦΫε ूܭʹ޲͍͍ͯΔ͔ ίϯςφ͸ಉ࣌ʹ͍࣮ͭ͘ߦ͞ΕΔ͔෼͔Βͳ͍ ͦΕͧΕͷίϯςφ͸͓ޓ͍ͷ͜ͱ͸஌Βͳ͍ ࣗ෼ࣗ਎ͷϝτϦΫεΛ CloudWatch ʹ౤͛Δ CloudWatch ͸ಉҰ࣌ࠁ ಉҰ Dimension ͷ஋ΛूܭͰ͖Δ ϝτϦΫε͕͍ͭ͋ͬͯ͘΋ؔ܎ͳ͍

Slide 44

Slide 44 text

ҙຯͷ͋ΔूܭΛ͢Δ ͲͷΑ͏ʹूܭ͢ΔͱΞϓϦέʔγϣϯతʹ ҙຯͷ͋Δ஋͕ಘΒΕΔ͔͸ਓ͕ؒߟ͑Δඞཁ͕͋Δ • ϦΫΤετ਺ɺಉ࣌઀ଓ਺ = ߹ܭ • ϨΠςϯγ = ฏۉɺPercentile

Slide 45

Slide 45 text

https://2018.cedec.cesa.or.jp/session/108 2018.08.22 (ਫ) - 08.24 (ۚ) ύγϑΟίԣ඿

Slide 46

Slide 46 text

ΦϯϥΠϯ༧બ 9݄15೔(౔),16೔(೔) ຊબ 10݄20೔(౔) ༏উ৆ۚ100ສԁ ֶੜ࿮ɺ͓Ұਓ༷ࢀՃ࿮͋Γ

Slide 47

Slide 47 text

No content