Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Goとコンテナで作るWebアプリケーションベンチマーカー / Benchmarker built with Go and Container

Goとコンテナで作るWebアプリケーションベンチマーカー / Benchmarker built with Go and Container

Ca6281fff64797dc419b78f51f25c0a5?s=128

FUJIWARA Shunichiro
PRO

June 30, 2018
Tweet

Transcript

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

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

  3. Game & Community

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

  6. ͳͥ΍Δͷ͔ - ੑೳධՁ / ݶքଌఆ • XXXϢʔβ·ͰͷΞΫηεʹ଱͑ΒΕΔ͔ • ໨ඪϢʔβ਺ʹ଱͑ΒΕͳ͍ =

    ͓ۚʹͳΒͳ͍ • ΠϯελϯεαΠζɺ୆਺ = ͓ۚ͸͍͘Β͔͔Δͷ͔ • ίετֻ͕͔Γ͗ͯ͢͸͍͚ͳ͍ • ϨεϙϯελΠϜ • ϢʔβʹշదͳମݧΛͯ͠΋Β͑Δ͔
  7. ͳͥ΍Δͷ͔ - ຊ൪ϦϦʔεͷ४උ ΞϓϦέʔγϣϯ / ϛυϧ΢ΣΞͷෆඋΛચ͍ग़͢ • ϘτϧωοΫݕग़ • DB

    ͷ index ͕ͳ͍ͱ͔ • ֤छઃఆ஋͕ద੾͔ • failover ͸ਖ਼ৗʹಈ࡞͢Δ͔
  8. ͳͥ΍Δͷ͔ - ຊ൪ϦϦʔεͷ४උ ϞχλϦϯά͕ద੾͔Λચ͍ग़͢ • ΄͍͠ϝτϦΫε͕ऩूͰ͖͍ͯΔ͔ • ݟ͍ͨάϥϑ͕͙͢ݟΒΕΔ͔ • ϘτϧωοΫ͕ద੾ʹݕ஌Ͱ͖Δ͔

    • Ξϥʔτͷᮢ஋ΛܾΊΔ
  9. ۩ମతʹ΍Γ͍ͨ͜ͱ REST API Λୟ͍ͯͦͷ݁ՌΛ࢖ͬͯ࣍ͷϦΫΤετ • ྫ / → /signup →

    /login → /mypage → /infomation ೝূ͕ಠࣗ • CookieͰ͸ͳ͍ HTTP ϦΫΤετϔομʹ token • ຖճ unique ͳ஋Λૹ৴ɺ࠶ૹʹΑΔଟॏϦΫΤετݕ஌ • Challenge & Response • ϦϓϨΠ߈ܸͳͲΛ๷͙
  10. ۩ମతʹ΍Γ͍ͨ͜ͱ ήʔϜͷਐߦʹ WebSocket ͕࢖ΘΕ͍ͯΔ • ଞͷϢʔβ͕ൃੜͤͨ͞Πϕϯτ͕ WebSocket Ͱ߱ͬͯ͘ Δ •

    Payload ͸ MessagePack • ͦͷΠϕϯτʹΑͬͯϦΫΤετΛม͑Δඞཁ͕͋Δ
  11. ͳʹͰ΍Δͷ͔ طʹੈʹ͋Δෛՙࢼݧπʔϧ ApacheBench (ab) • Apache HTTPd ʹ෇ଐ • 1

    URL ʹͻͨ͢ΒϦΫΤετ͢Δ $ ab -c 10 -n 1000 http://example.com/
  12. ͳʹͰ΍Δͷ͔ wrk github.com/wg/wrk • ApachBench ΑΓߴػೳ $ wrk -c 10

    -d 3 http://example.com/
  13. wrk - ϦΫΤετΛ Lua ͰΧελϚΠζ wrk.method = "POST" wrk.body =

    "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
  14. ΋ͬͱߴػೳͳπʔϧ Apache JMeter - jmeter.apache.org • Java • GUI ͕͋Δ

    • γφϦΦ͸ GUI or XML (jmx)
  15. Gatling - gatling.io • Scalar • γφϦΦ͸ Scala Ͱهड़

  16. JMeter or Gatling ? ͲͪΒ΋ • WebSocket ͕ѻ͑Δ • JMeter͸ϓϥάΠϯ

    • γφϦΦϨίʔμʔ͕͋Δ • HTTP Proxy ͱͯ͠ಈ࡞ͯ͠ϒϥ΢βૢ࡞Λ capture ͢Δ
  17. Go Ͱࣗ࡞͢Δ ձࣾͷڞ௨ݴޠ͕ Go / Perl / Ruby (ಛʹαʔό͕ Go

    ͷ৔߹) • JSON API / WebSocket Payload ͷߏ଄ମ͕ڞ௨ʹͰ͖Δ Ϩϙʔτ͕͖Ε͍Ͱ͋Δඞཁ͸ͳ͍ • αʔόଆͷϞχλϦϯάͰ࣮ݱ͞Ε͍ͯΔඞཁ͕͋Δ • req/sec, εςʔλείʔυͷׂ߹ ϨεϙϯελΠϜ
  18. ͲͷΑ͏ʹ࡞Δ͔

  19. ΞʔΩςΫνϟ

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

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

    // ... }
  22. ࣮ࡍͷϕϯνϚʔΫࢼߦ 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: // ...
  23. γφϦΦΛ࠷େ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) // ࣍ͷγφϦΦੜ੒͸ͪΐͬͱ଴ͭ } }
  24. 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)
  25. ࣮૷Ͱ஫ҙ͢Δ͜ͱ

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

  27. ద౰ʹ(෼ࢄͯ͠) Sleep ͢Δ ͖ͬͪΓ 100ms ͣͭͣΒͯ͠͠·͏ͱ ຖඵ 0, 100, 200,

    ... 900 ms ͷλΠϛϯάʹෛՙ͕ूத͢Δ ద౰ʹฏۉ100msͰ෼ࢄ͢Δ஋ΛٻΊΔʹ͸…?
  28. 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
  29. rand.NormFloat64()*4 + 10 0 ########## 1 ############## 2 ############# 3

    ############################ 4 ######################################## 5 ######################################################## 6 ############################################################## 7 ################################################################################### 8 ############################################################################################### 9 ############################################################################################## 10 ############################################################################################################ 11 ############################################################################################## 12 ################################################################################## 13 ###################################################################### 14 ############################################## 15 ######################################## 16 ##################### 17 #################### 18 ######### 19 #####
  30. net/http.Get() ౳Λ࢖Θͳ͍ resp, err := http.Get("http://example.com/") ҉໧ʹ http.DefaultClient ͕࢖ΘΕΔ •

    ಉҰϗετ΁ͷϦΫΤετΛ KeepAlive ͍ͯ͠ΔίωΫγϣ ϯʹ·ͱΊͯ͠·͏ͷͰίωΫγϣϯ͕ݮΔ • ࣮ࡍʹϢʔβͷ୺຤͕ͦΕͧΕ઀ଓΛுΔঢ়گͷγϛϡϨʔ γϣϯʹͳΒͳ͍
  31. ͏͔ͬΓ HTTP/2 ʹ஫ҙ AWS ALB ͸σϑΥϧτͰ HTTP/2 ରԠ͍ͯ͠Δ net/http.Client ΋σϑΥϧτͰ

    HTTP/2 Ͱܨ͛ΔͳΒܨ͙ ࣮ࡍͷΫϥΠΞϯτ͕ HTTP/1 ͷ৔߹ͷ γϛϡϨʔγϣϯʹͳΒͳ͍ ࣮ߦ࣌ʹ؀ڥม਺ GODEBUG=http2client=0 ͰແޮԽͰ͖Δ ৄ͘͠͸ godoc.org/net/http
  32. ઀ଓΛͪΌΜͱෳ਺ுΔ http.Client Λผʹ༻ҙͨ͠৔߹ c := &http.Client{} req, _ := http.NewRequest("GET",

    "https://example.com/", nil) resp, err := c.Do(req) //... • http1 ͳΒͦΕͧΕͷΫϥΠΞϯτ͕ผͷTCP઀ଓΛ࣋ͭ • http2 ͩͱͻͱͭͷίωΫγϣϯΛ࢖͍ճ͢(!!)
  33. http.Transport Λผʑʹ࡞Ε͹ h2 Ͱ΋ผ઀ଓ c := &http.Client{ Transport: &http.Transport{}, }

    req, _ := http.NewRequest("GET", "https://example.com/", nil) resp, err := c.Do(req) //...
  34. ϢʔβͷΞΫηεΛ໛ͨ͠ϕϯνϚʔΫʹ͢Δ ؾͮͨ͘Ίʹ͸ • αʔόଆͷίωΫγϣϯ਺ΛϞχλϦϯά͢Δ • ΞΫηεϩάʹΫϥΠΞϯτͷ IP ΞυϨε͚ͩͰ͸ͳ͘ɺ port ΋ग़ྗ͢Δ

    • ಉҰ port ͕࢖͍ճ͞Ε͍ͯΔ༷ࢠ͕෼͔Δ ϕϯνϚʔΫΛਖ਼֬ʹ͢Δ = ϞχλϦϯάେࣄ
  35. ࣮ࡍͷϢʔβ਺෼ϕϯνϚʔΫΛ࣮ߦ͢Δ 1ϓϩηε/ϗετ͔Β઀ଓͰ͖Δྔʹ͸੍໿͕͋Δ ͨͱ͑͹10ສಉ࣌Ϣʔβͷ݁Ռ͕΄͍͠ͱͯ͠ • CPU (32ίΞͩͱͯ͠ 0.00032 core/user ͔͠࢖͑ͳ͍) •

    Memory (1MB * 10ສ = 100GB) • ଳҬ (100Kbps * 10ສ= 10 Gbps) • IP source port (16bit = 65535 Ͳ͏ؤுͬͯ΋ແཧ) ෳ਺୆ʹ෼ࢄ͢Δඞཁ͕͋Δ
  36. Amazon ECS Ͱ ϕϯνϚʔΫΛେྔ࣮ߦ

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

  38. ϕϯνΫϥΠΞϯτଆͷϝτϦΫεΛͲ͏औΔ͔ 1ϓϩηεͰ͋Ε͹ 1000ฒྻͰ࣮ߦ = 1000ฒྻ࣌ͷෛՙ ෳ਺ϓϩηεΛঃʑʹىಈͯ͠ɺঃʑʹෛՙΛ্͍͛ͯ͘৔߹ ݱࡏԿฒྻͰಈ͍ͯΔ? ͔ΛՄࢹԽ͢Δඞཁ͕͋Δ e.g. 1,000

    → 10,000ฒྻ·Ͱ͸໰୊ͳ͠ɺ12,000ʹͨ͠Β XXX ͕ աෛՙʹͳͬͯΤϥʔൃੜɺͳͲΛه࿥͍ͨ͠
  39. None
  40. Amazon CloudWatch ͰΧελϜϝτϦΫεΛه࿥͢Δ ϦιʔεͷϞχλϦϯάͷͨΊͷϚωʔδυαʔϏε AWS Ͱಈ࡞͍ͯ͠ΔαʔϏεɺίϯϙʔωϯτͷϝτϦΫε͕ େ఍͜͜ʹه࿥͞Ε͍ͯΔ EC2 CPU, ELB

    Request, RDS... ଞ͋ΒΏΔ΋ͷ
  41. ΧελϜϝτϦΫεͷσʔλߏ଄ Namespace: benchmark # ໊લۭؒ MetricName: Concurrency # ϝτϦοΫ໊ Value:

    1000 # ஋ (float) Timestamp: 1528075230 # ࣌ࠁ(UNIX time) Dimensions: - Name: Scenario Value: GvG
  42. Dimensions? σʔλͷूܭͷͨΊͷϝλσʔλ ಉ࣌ؒ͡(ଳ)ʹొ࿥͞Εͨෳ਺ͷ஋ʹରͯ͠ Dimension ͝ͱʹ ߹ܭ, ࠷େ, ࠷খ, Percentile஋, σʔλݸ਺

    Λूܭͨ݁͠ՌΛऔಘͰ͖Δ
  43. ͳͥ CloudWatch ͕ίϯςφ؀ڥͷϝτϦΫε ूܭʹ޲͍͍ͯΔ͔ ίϯςφ͸ಉ࣌ʹ͍࣮ͭ͘ߦ͞ΕΔ͔෼͔Βͳ͍ ͦΕͧΕͷίϯςφ͸͓ޓ͍ͷ͜ͱ͸஌Βͳ͍ ࣗ෼ࣗ਎ͷϝτϦΫεΛ CloudWatch ʹ౤͛Δ CloudWatch

    ͸ಉҰ࣌ࠁ ಉҰ Dimension ͷ஋ΛूܭͰ͖Δ ϝτϦΫε͕͍ͭ͋ͬͯ͘΋ؔ܎ͳ͍
  44. ҙຯͷ͋ΔूܭΛ͢Δ ͲͷΑ͏ʹूܭ͢ΔͱΞϓϦέʔγϣϯతʹ ҙຯͷ͋Δ஋͕ಘΒΕΔ͔͸ਓ͕ؒߟ͑Δඞཁ͕͋Δ • ϦΫΤετ਺ɺಉ࣌઀ଓ਺ = ߹ܭ • ϨΠςϯγ =

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

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

  47. None