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
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.6k
Java 21 Overview
line_developers
6
1.3k
Code Review Challenge: An example of a solution
line_developers
1
1.7k
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.2k
LINEのサポートバージョンの考え方
line_developers
2
1.6k
Other Decks in Technology
See All in Technology
運用を犠牲にせずコストを制御し事業成長を支える B2B SaaS ID管理基盤におけるS3 Tableのログストレージ活用
kaminashi
1
130
なぜ、あなたのエージェントは言うことを聞かないのか
segavvy
1
610
PLaMoを毎日の開発で使い育てていく
pfn
PRO
0
170
大 AI 時代におけるC# の事情 ~ぶっちゃけトークを交えながら~
nenonaninu
1
620
もう一度考える SRE チームの作り方・育て方 / Rethinking SRE #1: Building and Growing SRE Teams
rrreeeyyy
4
640
ガバメントクラウドでのランサムウェア対策
techniczna
1
520
クラウドセキュリティ入門 ~安全なクラウド利用のための基礎知識~
lhazy
7
5.9k
13年運用タイトルのサーバーサイドが辿り着いた現在地 ― モンスターストライクにおける技術・組織・AI活用から得た知見
mixi_engineers
PRO
1
380
BigQuery を検索ソースとした AI Agent の作り方って 〇〇 通りあんねん
satohjohn
0
150
データ組織の転換期 一足飛びしない段階的戦略
leveragestech
PRO
0
140
Webの技術とガジェットで子どもも大人も楽しめるワクワク体験を提供する / Qiita Tech Festa Day 2026
you
PRO
1
330
AIQAのナレッジ構築について
qatonchan
1
140
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
270
First, design no harm
axbom
PRO
2
1.2k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
330
Building AI with AI
inesmontani
PRO
1
1.1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
230
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
The Invisible Side of Design
smashingmag
301
52k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
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 ͝੩ௌ͋Γ͕ͱ͏͍͟͝·͢