Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
マイクロサービス時代 のHTTPクライアントの作り方 / how we build our ...
Search
LINE Developers
July 13, 2019
Technology
2.1k
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.6k
Java 21 Overview
line_developers
6
1.4k
Code Review Challenge: An example of a solution
line_developers
1
1.7k
KARTEのAPIサーバ化
line_developers
1
660
著作権とは何か?〜初歩的概念から権利利用法、侵害要件まで
line_developers
5
2.4k
生成AIと著作権 〜生成AIによって生じる著作権関連の課題と対処
line_developers
3
2.6k
マイクロサービスにおけるBFFアーキテクチャでのモジュラモノリスの導入
line_developers
9
4.2k
A/B Testing at LINE NEWS
line_developers
3
1.2k
LINEのサポートバージョンの考え方
line_developers
2
1.6k
Other Decks in Technology
See All in Technology
AIエージェント時代、Kaggleにどう取り組むか
takanao
1
190
バフェットコード開発チームの心得(v1.1)
shoe116
0
110
AIコーディングを実践してきた1年を振り返る / Looking Back on a Year of Practicing AI Coding
takedatakashi
1
140
CSS2026:OWS研究会・招待講演「世界観を、実装する」
atsush1_sada
2
340
1週間、Opus封印でお願いします
kintotechdev
0
210
Teaching Python with three kinds of AI
reuven
0
120
なぜAI時代に技術記事を書くのか?どう書くのか? 〜bunの場合〜
kworkdev
PRO
0
150
2026-10-24 JAWS JAWS-UG 茨城 #18 IAM Policy Autopilotってなにさ。terraform planからIAM Policyつくれるの? / What's IAM Policy Autopilot
masasuzu
0
170
「作れる」と「リリースできる」の間にあったもの── PdMを外して見えた、PdMがやるべき仕事/Buildable ≠ Shippable: What Removing the PM Taught Me About the PM’s Job
yappli_developers
0
290
AWS DevOps Agentはどこまで任せられるか 〜機能の現在地と、機能拡張の実践〜
nyankotaro
0
250
VLA-JEPA: Enhancing Vision-Language-Action Models with Latent World Models
takmin
0
330
推論基盤と Scale-Up Interconnect の現状と制約から俯瞰する技術動向
markunet
2
300
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
260
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Raft: Consensus for Rubyists
vanstee
143
7.8k
It's Worth the Effort
3n
188
29k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Design in an AI World
tapps
1
360
A Modern Web Designer's Workflow
chriscoyier
699
190k
HDC tutorial
michielstock
2
980
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
470
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
560
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
900
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 ͝੩ௌ͋Γ͕ͱ͏͍͟͝·͢