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

AWS Lambdaで実現するスケーラブルで低コストなWebサービス構築/YAPC::Hako...

AWS Lambdaで実現するスケーラブルで低コストなWebサービス構築/YAPC::Hakodate2024

YAPC::Hakodate 2024 前夜祭 rejectcon

FUJIWARA Shunichiro

October 04, 2024
Tweet

More Decks by FUJIWARA Shunichiro

Other Decks in Technology

Transcript

  1. @fujiwara ໘ന๏ਓΧϠοΫSREνʔ Ϝ ISUCON 1,2,5,11 ! ༏উ4ճ ISUCON 3,8,12ʙ14 ӡӦ(ग़୊)

    github.com/kayac/ecspresso Amazon ECS σϓϩΠπʔϧ github.com/fujiwara/lambroll AWS Lambda σϓϩΠπʔϧ
  2. AWS Lambdaͷجຊ FaaS = Function as a Service αʔόʔΛ͋Β͔͡Ί༻ҙͤͣɺΫϥ΢υ্ʹσϓϩΠͨ͠ ʮؔ਺ʯΛ࣮ߦ͢ΔαʔϏε

    ؔ਺=ʮೖྗΛड͚औͬͯ (ॲཧΛߦ͍) ग़ྗΛฦ͢΋ͷʯ use v5.40.0; sub sum ($a, $b) { return $a + $b; }
  3. Lambda༻ͷ sum ؔ਺ͷྫ use v5.40.0; sub sum ($event, $context) {

    my $a = $event->{a}; my $b = $event->{b}; return { sum => $a + $b }; } ͜ΕΛLambdaʹσϓϩΠ(ৄࡉུ)→ʮؔ਺ʯΛݺͼग़ͤΔ $ aws lambda invoke \ --function-name sum \ --payload '{"a":1, "b":2}' \ --cli-binary-format raw-in-base64-out \ /dev/stdout {"sum":3}
  4. LambdaͰHTTPΛॲཧ͢ΔͨΊͷํ๏ 1. Amazon API Gateway 2. Application Load Balancer(ALB) 3.

    Lambda Function URLs AWS͕༻ҙ͍ͯ͠ΔϚωʔδυͳ΋ͷ (ଞʹ΋Ͱ͖Δ͕ޙड़)
  5. Amazon API Gateway (2015ʙ) ϦΫΤετͷϧʔςΟϯά΍ม׵ɺೝূɺೝՄͳͲߴػೳ VPC಺ʹઃஔՄɺLambdaҎ֎ͷόοΫΤϯυ΋ࢦఆͰ͖Δ Application Load Balancer(ALB) (2018ʙ)

    ϩʔυόϥϯαʔͷλʔήοτͱͯ͠LambdaΛ௥ՃͰ͖Δ Path/ϔομϕʔεͰͷϧʔςΟϯά VPC಺ʹઃஔՄɺίετ͸ଟগֻ͔Δ(ݻఆඅ༻) Lambda Function URLs (2022ʙ) Lambdaؔ਺/aliasʹ1:1ରԠͨ͠URLΛൃߦ(VPC಺ෆՄ) ϧʔςΟϯά͸Ͱ͖ͳ͍ɺγϯϓϧɺ௿ίετ
  6. LambdaͰHTTPϦΫΤετ GET /sum?a=1&b=2 HTTP/1.1 Host: example.com ↓͜ͷϦΫΤετΛLambda͕ड৴͢Δͱ͖ͷΠϕϯτ2 { "httpMethod": "GET",

    "path": "/sum", "headers": {"Host": "example.com"}, "queryStringParameters": {"a": "1", "b": "2"}, } 2 (Πϝʔδ) API GW(v1,v2), ALB, Function URLͰΠϕϯτͷܗࣜ͸ඍົʹҟͳΔ
  7. LambdaͰHTTPϨεϙϯε { "statusCode": 200, "headers": {"Content-Type": "application/json"}, "body": "{\"sum\":3}" }

    ↓͜ͷϨεϙϯεΛLambda͕ฦ͢ͱ HTTP/1.1 200 OK Content-Type: application/json {"sum":3}
  8. ͜ΕΛશ෦ࣗ෼Ͱॲཧ͢Δͱ… sub handler ($event, $context) { my $path = $event->{path};

    if ($path eq '/sum') { # pathͷϧʔςΟϯάॲཧ my $a = $event->{queryStringParameters}->{a}; my $b = $event->{queryStringParameters}->{b}; # ϨεϙϯεΛฦ͢ return { statusCode => 200, headers => {'Content-Type' => 'application/json'}, body => encode_json({ sum => $a + $b }), }; } return { statusCode => 404, headers => { 'Content-Type' => 'text/plain' }, body => 'Not Found', }; }
  9. ϑϨʔϜϫʔΫΛ࢖͍͍ͨ ͍·Ͳ͖ϧʔςΟϯά΍Ϩεϙϯεੜ੒Λࣗ෼Ͱॻ͖ͨ͘ͳ͍ use Kossy; get '/sum' => sub ($self, $c)

    { my $a = $c->req->param('a'); my $b = $c->req->param('b'); return $c->render_json({ sum => $a + $b }); }; ͜Ε͚ͩͰࡁΉ
  10. HTTPϦΫΤετ/Ϩεϙϯε㱻LambdaͷΠϕϯτ ͜ͷม׵͕Ͱ͖Ε͹ैདྷͷϑϨʔϜϫʔΫΛͦͷ··࢖͑Δʂ Perlͷ৔߹ AWS::Lambda::PSGI Λ࢖͑͹؆୯ use AWS::Lambda::PSGI; my $app =

    require "$ENV{'LAMBDA_TASK_ROOT'}/app.psgi"; my $func = AWS::Lambda::PSGI->wrap($app); sub handle { return $func->(@_); }
  11. Goͷ৔߹ fujiwara/ridge3 (2016ʙ) import "github.com/fujiwara/ridge" func main() { var mux

    = http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "Hello") } ridge.Run(":8080", "/", mux) } Goͷඪ४ net/http ͷϋϯυϥΛͦͷ··࢖͑Δ Lambda্Ͱ͸ؔ਺ɺଞͷ؀ڥͰ͸HTTPαʔόͱͯ͠ಈ࡞ ίʔυ͸มߋ͢Δඞཁ͕ͳ͍(=ಉ͡όΠφϦͰOK) 3 https://github.com/fujiwara/ridge
  12. ެࣜ awslabs/aws-lambda-go-api-proxy4 (2018ʙ) import "github.com/aws/aws-lambda-go/lambda" import "github.com/awslabs/aws-lambda-go-api-proxy/httpadapter" func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "Hello") }) lambda.Start(httpadapter.New(http.DefaultServeMux).ProxyWithContext) } ࣮ߦ؀ڥΛࣗಈ൑ผ͠ͳ͍ɻhttpαʔόΛىಈ͢Δʹ͸ ࣗ෼Ͱ൑ผ or main(όΠφϦ)Λ෼͚Δ 4 https://github.com/awslabs/aws-lambda-go-api-proxy
  13. τʔφϝϯτܗࣜ - উͪ࢒Γઓ γϯάϧΠϦϛωʔγϣϯ ⭐ 6 ɹ1ճෛ͚ͨΒऴΘΓ ɹ೔ຊޠͰ୯ʹʮτʔφϝϯτʯͱݴͬͨΒେ఍͜Ε μϒϧΠϦϛωʔγϣϯ ⭐

    ɹ2ճෛ͚ͨΒऴΘΓɺ1ճෛ͚ͨΒഊऀαΠυʹ·ΘΔ ɹΦϦϯϐοΫͷॊಓ͸มଇμϒϧΠϦϛωʔγϣϯ εςοϓϥμʔ ϓϩ໺ٿΫϥΠϚοΫεγϦʔζͷ͋Ε 6 ⭐ ͸TonamelͰαϙʔτ͍ͯ͠Δܗࣜ
  14. TonamelͷΞʔΩςΫνϟ 2017೥ ϦϦʔε Amazon EC2 + Perl + MySQL(Aurora) +

    Redis(ElastiCache) ͍ΘΏΔී௨ͷϞϊϦγοΫWebΞϓϦέʔγϣϯ 2020೥ EC2 → ECS & GoͰϚΠΫϩαʔϏε ຊମͷWebΞϓϦέʔγϣϯ(Perl)ͷػೳΛ GoͰ࣮૷͞ΕͨϚΠΫϩαʔϏεʹҠߦ͍ͯ͘͠ ৽ػೳ͸جຊతʹGoͰ࣮૷ վम͸͍ܰ͘͝΋ͷͳΒPerlͰɺେ͖͍΋ͷ͸GoͰ
  15. ECS → Lambda ҠߦͰ΍ͬͨ͜ͱ net/http.Server → fujiwara/ridge αΠυΧʔͷॲཧΛ֎ʹग़͢ Fluentd: ϩάసૹ

    katsubushi: IDൃߦϛυϧ΢ΣΞ ΞϓϦέʔγϣϯͷίʔυࣗମ͸มߋͳ͠ पล෦ͷΈͷมߋͰLambdaʹҠߦͰ͖ͨ
  16. katsubushi ͷҠߦ github.com/kayac/go-katsubushi Int64ͷIDΛൃߦ͢Δϛυϧ΢ΣΞ DBͷauto incrementΛ࢖Θͣʹߴ଎ʹ int64ͷҰҙͳIDΛൃߦ͢Δ memcached protocol(text/binary) HTTP,

    gRPC ʹରԠ ʲࢀߟʳYAPC::Fukuokaͷൃද9,blog10 10 https://techblog.kayac.com/katsubushi-introduction.html 9 https://speakerdeck.com/fujiwara3/katsubushi
  17. Ҡߦखॱ Internal ALBͷλʔήοτͱͯ͠ECSͱLambdaΛ྆ํ௥Ճ ՃॏϧʔςΟϯάͰঃʑʹτϥϑΟοΫΛҠߦ Lambda:ECS = 10:90 → 50:50 →

    100:0 ண໨఺ ෛՙ͕૿Ճͨ͠λΠϛϯάͰCold Start͕ൃੜ͢Δ͸ͣ ͜ͷλΠϛϯάͰϨΠςϯγ͕૿Ճ͢ΔՄೳੑ͕͋Δ͕…? ⭕ ϩάͰ͸1ඵҎ಺ͰىಈͰ͖͍ͯΔ ⭕ ALBܦ༝ͰͷϨΠςϯγ΋໰୊ͳ͠
  18. ։ൃ/ϓϨϏϡʔ؀ڥ͸? ։ൃ࣌ ridge / AWS::Lambda::PSGIΛ࢖͑͹ ͦͷ··ϩʔΧϧͰಈ͔ͤΔ ϓϨϏϡʔ؀ڥ ECSͰ͸ mirage-ecs acidlemon/mirage-ecs13

    ECSͰ޷͖ͳ͚ͩ։ൃ؀ڥΛ࡞ΕΔ ؀ڥ͝ͱʹURLΛൃߦͯ͠ϧʔςΟϯά (proxy)ͯ͘͠ΕΔϛυϧ΢ΣΞ14 14 https://speakerdeck.com/fujiwara3/yapc-hiroshima-2024 13 github.com/acidlemon/mirage-ecs
  19. LambdaͰ΋ϓϨϏϡʔ؀ڥ ࡞Γ·ͨ͠ fujiwara/lamux15 Lambda multiplexer URLͰaliasΛ൑ผͯ͠invoke͢Δ foo.example.com → invoke alias=foo

    bar.example.com → invoke alias=bar ݺͼग़͠ઌͷؔ਺͸HTTPॲཧ͢Δલఏ (ෳ਺ؔ਺ͷinvokeʹ΋ରԠ) 15 https://github.com/fujiwara/lamux
  20. Lamux ͷ࣮ྫ perlbatross.kayac.com ΧϠοΫఏڙͷίʔυΰϧϑاը Perlbatross16 WebApp͸LambdaͰಈ࡞ Perl / Kossy /

    AWS::Lambda::PSGI / Aurora PostgreSQL ίϯςφΠϝʔδͰLambdaʹσϓϩΠ 16 https://perlbatross.kayac.com/