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
マイクロサービス時代 のHTTPクライアントの作り方 / how we build our ...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
LINE Developers
July 13, 2019
Technology
2k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
マイクロサービス時代 のHTTPクライアントの作り方 / how we build our http client for microservice
Go Conference'19 Summer in Fukuokaでの登壇資料です
https://fukuoka.gocon.jp/ja/
LINE Developers
July 13, 2019
More Decks by LINE Developers
See All by LINE Developers
LINEスタンプのSREing事例集:大きなスパイクアクセスを捌くためのSREing
line_developers
3
2.5k
Java 21 Overview
line_developers
6
1.3k
Code Review Challenge: An example of a solution
line_developers
1
1.6k
KARTEのAPIサーバ化
line_developers
1
640
著作権とは何か?〜初歩的概念から権利利用法、侵害要件まで
line_developers
5
2.3k
生成AIと著作権 〜生成AIによって生じる著作権関連の課題と対処
line_developers
3
2.5k
マイクロサービスにおけるBFFアーキテクチャでのモジュラモノリスの導入
line_developers
9
4k
A/B Testing at LINE NEWS
line_developers
3
1.1k
LINEのサポートバージョンの考え方
line_developers
2
1.5k
Other Decks in Technology
See All in Technology
End-to-Endで考える信頼性 —LINEアプリにおけるクライアント開発×SRE連携の実践
maruloop
4
3.1k
“ID沼入口” - 基本とセキュリティから始める、考え続けるためのID管理技術勉強会 告知&イントロ
ritou
0
440
SRE依存からの脱却 運用を開 発チームへ移す、 フルサイ クル開 発体制の実践
joooee0000
0
1.9k
AIで政治は変わるのか? — 中高生と考えたAI時代の民主主義(東海高校サタデープログラム)
eitarosuda
0
400
“全部コピーしない”ファイルデータの活用 : — FSx for ONTAP × S3 Tables × Icebergで作るメタデータカタログ
yoshiki0705
0
560
20260702_生成AIはどこまで成長するのか_チャットだけじゃない世界
doradora09
PRO
0
110
小さいから、全部わかる。— 常駐AI "xangi" のすすめ
sugupoko
0
270
Baseline対応のDOMの型定義を作った
uhyo
3
720
CIで使うClaude
iwatatomoya
0
170
金融の未来を考える / Thinking About the Future of Finance
ks91
PRO
0
180
事業価値を⽣み出すSREへ SREが担うべき意思決定の5層
kenta_hi
2
2.2k
攻撃者がいなくてもAIエージェントはインシデントを起こす
nomizone
0
200
Featured
See All Featured
Evolving SEO for Evolving Search Engines
ryanjones
0
240
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.7k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
Accessibility Awareness
sabderemane
1
150
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Visualization
eitanlees
152
17k
Why Our Code Smells
bkeepers
PRO
340
58k
Embracing the Ebb and Flow
colly
88
5.1k
Making Projects Easy
brettharned
120
6.7k
Raft: Consensus for Rubyists
vanstee
141
7.6k
Building an army of robots
kneath
306
46k
GraphQLとの向き合い方2022年版
quramy
50
15k
Transcript
ϚΠΫϩαʔϏε࣌ ͷHTTPΫϥΠΞϯτͷ࡞Γํ @dxhuy Observability Team / LINE Corp
@dxhuy https://github.com/huydx
None
Developer
• LINEͷObservabilityνʔϜʹ͍ͭͯ • ϚΠΫϩαʔϏεͷམͱ݀͠ • ෦ͰΧελϜͨ͠HTTPΫϥΠΞϯτ ͷઃܭͱհ ࠓͷ
Engineering LINE’S OBSERVABILITY TEAM
Engineering OBSERVABILITY IS NEW WAVE
Πϝʔδతʹ ࣾDATADOGΛ࡞͍ͬͯΔ
Engineering Log ج൫ Metric ج൫ ࢄ τϨʔγ ϯάج൫ ZipkinͷOSS ίϯτϦϏϡʔτ
Engineering GO͍ͬͯΔͷʁ Metric Agent Time Series Storage Metric API Server
͜Ε͔Β࡞Δͷ ͲΜͲΜGO࠾༻ʂ CLI tool Metric Alert Engine
> 1.000.000 metrics per sec εέʔϧνϟϨϯδ
> 2.000 read per sec εέʔϧνϟϨϯδ
Engineering Metrics૿Ճ Ϗδωεεέʔϧ
Engineering GOPHERੵۃ࠾༻தʂ ιϑτΣΞΤϯδχΞ (Software EngineerɺEngineering Efficiency)ʲLINEϓϥοτϑΥʔϜʳ
Engineering ࠓͷຊ
Engineering ϚΠΫϩαʔϏε ͍ͬͯ·͔͢
Engineering ίϛϡχέʔγϣϯ(RPC) ͕େࣄ
Engineering twitch/Twirp GRPC Thrift REST Http RPCख๏͕༷ʑ ࠓޙ૿͑ͦ͏
Engineering GRPC, THRIFTͳͲશͯͷ γεςϜΛม͑ͳ͍ͱߦ͚ͳ͍
Engineering ͢Ͱʹଘࡏ͍ͯ͠Δ APIαʔϏε͕ࠞࡏ net/http͕ఆ൪
Engineering NET/HTTPͪΐͬͱ Γͳ͍
Engineering ϚΠΫϩαʔϏε௨৴ͷ ΫϥΠΞϯτඞཁͳੑ࣭
Engineering αʔϏεͷελοΫ ωοτϫʔΫԆ ϦΫΤετࣦഊ αʔϏεಥવؾઈ https://www.flickr.com/photos/chrish_99/8526019374/
Engineering https://www.flickr.com/photos/chrish_99/8526019374/
Engineering ϦϞʔτίʔϧ͕ࣦഊ͠ ͯճ෮Ͱ͖ΔΑ͏ʹͳ Δ ࣮ύλʔϯ - Retry - CircuitBreaker ճ෮ੑ
ίʔϧઌ͕ࢄͰ͖ΔΑ ͏ʹͳΔ ࣮ύλʔϯ - Load Balancing - Service Discovery ߴՄ༻ੑ ࢲ͕ཉ͍͠ HTTPΫϥΠΞϯτ
Engineering • CircuitBreaker, RetryͳͲ͕ἧ͏ύοέʔδͳͲଘࡏ͢Δ͕ • Ұͭͷػೳ͔͍࣋ͬͯ͠ͳ͍ͷ͕ଟ͍ • ඪ४ͷnet/httpͷΠϯλʔϑΣʔεʹ૬ੑѱ͍ɺίʔυϕʔεͷม ߋ͕ଟ͘ͳΔ •
BoilerPlate͕ଟ͍ • ύϑΥʔϚϯεྑ͘ͳ͍ • ֎෦dependencies͕ଟ͍ • ྫɿgojek/heimdall, go-kitܥͷϥΠϒϥΠͳͲ ͭ·ΓΧελϜNET/HTTP ΫϥΠΞϯτཉ͍͠
Engineering ࣾͰΧελϜNET/HTTP ࡞Γ·ͨ͠
Engineering XHTTPύοέʔδ ઃܭͱ͍ํͷհ
Engineering • ඪ४ͷnet/httpͷΠϯλʔϑΣʔεͰ͖Δ͚ͩै͏ • ͏ଆʢϢʔβʣͷมߋΛ࠷খݶʹ͢Δ • net/httpͷϥούϥΠϒϥϦͱͯ͠ • ඞཁͳͷશ෦ἧ͏ •
ճ෮ੑɺߴՄ༻ੑͷػೳΛἧ͏ • ϝτϦΫεɺTracingͷػೳΛἧ͏ • ଥͳσϑΥϧτʢλΠϜΞτͳͲʣ ઃܭࢥߟ
Engineering package xhttp type ClientConfig struct {…} func NewClient(config *ClientConfig)
*Client {} func NewRequestX(method string, addr *AddressGroup, path string, body io.Reader) (*Request, error) func (c *Client) DoX(req *Request, option ...CallOption) (*Response, error) func (c *Client) PostX(addr *AddressGroup, path string, contentType string, body io.Reader, options ...CallOption) (resp *Response, err error) { func (c *Client) PostFormX(addr *AddressGroup, path string, data url.Values, options ...CallOption) (resp *Response, err error) func (c *Client) GetX(addr *AddressGroup, path string, options ...CallOption) (resp *Response, err error) { NET/HTTPͱಉ͡ΠϯλʔϑΣΠε
Engineering addrGroup := xhttp.MustNewAddressGroup( //AddressGroup͋ͱ΄Ͳհ͠·͢ “dns: //txt:your-domain.com:8080”, xhttp.WithLoadBalancer(xhttp.RoundRobin), ) reqP,
_ := xhttp.NewRequestX("POST", addrGroup, "/", nil) res, err = client.DoX(reqG) res, err = client.PostFormX(addrGroup, "/", url.Values{}) res, err = client.GetX(addrGroup, "/") ͍ํͷΠϝʔδ
Engineering ߴՄ༻ੑͷ
Upstream 2 die xhttp client Upstream 1 αʔό͍ͭͰࢮ͵Մೳੑ Upstream 3
Engineering • ීஈ Reverse Proxy (VIP)ͳͲར༻͕ଟ͍ • ৽͍͠αʔϏεՃΛ͢Δͨͼʹ৽͍͠ Reverse Proxyಋೖ͢Δ
ͷ͕໘ • Solution • Client Side Load Balancing • ΫϥΠΞϯτίʔϧઌͷαʔόάϧʔϓΛࣗͰίϯτϩʔ ϧ͢Δ͜ͱ • ΫϥΠΞϯτίʔϧઌͷαʔόάϧʔϓɺͲΕΛݺͼग़͢ͷ ͔ͷϩʔυόϥϯγϯάϩδοΫΛ࣮͢Δ͜ͱ αʔόάϧʔϓ͕ඞཁ
Engineering type Address struct { Port string Host string }
type AddressGroup struct { scheme Scheme name string resolver Resolver loadBalancer LoadBalancer cacheAddress []Address closeCh chan interface{} } AddressGroup ʢαʔόάϧʔϓͷநԽʣ
Engineering type Resolver interface { Scheme() Scheme Init(address string) error
UpdateCh(context.Context) <-chan []Address Close() } type LoadBalancer interface { Pick() (Address, error) HandleStateChange(list []Address) error } Resolver + LoadBalancer
Engineering type DnsResolver struct { domain string updateCh chan []Address
doneCh chan interface{} } func (d *DnsResolver) Scheme() Scheme { return Scheme("dns") } func (d *DnsResolver) Init(name string) error { d.resolve() } func (d *DnsResolver) resolve() { go func() { // resolve d.domain d.updateCh <- addresses time.Sleep(TTL) } } Example: DnsResolve
Engineering type roundRobinLB struct { list []Address next uint32 mu
sync.RWMutex } func (rr *roundRobinLB) Pick() (Address, error) { l := len(rr.list) if l == 0 { return Address{}, fmt.Errorf("empty list of address") } v := atomic.AddUint32(&rr.next, 1) return rr.list[int(v)%len(rr.list)], nil } func (rr *roundRobinLB) HandleStateChange(list []Address) error { rr.mu.Lock() defer rr.mu.Unlock() rr.list = list return nil } Example: Round Robin LB
Engineering ͏ଆBOILER PLATE͕΄ͱΜͲͳ͍ addrGroup := xhttp.MustNewAddressGroup( //AddressGroup͋ͱ΄Ͳհ͠·͢ “dns: //txt:your-domain.com:8080”, xhttp.WithLoadBalancer(xhttp.RoundRobin),
) reqP, _ := xhttp.NewRequestX("POST", addrGroup, "/", nil) ϥΠϒϥϦଆͰ schemeύʔεͯ͠Resolver ΛΞαΠϯ͢Δ
Engineering • Load Balancing is impossible • https://www.youtube.com/watch?v=kpvbOzHUakA • Round
Robin Upstreamϗετͷঢ়ଶʢLatency, Φʔόϩʔυঢ় گʣͳͲΛҙࣝͰ͖ͣɺͣͬͱಉ͡ѱ͍ঢ়ଶͷϗετʹಉ͡ϦΫΤε τΛ͛Δɹ • P2C ΞϧΰϦζϜ • Power of 2 Random Choice • Upstreamͷঢ়ଶΛୡඞཁ͋Δ • https://www.eecs.harvard.edu/~michaelm/postscripts/mythesis.pdf ༨ஊ ϩʔυόϥγϯάΞϧΰϦζϜ͍͠
Engineering ճ෮ੑͷ
Engineering Upstream 2 die xhttp client Upstream 1 αʔό͍ͭͰࢮ͵Մೳੑ Upstream
3
Engineering Upstream 2 die xhttp client Upstream 1 die (શʣαʔό͍ͭͰࢮ͵Մೳੑ
Upstream 3 die
Engineering • શʹࢮ͵͡Όͳͯ͘ɺ(GCͳͲͷཧ༝ͰʣLatency͕Ͷ্͕Δ • దͳσϑΥϧτλΠϜΞτ͕ඞཁ • ଈ࣌తͳϦΫΤετࣦഊ (500ΤϥʔͳͲʣ • దͳϦτϥΠ
• ܧଓతͳϦΫΤετࣦഊ (ωοτϫʔΫࣦഊͳͲʣ • Ͱ͖Δ͚ͩૣ͍ஈ֊ͰϦΫΤετΛυϩοϓ͢Δ • CircuitBreakerύʔλϯɿFail Fast Error αʔό͕ࢮ͵ͱ͖Ͳ͏͠·͢ʁ
Engineering • net/httpσϑΥϧτλΠϜΞτ͋Γ·ͤΜʂ • ແݶʹϦΫΤετͭ • xhttpͰσϑΥϧτͰ30sઃఆՄೳɺ֎͔Β͢ͷՄೳ λΠϜΞτʹ͍ͭͯ func NewClient(config
*ClientConfig) *Client { client.client = &http.Client{ Timeout: config.RequestTimeout, Transport: newRoundTripper(config.RoundTripper, config.MetricRegistry), }… }
Engineering Dial TLS Handshake Request Resp Headers Resp Body Idle
Client.Do http.Client.Timeout net.Dialer.Timeout http.Transport.TLSHandshake.Timeout http.Transport.ResponseHeader.Timeout http.Transport.IdleConn.Timeout https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/ ߹ʹΑΓࡉ͔͘ίϯτϩʔϧՄೳ
Engineering • Լखʹretry͢Δ͜ͱʹࣾαʔϏεΛDDOS͢Δ͜ͱ • ඞͣ Backoff ( Exponential )͢Δ͜ͱ •
RetryϦΫΤετείʔϓͷOption (ClientείʔϓͰ͋Γ·ͤΜʣ RETRYʹ͍ͭͯ res, err = client.DoX(reqG, xhttp.WithRetry(&xhttp.RetryOptions{ MaxAttempts: 2, RetryOn: func(response *http.Response) bool { return response.StatusCode != 200 }, TimeoutPerAttempt: time.Second, }))
Engineering • ૣ͍ஈ֊Ͱυϩοϓ͢Δख๏ͷҰͭͱͯ͠ CircuitBreakerύλʔϯɹ • https://engineering.linecorp.com/ja/blog/circuit-breakers-for- distributed-services/ • ϗετͷঢ়ଶΛʮࣦഊ͢ΔϦΫΤετͷʯͰஅ •
ʮࣦഊʯఆٛࣗମϢʔβʹͤΔ • ঢ়ଶʹΑΓʮϦΫΤετՄೳʯͱʮϦΫΤετෆՄೳʯͰ͚Δ • ϦΫΤετෆՄೳͷ߹୯७ʹ FailFastErr ฦ͢ FAIL FASTରࡦʹ͍ͭͯ
Engineering • ׂͱύϥϝʔλ͕ଟ͍ͷͰɺΞϧΰϦζϜࣗମΛཧղ͢Δ্ઃఆ͢Δ ඞཁ͕͋Δ CIRCUIT BREAKER type CircuitBreakerConfig struct {
noop bool FailureRateThreshold float64 MinimumRequestThreshold int64 TrialRequestInterval time.Duration CircuitOpenWindow time.Duration CounterSlidingWindow time.Duration CounterUpdateInterval time.Duration IsFailed FailedJudger KeyBuilder KeyBuilder } client := xhttp.NewClient(&xhttp.ClientConfig{ CircuitBreakerConfig: &xhttp.CircuitBreakerConfig{}, })
Engineering • > ϗετͷঢ়ଶΛʮࣦഊ͢ΔϦΫΤετͷʯͰஅ • Ͳ͏ͬͯૣ͑͘Δʁ ༨ஊɹHIGH PERFORMANCE CIRCUITBREAKERͷͨΊʹ var
c int64 c ++ var c atomic.Int64 c.Add(1) • AtomicͬͯcontentionมΘΒͳ͍ʢಉ͡มʹࢀর͢Δ͜ͱʣ • https://github.com/linxGnu/go-adder • Java LongAdderͷΞΠσΟΞʢatomicΛsharding) • ϚϧνϧʔνϯڥͰatomic.Int64ΑΓ2~4ഒૣ͍
Engineering METRICS/TRACINGͷ
Engineering • ObservabilityνʔϜͳͷͰͦͷॏཁੑΛ͘͢͝ཧղ͍ͯ͠Δ • ͑ͳ͍ͱ͍͚ͳ͍ͷ • ϦΫΤετLatencyߴ͍Ͱ͔͢ʁ • Latencyߴ͍࣌ͳͥʁ OBSERVABILITYͷॏཁੑ
• Latencyߴ͍͔Ͳ͏͔MetricsͰ͑Δ • Metrics Instrumentation prometheus client ͏ • ͳͥʁΛ͑Δͷ Metrics + TracingͰ͑Δ • Tracing Instrumentation zipkin-go
Engineering ROUNDTRIPPERར༻ͯ͠INSTRUMENT type ClientConfig struct { MetricRegistry *prometheus.Registry Tracer *zipkin.Tracer
…… } func newRoundTripper(originRt http.RoundTripper, mr *prometheus.Registry, tc *zipkin.Tracer) *roundtripper { … .. } client.client = &http.Client{ Timeout: config.RequestTimeout, Transport: newRoundTripper(config.RoundTripper, config.MetricRegistry, config.Tracer), }
Engineering • ΧελϚΠζ͢ΔͨΊͷϑοΫ • ϦΫΤετૹΔॲཧΛΧελϚΠζɿ RoundTripperΛ͢ • ίωΫγϣϯΛ࡞ΔॲཧΛΧελϚΠζɿDialContextΛ͢ ༨ஊɹNET/HTTPࢁ ϑοΫఏڙͯ͘͠ΕͯΔ
• ϝτϦΫεΛऔಘ͢ΔͨΊͷϑοΫ • http/ClientTraceेɹ • https://blog.golang.org/http-tracing
Engineering ࠷ޙ
Engineering • Ͱ͖Εࣾɺ͋Δ͍νʔϜڞ௨ͷϥΠϒϥϦἧͬͨ΄͏͕ྑ͍ • http client, log package, metrics instrument…
• ϚΠΫϩαʔϏε͍͠ɺͰ͖Εආ͚ͨ΄͏͕ྑ͍ • ͍ۙ͏ͪʹxhttpΛOSS͢Δ • go͖ͰɺେنγεςϜΛ࡞Γ͍ͨਓ͝࿈བྷ͓ͪͯ͠Γ·͢
Engineering ͝੩ௌ͋Γ͕ͱ͏͍͟͝·͢