Share
Embed
Perlでも分散トレーシングしたい!AWS::XRay による解析とその実装 / YAPC::Tokyo 2019
YAPC::Tokyo 2019 のトークです
FUJIWARA Shunichiro
January 26, 2019
Transcript
88 slides
-
ࢄτϨʔγϯάͷඞཁੑ ࢄγεςϜ(ϚΠΫϩαʔϏε)Ͱͻ ͱͭͷॲཧ͕ෳͷίϯϙʔωϯτʹ· ͕ͨΔ ύϑΥʔϚϯεͷ͕͔ΓͮΒ͍ োΛݟ͚ͭΔͷ͍͠ ਤ Dapperจ 1 ΑΓ
1 https://ai.google/research/pubs/pub36356 -
֓೦ Span ҎԼͷཁૉΛͭ ໊લ ։࢝࣌ࠁ ऴྃ࣌ࠁ Context (ID, Trace-ID, Parent)
Tag {Key: Value},... Log {Key: Value},... -
ࢄτϨʔγϯάͷ࣮ͱ༷ Zipkin(OpenZipkin)2: Twitter → OSS 2012 Jeager3: Uber → CNCF
OSS 2016 OpenTracing4: ࢄτϨʔγϯάͷ༷ CNCF 2016 AWS X-Ray: AWS͕ఏڙ ϚωʔδυαʔϏε 2016 StackDriver Trace: Google͕ఏڙ ZipkinΫϥΠΞϯτޓ 2017 4 https://opentracing.io/ 3 https://www.jaegertracing.io/ 2 https://zipkin.io/ -
AWS X-Ray ͷߏཁૉ6 X-Ray API AWS͕ఏڙ͍ͯ͠ΔAPI X-Ray daemon τϨʔεసૹ༻σʔϞϯ X-Ray
SDK X-Ray daemonʹτϨʔεΛૹ৴͢Δͨ ΊͷϥΠϒϥϦ X-Ray console τϨʔεΛՄࢹԽ͢ΔViewer 6 https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/aws-xray.html -
ͲͷΑ͏ʹτϨʔεΛૹ৴͢Δ͔ X-Ray daemon7 ͕ UDP port 2000 Λ listen ΞϓϦέʔγϣϯ(SDK)͔ΒτϨʔεσʔλΛUDPͰ͛Δ
{"format": "json", "version": 1} { "trace_id": "1-5759e988-bd862e3fe1be46a994272793", "id": "defdfd9912dc5a56", "start_time": 1461096053.37518, "end_time": 1461096053.4042, "name": "MyApp" } 7 https://github.com/aws/aws-xray-daemon -
ͲͷΑ͏ʹτϨʔεΛૹ৴͢Δ͔ X-Ray daemon ͕όοϑΝϦϯάͯ͠όονͰ X-Ray API ʹૹ৴ X-Ray API ʹಧ͍ͨ͋ͱશʹϚωʔδυ
σʔλอ࣋ 30(ݹ͍ͷফ͑Δ) τϨʔεͱදࣔ࣌ͷεΩϟϯͨ͠ྔʹΑΔશैྔ՝ۚ -
X-Ray ͷΞʔΩςΫνϟͷ͍͍ͱ͜Ζ τϨʔεσʔλେྔʹൃੜ͢Δ 1ϦΫΤετॲཧதʹଟ͍ͱेҎ্ ຖճΞϓϦέʔγϣϯ͔Βಉظ௨৴(TCP) → ϨΠςϯγ૿Ճʹ݁͢Δ ಛʹো࣌ X-Ray daemon
ʹUDPͰ͛ͬͺͳ͠ → ΞϓϦέʔγϣϯͷӨڹ͕ܰඍ X-Ray daemon ͕མ͍ͪͯͯΞϓϦʹӨڹ͠ͳ͍ -
X-Ray SDK τϨʔεΛ X-Ray daemon ʹૹΔϥΠϒϥϦ AWS͕ఏڙ͍ͯ͠Δͷ Java, Go, Node,
Python, Ruby, .NET ͋Εʁࠓ YAPC (Yet Another Perl Conference)… -
AWS::XRay Λॻ͖·ͨ͠ ཁ͢Δʹ JSON Λ UDP Ͱ͛Ε͍͍͚ͩ ͳͷͰ؆୯ 300ߦ͙Β͍͔͠ͳ͍ capture
$name, sub {} ͰηάϝϯτΛ࡞ͬͯૹ৴ use AWS::XRay qw/ capture /; capture "myApp", sub { capture "foo", sub { # do something ... capture "bar", sub { # ... }; }; }; -
Plack::Middleware::XRay ΈࠐΉͱτϨʔεΛ։࢝ͯ͘͠ΕΔ Plack Middleware 100ߦ͙Β͍ .psgi Ͱ enable ͢Δ͚ͩ (Φϓγϣϯޙड़)
use Plack::Builder; builder { enable "XRay", name => "myApp"; $app; }; -
AWS::XRay ։ൃܦҢ Perl Ͱ X-Ray ͍͍ͨ… → JSONΛUDPͰ͛Δ͚ͩͩ͠؆୯ͩΑͶʁ → ͰτϨʔεࠐΉͷΊΜͲ͍͘͞ͳ…
→ ! Devel::KYTProf ͕औͬͨ݁ՌΛૹΕʂ -
Devel::KYTProf::Logger::XRay Devel::KYTProf ͱ͍͏ϓϩϑΝΠϥͷϩΨʔͱͯ͠ಈ࡞ͯ͠ τϨʔεσʔλΛૹ৴ Devel::KYTProf use ͢Δ͚ͩͰDBIͳͲͷݺͼग़͠Λܭଌ ϩάΛग़ྗͯ͘͠ΕΔศརϓϩϑΝΠϥ use
Devel::KYTProf; # your code 315.837 ms [DBI::st] select * from table where name = ? (1 rows) | main:23 1464.204 ms [LWP::UserAgent] GET http://www.hatena.ne.jp/ | main:25 -
AWS::XRay ։ൃܦҢ Perl Ͱ X-Ray ͍͍ͨ… → JSONΛUDPͰ͛Δ͚ͩͩ͠؆୯ͩΑͶʁ → ͰτϨʔεࠐΉͷΊΜͲ͍͘͞ͳ…
→ ! Devel::KYTProf ͕औͬͨ݁ՌΛૹΕʂ → Logger ࠩ͠ସ͑Ͱ͖Δ KYTProf++ ਖ਼ KYTProf ͕ͳ͔ͬͨΒ࡞ͬͯͳ͔͔ͬͨ͠Εͳ͍ -
ISUCON is ͳʹ ͍͍ײ͡ʹεϐʔυΞοϓίϯςετͷུ ఏڙ͞Εͨαʔό্Ͱಈ͘WebΞϓϦέʔγϣϯΛߴԽ !!!!!!!!!! ༏উۚ100ສԁ 2011͔Βຖ։࠵͞Ε͍ͯΔ (ओ࠵ LINEࣾ)
2018ͷ ISUCON 8 Λ DeNA ͞ΜͱΧϠοΫͰग़ ࣍ͷ karupanerura ͞ΜʹΑΔ ʮISUCON8༧બ࡞ͷཪଆʯͷτʔΫͰ͢ -
ISUCON 8 ຊબ Ծ௨՟औҾαʔϏε ISUCOIN ۜߦAPI, ϩάهAPIӡӦ͕༻ҙͨ͠ ϒϥοΫϘοΫεͰఏڙ͞Εɺhttps Ͱ ϦΫΤετΛૹΔඞཁ͕͋Δ
֎෦APIݺͼग़͠Λ͍͔ʹ্ख͘ॲཧ͢ Δ͔͕ϙΠϯτ -
Perl ࣮ʹ AWS::XRay ΛΈࠐΉ ఏڙ͞Εͨݴޠ࣮ Go, Perl, PHP, Python, Ruby
YAPC ͳͷͰવ Perl ࣮Ͱ https://github.com/isucon/isucon8-final -
X-Ray daemon Λ༻ҙ ॳظ࣮ docker-compose ͳͷͰదʹ Dockerfile Λ༻ҙ8 FROM amazonlinux
RUN yum install -y unzip RUN curl -o daemon.zip https://s3.dualstack.us-east-2.amazonaws.com/ aws-xray-assets.us-east-2/xray-daemon/aws-xray-daemon-linux-3.x.zip RUN unzip daemon.zip && cp xray /usr/bin/xray ENTRYPOINT ["/usr/bin/xray", "-b", "0.0.0.0:2000", "--local-mode"] EXPOSE 2000/udp 8 https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-daemon-local.html -
docker-compose.yml services: isucoin: environment: # ུ AWS_XRAY_DAEMON_ADDRESS: 'xray:2000' links: -
mysql - xray xray: build: xray environment: AWS_REGION: "ap-northeast-1" AWS_ACCESS_KEY_ID: "000000000000" AWS_SECRET_ACCESS_KEY: "****" -
AWS::XRay ΈࠐΈ app.psgi ʹ5ߦՃ + cpanfile # app.psgi use Devel::KYTProf::Logger::XRay;
use AWS::XRay; Devel::KYTProf->logger("Devel::KYTProf::Logger::XRay"); builder { enable 'XRay', name => 'isucoin'; # ... # cpanfile requires 'AWS::XRay'; requires 'Plack::Middleware::XRay'; requires 'Devel::KYTProf::Logger::XRay'; -
ϘτϧωοΫൃݟ SELECT * FROM trade ORDER BY id DESC 23ສߦΛಡΈऔͬͯ1ߦࣺ͍ͬͯͯͯΔ
LIMIT 1 ͢Ε OK ! ʮ͜ΕͭʹࢄτϨʔγϯά͍Βͳ͍ΑͶ?ʯ ! ʮslowlog ݟΕ͔ΔΖʯ -
֎෦API࣮ʹ X-Ray ΛΈࠐΜͰΈΔ (ڝٕͰ࣮ࡍϒϥοΫϘοΫε͚ͩͲ) xray-sdk-go ΛΈࠐΈ // sql.Open -> xray.SQL
db, err := xray.SQL("mysql", dsn) // http.Handler Λ xray.Handler Ͱ wrap return xray.Handler( xray.NewFixedSegmentNamer("Isubank"), myHandler, ) -
Perl ଆͷ HTTPϦΫΤετૹ৴ capture ݺͼग़͠ݩΛ͑ΔͨΊʹ X-Amzn-Trace-ID ϔομΛ༩ capture "externalHTTP", sub
{ my $segment = shift; $res = $self->client->post( $self->endpoint . $p, [ "Content-Type" => "application/json", "Authorization" => "Bearer " . $self->app_id, "X-Amzn-Trace-ID" => $segment->trace_header, ], $body, ); }; -
ϓϩηεΛ·͕ͨͬͨͷΈ Isucoin(Perl) ϦΫΤετ։࢝࣌ʹ X-Amzn-Trace-ID Λൃߦ 1-5c4902d7-e8fe620cab66e01e57df8a12 1-[timestamp]-[unique_id] sprintf( "1-%x-%s", CORE::time(),
unpack("H*", Crypt::URandom::urandom(12)), ); -
֎෦ϦΫΤετݺͼग़͠ʹϔομΛ༩ use AWS::XRay qw/capture/; capture "externalHTTP", sub { # Ͳ͜ͰݺΔ(͕͍ͳ͚ΕRootʹͳΔ)
my $segment = shift; $furl->POST( "https://example.com", [ "X-Amzn-Trace-ID" => $segment->trace_header ], $body, ); }; POST / HTTP/1.1 Host: example.com X-Amzn-Trace-ID: Root=1-5c4902d7-e8fe620cab66e01e57df8a12;Parent=851cf9ec07b528c2 ... -
ϔομΛड৴ͨ͠API(Isubank)͕Ҿ͖ܧ͙ Root=1-5c4902d7-e8fe620cab66e01e57df8a12;Parent=851cf9ec07b528c2 # ࣮ࡍGo͚ͩͲઆ໌ͷͨΊʹPerl AWS::XRay::Segment->new( id => new_id(), trace_id =>
"1-5c4902d7-e8fe620cab66e01e57df8a12", parent_id => "851cf9ec07b528c2", ); ͦͷτϨʔεΛ X-Ray daemon ૹ৴ → X-Ray consoleͰτϨʔε͕࿈݁ͯ͠දࣔ͞ΕΔ -
τϨʔε͍ͨ͠ͱ͜ΖͰʮݱࡏͷʯRootParent͕ඞཁ package App; sub main { capture "App::main", sub {
# Root my $segment = shift; Model::call($param); # ֎෦ݺͼग़͠Λ͏ॲཧ }; }; package Model; sub call() { my $param = shift; # ࣮ࡍʹ֎ΛݺͿͷ͕ͩ͜͜ݺͼग़͠ݩͷsegmentΛΒͳ͍ͱRoot͕Θ͔Βͳ͍ $furl->post($url, [ "X-Amzn-Trace-ID" => "????", ], $param); } call($param)Λcall($segment,$param)ʹॻ͖͑ͨ͘ͳ͍ -
AWS::XRay ͰҾΛ͞ͳ͍͍ͯ͘Α͏ʹͳͬͯΔ package App; sub main { capture "App::main", sub
{ # Root my $segment = shift; Model::call($param); # ֎෦ݺͼग़͠Λ͏ॲཧ }; }; package Model; sub call() { my $param = shift; # ͷ͜ͱΒͳ͍͚Ͳͱʹ͔͘ capture ͢ΕΑ͍ capture "Model::call", sub { my $segment = shift; # ͔ΒݺΕ͍ͯΕࣗಈతʹࢠʹͳΔ $furl->post($url, [ "X-Amzn-Trace-ID" => $segment->trace_header, ], $param); }; } -
Ͳ͏࣮ͬͯ͞Ε͍ͯΔ͔ Perl ͷຐ๏ͷͻͱͭ local perldoc -f local ͋ͳ͕ͨຊʹΜͰ͍Δͷ my ͷํͰ͠ΐ͏;
local ΄ͱΜ Ͳͷਓʑ͕ʮϩʔΧϧʯͱߟ͑Δͷͱ ҧ͏͔ΒͰ͢ɻ "local" ϦετΞοϓ͞ΕͨมΛɺғ͍ͬͯΔϒϩοΫɺ ϑΝΠϧɺeval ͷதͰɺϩʔΧϧͳͷʹ͠·͢ɻ !!!!!!! -
local → μΠφϛοΫείʔϓ (ݺͼग़͠ݩͰείʔϓ͕ܾ·Δ) my → ϨΩγΧϧείʔϓ (ιʔείʔυͷࣈ໘Ͱείʔϓ͕ܾ·Δ) package main;
our $Foo = "A"; # ύοέʔδม sub foo { print $Foo; } foo(); #= A { local $Foo = "B"; # ͜ͷϒϩοΫ͔ΒݺΕ͍ͯΔؒB foo(); #= B } foo(); #= A ϒϩοΫΛൈ͚ΔͱࣗಈతʹΔ -
Կճωετͯ͠ݺͼग़ͯ͠ॱ൪ʹ্ॻ͖ͯ͠ɺͲΕ෮ݩ foo(); #= A { local $Foo = "B"; foo();
#= B { local $Foo = "C"; foo(); #= C { local $Foo = "D"; foo() #= D } foo(); #= C } foo(); #= B } foo(); #= A -
AWS::XRay Ͱ۩ମతʹ͜Μͳײ͡ ݱࡏͷ Trace-ID, Segment-ID Λ local Ͱอ࣋ package AWS::XRay;
our $TRACE_ID; # Root our $SEGMENT_ID; # ݱࡏͷSegmentID sub capture { my ($name, $code) = @_; # $TRACE_ID͕ະఆٛͳΒRootͳͷͰ৽نIDൃߦ local ʹ local $TRACE_ID = $TRACE_ID // new_trace_id(); # ৽͍͠ηάϝϯτΛ࡞Δ # $SEGMENT_ID ͕͋Ε parent_id => $SEGMENT_ID ʹͳ͍ͬͯΔ my $segment = AWS::XRay::Segment->new({ name => $name, type => $SEGMENT_ID ? "subsegment" : undef, parent_id => $SEGMENT_ID, }); -
local $SEGMENT_ID = $segment->{id}; # ৽͍͠ηάϝϯτIDΛ্ॻ͖ͯ͠localʹଋറ # ίʔυΛ࣮ߦ # ͜ͷதͰ
$SEGMENT_ID ͕ઃఆ͞Ε͍ͯΔͷͰ # ͞Βʹ capture ͨ͠Β $segment ͷࢠڙʹͳΔ $ret = $code->($segment); $segment->close(); # ηάϝϯτσʔλૹ৴ return $ret; # $segment ফ͑Δ(my͔ͩΒ) # $SEGMENT_ID ݺͼग़࣌͠ͷʹΔ # RootͳΒ $TRACE_ID ফ͑Δ(ݩ͕ະఆ͔ٛͩΒ) } -
༨ஊ Go Ͱ X-Ray SDK Λ͏߹ ϦΫΤετͰൃੜͨ͠ context.Context ΛͲ͜·Ͱ Ҿʹ͍͔ͯ͠ͳ͍ͱτϨʔεͰ͖ͳ͍
్தʹ ctx ΛҾ͖ܧ͛ͳ͍ϥΠϒϥϦ(ORMͱ͔)͕ڬ·Δͱ (Isubank ࣮ࡍ40ՕॴҎ্ ctx Λ͢Α͏ʹॻ͖͑ͨ) -
! ίετͷ ʮX-Ray Αͦ͞͏͚ͩͲɺ͓ߴ͍ΜͰ͠ΐ͏…?ʯ ίετ = X-Ray ར༻ྉۚ ؒίετ =
ΞϓϦέʔγϣϯͷύϑΥʔϚϯεྼԽ (݁Ռతʹ༻Ϧιʔε͕૿͑ΔɺϢʔβମݧ͕ଛͳΘΕΔͳͲ) -
ΞϓϦέʔγϣϯͷύϑΥʔϚϯεྼԽ τϨʔεΛΈࠐΉ͜ͱʹΑͬͯͲΕ͙Β͍͘ͳΔ͔ • 1ॲཧͰ100ݸͷ capture (ίʔυۭ sub{}) Λੜ • αϯϓϦϯά͠ͳ͍ͰશͯͷτϨʔεΛૹ৴
Λ 500/sec ఔ࣮ߦͰ͖Δ (macbook pro 13 2017) ͭ·Γ1ॲཧ͋ͨΓ2msఔͷΦʔόʔϔου τϨʔεΛૹ৴͠ͳ͍(captureΛωετ͢Δ͚ͩ)ͳΒ 10,000/sec, 0.1msఔͷΦʔόʔϔου -
X-Ray ར༻ྉۚ ຖ݄ͷແྉ τϨʔεͷه 10 ສճ·Ͱແྉ τϨʔεͷऔಘͱεΩϟϯ߹Θͤͯ 100 ສճ·Ͱແྉ ՃͰ
τϨʔεͷه 100 ສ݅͋ͨΓ 5 USD τϨʔεͷऔಘͱεΩϟϯΛ߹Θͤͯ 100 ສ݅͋ͨΓ 0.50 USD -
࣮ࡍͲΕ͙Βֻ͍͔Δͷʁ ฏۉ 100 req/sec ͷ߹ 100 * 86,400 * 30
/ 1,000,000 * 5 USD = 1,296 USD ฏۉ 1,000 req/sec ͳΒ 12,960 USD / month શͯͷϦΫΤετʹ͍ͭͯه͢Δͷίετ͕ߴ͍ -
αϯϓϦϯάͷ ྫɿ1ඵ͝ͱʹ࠷ॳͷϦΫΤετͱ ՃϦΫΤετͷ5%Λه (ެࣜSDKͷσϑΥϧτઃఆ) 100 req/sec ͷ߹ 1 + 100
* 5% = 6 req/sec ͕ه͞ΕΔ ϦΫΤετ͕গͳͯ͘ 1 req/sec ࣮֬ʹه ެࣜ SDK X-Ray console ͔ΒαϯϓϦϯάϧʔϧΛઃఆՄ (AWS::XRay ͰະରԠ…) -
αϯϓϦϯάϧʔϧΛίʔυͰهड़ PSGI $env Λड͚औͬͯਅِΛฦ͢ίʔυΛࢦఆͰ͖Δ enable "XRay" name => "myApp", sampler
=> sub { my $env = shift; state %paths; if ( $paths{$env->{PATH_INFO}++ == 0 ) { # ಛఆͷPATHΛॳΊͯड৴ͨ͠߹ඞͣه return 1; } rand() < 0.05; # ͦΕҎ֎ 5% }; -
Τϥʔ͍ϦΫΤετඞͣه͍ͨ͠ 5% αϯϓϦϯάˠ ΤϥʔΛهͰ͖Δ֬5% શϦΫΤετͰϝϞϦ্ʹτϨʔεΛอଘ͓ͯ͘͠ ϨεϙϯεΛฦ࣌͢ͰτϨʔεΛૹ৴͢Δ͔Ͳ͏͔ΛܾΊΔ enable "XRay" name =>
"myApp", response_filter => sub { my ($env, $res, $elapsed) = @_; # 5xx OR 1ඵҎ্ֻ͔ͬͨ߹ʹૹ৴ return $res->[0] >= 500 || $elapsed >= 1; }; -
·ͱΊ ࢄτϨʔγϯάύϑΥʔϚϯεɺোղੳʹେม༗༻ ର ISUCON ༻ܾઓฌثͱͯ͠༗༻ AWS X-Ray ϚωʔδυͰಋೖ͕༰қ αϯϓϦϯάઃఆʹཁҙ !
Perl SDK ͳ͔ͬͨͷͰ AWS::XRay Λ࡞ͬͨ पลϞδϡʔϧؚΊͯඦߦͰ͍͍͔Μ͡ʹ