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
Ridge GAE/Go みたいなの on AWS
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
FUJIWARA Shunichiro
January 26, 2017
Technology
2.8k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Ridge GAE/Go みたいなの on AWS
FUJIWARA Shunichiro
January 26, 2017
More Decks by FUJIWARA Shunichiro
See All by FUJIWARA Shunichiro
作るべきものと向き合う - ecspresso 8年間の開発史から学ぶ技術選定 / 技術選定con findy 2026
fujiwara3
9
4.8k
さくらのクラウドでのシークレット管理を考える/tamachi.sre#2
fujiwara3
2
340
Amazon ECS デプロイツール ecspresso の開発を支える「正しい抽象化」の探求 / YAPC::Fukuoka 2025
fujiwara3
13
12k
パフォーマンスチューニングのために普段からできること/Performance Tuning: Daily Practices
fujiwara3
9
6.7k
alecthomas/kong はいいぞ
fujiwara3
7
2.5k
ecspressoの設計思想に至る道 / sekkeinight2025
fujiwara3
12
3.7k
さくらのIaaS基盤のモニタリングとOpenTelemetry/OSC Hokkaido 2025
fujiwara3
3
4.4k
監視のこれまでとこれから/sakura monitoring seminar 2025
fujiwara3
12
5.9k
k6による負荷試験 入門から日常的な実践まで/Re:TechTalk #01
fujiwara3
2
610
Other Decks in Technology
See All in Technology
現場のトークンマネジメント
dak2
1
150
Oracle AI Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
4
3k
“詰む”前に仕組みを作れ 〜技術の波に溺れないためのキャッチアップ術〜
takasyou
6
2.8k
スタートアップにAmazon EKSは早すぎる? マルチプロダクト戦略を加速する Platform Engineeringの実践 / Is Amazon EKS Too Soon for Startups? Practical Platform Engineering to Accelerate a Multi-Product Strategy
elmodev09
1
1.2k
SONiCで構築・運用する生成AI向けパブリッククラウドネットワーク ~実装編~
sonic
0
320
FPGAの開発コンペでZephyrを使ってみた
iotengineer22
0
170
Comment regagner la souveraineté de vos données tout en étant payé grâce à Nostr !
rlifchitz
0
120
AI-DLCを “そのまま導入しなかった”話 ~組織に合わせてアジャストした 私たちの実践共有~
hiroramos4
PRO
1
350
Chainlitで作るお手軽チャットUI
ynt0485
0
290
Kiro Ambassador を目指す話
k_adachi_01
0
110
AIのReact習熟度を測る
uhyo
2
660
AWS Security Hub CSPMの成功・失敗体験
cmusudakeisuke
0
430
Featured
See All Featured
Thoughts on Productivity
jonyablonski
76
5.2k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
New Earth Scene 8
popppiees
3
2.3k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
240
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
240
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.7k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.1k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
210
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
620
Transcript
Ridge GAE/Go Έ͍ͨͳͷ on AWS 2017.01.26 @fujiwara https://www.flickr.com/photos/jimgrant/2339167908
౻ݪ ढ़Ұ @fujiwara github.com/fujiwara sfujiwara.hatenablog.com ٕज़෦
Ridge is ͳʹ github.com/fujiwara/ridge API Gateway ɹ Lambda ɹ Go
Λͬͯ GAE/Go Έ͍ͨͳͷΛ࡞ΔϥΠϒϥϦ
API Gateway Proxy Integration & Lambda ?
API Gateway Proxy Integration & Lambda
API Gateway Proxy Integration ͱ Lambda Λઃఆ͢Δͱ GET /api/hello?name=Bob HTTP/1.1
User-Agent: curl/7.43.0 ! { "path": "/api/hello", "httpMethod": "GET", "headers": { "User-Agent": "curl/7.43.0", ... }, "queryStringParameters": { "name": "Bob" }, "body": null } API Gateway͕͏͚ͨҙͷHTTPϦΫΤετ͕ ^ͷΑ͏ͳObjectʹͳͬͯLambdaʹ
Lambda͕ฦͨ͠Object͕ API Gateway ʹΑͬͯ HTTPϨεϙϯεʹ { "statusCode": 200, "headers": {
"Content-Type": "text/plain" }, "body": "Hello Bob." } ! HTTP/1.1 200 OK Content-Type: text/plain Hello Bob.
ͭ·ΓLambdaͰҙͷWebΞϓϦ͕࡞ΕΔ ͚Ͳ • ಠࣗObjectΛಡΜͰಠࣗObjectΛฦ͢ • routing… ! • ςετͲ͏ͬͯ… !
͋ͱ Ͱॻ͖͍ͨ
Lambda Ͱ Go Λಈ͔͢
http://apex.run
ApexΛ༻͢ΔͱɺAWS LambdaؔΛ؆୯ʹߏஙɺల։ɺ ཧ͢Δ͜ͱ͕Ͱ͖·͢ɻ ApexΛ༻͢ΔͱɺGolangͳͲɺ AWS Lambda͕ωΠςΟϒʹαϙʔτ͍ͯ͠ͳ͍ݴޠΛɺϏϧ υʹೖ͞ΕͨNode.jsγϜΛ༻ͯ͠༻Ͱ͖·͢ɻ ػೳͷς ετɺσϓϩΠͷϩʔϧόοΫɺϝτϦοΫͷදࣔɺϩάͷς ʔϦϯάɺϏϧυγεςϜͷϑοΫͳͲɺ͞·͟·ͳϫʔΫ
ϑϩʔʹؔ࿈͢Δπʔϧ͕ఏڙ͞Ε͍ͯ·͢ɻ (by Google༁)
Apex Ͱ Go ͕ಈ͘Έ GoͷόΠφϦΛಉࠝɺࢠϓϩηεͱͯ͠ىಈ STDIN / STDOUTͰϓϩηεؒ௨৴(JSON)
Example package main type input struct { Name string `json:"name"`
} type output struct { Message string `json:"message"` } func main() { apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) { var in input if err := json.Unmarshal(event, &in); err != nil { return nil, err } out := output{Message: "Hello " + in.Name} return out, nil }) }
؆୯ʹBuild, DeployͰ͖Δ $ apex deploy Goͷbuild zip ࡞ͯ͠ Lambda ʹ
deploy ͜Ε͚ͩ
! API Gateway ͷ Object ͱ Go ͷ net/http Λ૬ޓม͢Ε͍͍ͷͰ
ͦΕ͕ Ridge github.com/fujiwara/ridge
RidgeͰॻ͔ΕͨΞϓϦͷྫ import ( "net/http" "github.com/fujiwara/ridge" ) func main() { var
mux = http.NewServeMux() mux.HandleFunc("/hello", handleHello) ridge.Run(":8080", "/api", mux) } func handleHello(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "Hello %s\n", r.FormValue("name")) } ridge.Run() Ҏ֎ී௨ͷ net/http ΞϓϦέʔγϣϯ
ridge.Run() ͕Δ͜ͱ API Gateway Proxy Integration ͱ net/http ͷ૬ޓม apex.HandleFunc(func(event
json.RawMessage, ctx *apex.Context) (interface{}, error) { r, _ := NewRequest(event) // API GW ͷ Object Λ *http.Request ʹ͢Δ w := NewResponseWriter() // RidgeͷResponseWriter mux.ServeHTTP(w, r) // ී௨ʹHTTP Handlerʹͯ͠ॲཧ return w.Response(), nil // API GW͕ཁٻ͢ΔObjectʹมͯ͠ฦ͢ })
ridge.Run() ͕Δ͜ͱ Apex(Lambda)Ͱಈ͔͞ͳ͍߹ී௨ʹhttp.Serverىಈ if os.Getenv("APEX_FUNCTION_NAME") != "" { apex.HandleFunc(...) }
else { // ApexͰͳ͍߹ m := http.NewServeMux() m.Handle(prefix+"/", http.StripPrefix(prefix, mux)) log.Println("starting up with local httpd", address) log.Fatal(http.ListenAndServe(address, m)) }
ී௨ͷ net/http ΞϓϦέʔγϣϯ͕ API Gateway + Lambda Ͱ net/http.Server Ͱಈ͘
Ridge ͷ͍͍ͱ͜Ζ
Ridge ͷ͍͍ͱ͜Ζ ͘͝ී௨ͷ Go ͷ net/http ΞϓϦέʔγϣϯͰ͋Δ • ςετී௨ʹ httptest
Ͱ • ϩʔΧϧͰಈ͔ͤ curl / ϒϥβͰಈ࡞֬ೝ • API GatewayͰͷੑೳʹ͕͋ͬͨ߹(ޙड़) ී௨ʹEC2Ͱಈ͔ͤΔ
Ridge ͷ͍͍ͱ͜Ζ API Gateway + Lambda Ͱಈ͘ͷͰ • ϦΫΤετʹԠͯࣗ͡ಈͰεέʔϧ •
ϦΫΤετ͕ͳ͚Ε ! ͳ͠ • EC2ͷཧҰͳ͠ • σϓϩΠ apex deploy Ұൃ
ͭ·Γ͜Ε GAE/Go Έ͍ͨͳͷʂ
Ridge ͰͰ͖ͳ͍͜ͱ
Ridge ͰͰ͖ͳ͍͜ͱ • ಉҰ໊ෳURLҾ (?foo=a&foo=b Έ͍ͨͳͷ) API Gateway͔ΒདྷΔ࣌Ͱ໊લΛkeyʹͨ͠objectͳͷͰ… • ಉҰ໊ෳ
HTTP ϔομ API Gatewayͷ࣌Ͱ(ུ) Proxy Integrationͷ༷ʹΑΔ
Ridge ͰͰ͖ͳ͍͜ͱ • όΠφϦΛฦ͢ (ը૾ͱ͔) API GatewayઌόΠφϦαϙʔτ͚ͨ͠Ͳ Proxy Integration͔Βฦͤͳ͍Α͏ͳ… ࠓޙʹظ
Ridge ͰͰ͖ͳ͍͜ͱ • ཪͰ Goroutine Λಈ͔͠ଓ͚Δ LambdaϦΫΤετॲཧΛऴ͑Δͱϓϩηεٳ • 1ϦΫΤετʹ10ඵҎ্ֻ͔Δॲཧ API
GatewayͷλΠϜΞτ͕ݻఆ Long poll / SSE తͳ͜ͱؚΉ
RidgeͷੑೳධՁ
RidgeͷੑೳධՁ RedisʹೖΕͨ༣ศ൪߸DB1 ΛҾ͍ͯJSONΛฦ͢API ڞ௨: ElastiCacheRedis (t2.micro) 1. ALB(https) + EC2(t2.micro)
2. API Gateway(https) + Lambda (128MB) $ curl -s "https://***/api/postal_code?code=1000001" {"code":"1000001","addresses":[{"address":"౦ژઍా۠ઍా","yomi":"τΩϣτνϤμΫνϤμ"}]} 1 KEN_ALL.csv
1. ALB + EC2 (t2.micro) Running 10s test @ https://***/api/postal_code?code=1000001
4 threads and 30 connections Thread Stats Avg Stdev Max +/- Stdev Latency 10.55ms 4.22ms 222.76ms 96.48% Req/Sec 662.03 68.84 780.00 76.00% Latency Distribution 50% 9.89ms 75% 10.82ms 90% 12.28ms 99% 19.18ms 26402 requests in 10.02s, 7.68MB read Requests/sec: 2634.14 Transfer/sec: 784.46KB
2. API Gateway + Lambda (128MB) Running 10s test @
https://***/api/postal_code?code=1000001 4 threads and 30 connections Thread Stats Avg Stdev Max +/- Stdev Latency 33.83ms 14.64ms 355.60ms 86.32% Req/Sec 190.01 27.50 260.00 70.50% Latency Distribution 50% 31.43ms 75% 37.48ms 90% 46.82ms 99% 81.43ms 7603 requests in 10.05s, 4.30MB read Requests/sec: 756.37 Transfer/sec: 438.01KB
ൺֱͷͨΊͲͪΒ30ฒྻ ݶքੑೳΛܭଌ͍ͯ͠ͳ͍͜ͱʹҙ • EC2, LambdaͱΞϓϦࣗମͷॲཧฏۉ 5msఔ • API Gateway, Apex,
Ridge ͰͷϨΠςϯγ͕߹ܭ20msఔ (େ෦͕API Gateway) ฒྻ্͕͕Ε req/sec ্͕Δ API Gateway1000req/sec2, Lambda 100ฒྻͷ੍ݶ͋Γ (্ݶ؇ਃՄೳ) 2 ͳͷͰϕϯνͷฒྻΛ্͛Ε͍ͯͳ͍
Ridgeʹ͍͍ͯͳ͍͜ͱ ϨΠςϯγ͕ཁٻ͞ΕΔΞϓϦέʔγϣϯ ͨͱ͑෦͚ microservice ͦͦ API Gateway ͕ VPC Ͱಈ͔ͳ͍
Ridge͕(ಛʹ)͍͍ͯΔ͜ͱ සൟʹΞΫηε͕ͳ͍ / ϨΠςϯγཁٻ͕γϏΞͰͳ͍ • webhookΛड͚Δ Slack bot • S3ͷrepo
viewer github.com/fujiwara/ridge-s3viewer • αʔϏε͕ऴྃͨ͠ήʔϜͷࠂAPI POSTΛड͚ͯJSONΛฦ͢ͷΛEC2ͳ͠Ͱ ΧϠοΫͰຊ൪APIͱͯ͠ೖ࣮͋Γ
Ridge(ͱ͍͏͔Lambda)ͷҙࣄ߲ • (VPC Lambda ͷ߹) ॳճىಈ࣌ʹENIΛׂΓͯΔͷʹ 10ඵఔඞཁ • ίϯςφ͕શʹࢭ·ͬͯ͠·͏ͱىಈ͕͍ ఆظత(1ʙ5ִؒ)ʹ֎ܗࢹͳͲͰୟ͚OK
• ϝϞϦׂྔͱCPUੑೳ͕ൺྫ͢Δ ࣮ࡍʹϝϞϦΛΘͳͯ͘CPU͕ඞཁͳΒେ͖͘ (! ൺྫ͠·͢)
ϩάͷऔΓѻ͍
ϩάͷऔΓѻ͍ go-apexͰΈ্ STDOUT ʹԿग़ྗͰ͖ͳ͍ STDERR ʹग़ྗͨ͠ͷ CloudWatch Logs ʹه͞ΕΔ apex
logs -f ͰӾཡ(tail)Մೳ
ϩάͷऔΓѻ͍ CloudWatch Logs ͍͍͓ஈ + औΓѻ͍͕ͭΒ͍ → Lambda ʹྲྀ͢͜ͱ͕Ͱ͖Δ {
"awslogs": { "data": "H4sIAKmNfFgAA5VQTWvbQBS891cI0aNV7dtv+aYQNRRiWiy1l9iYlfVkBPpwp XXTNOS/98lOwRBy6B7eYWb2zcx7DjucJnfA4umI4TK8TYt0t8ryPL3LwkU4PPY4EpxcPYL b4XA3DqcjMbF7nOLWdWXl4rGpDhh5nPyuc01/EeZ+RNeRkjMwMYMYdPzw8T4tsrzYVhxLU Vd1KS1Ih3W5R+2U2guuoUTNaMV0Kqf92Bx9M/Sfm9bjOIXLh/D+bHlZvrsyJsdwezbOfmH vZ+1z2FTkLwQwrY3QVjHNjUgSKbVRUlhrGZdglALOleCCYCsSQzgwAZTBN3Ql7zoqDNJKp aRKwDJY/Lserc+LdF0Ea/x5IumXahmANgythKgq9zICQB1ZmySRFMrUNdRaKQx+UB0qtgx eL7Lpw5fF28DAjJBAP5nhijHgWnFpaaqEGaNnQicJIzer9fuBxXXgdfbt6/8n3vjb0+j8O TN84izopo2/adoWq+CKYTMRbPwKu2F8CvLmDxLKbbC6IdD9Dl6J7xPOxhd8Lr99+fAXpgd o/ZQCAAA=" } } ͳʹ͜ͷσʔλ !
CloudWatch Logs → Lambda JSONจࣈྻΛgzipͯ͠base64ͨ͠ͷ͕ྲྀΕͯ͘Δ ! $ jq -r .awslogs.data
| base64 --decode | gzip -dc | jq . { "messageType": "DATA_MESSAGE", "owner": "999999999999", "logGroup": "/aws/lambda/ridge-test_main", "logStream": "2017/01/16/[$LATEST]d2eb3fdfb4814aefbce6a55c3261be60", "subscriptionFilters": [ "LambdaStream_ridge-test_log" ], "logEvents": [ { "id": "33106673685062739944675438880241755122532346783978881031", "timestamp": 1484554591801, "message": "START RequestId: 1670e841-dbc4-11e6-8899-4357ff1f655e Version: $LATEST\n" }, { "id": "33106673685107341435072500126524826559077643506990841866", "timestamp": 1484554591803, "message": "REPORT RequestId: 1670e841-dbc4-11e6-8899-4357ff1f655e\t Duration: 1.20 ms\tBilled Duration: 100 ms \tMemory Size: 128 MB\tMax Memory Used: 18 MB\t\n" } ] }
ridge.DecodeLogStream() Ͱόϥͤ·͢ apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) { logStream,
_ := ridge.DecodeLogStream(event) for _, e := range logStream.LogEvents { /* e => { ID: "33106673685062739944675438880241755122532346783978881031", Timestamp: 1484554591801, Message: "START RequestId: 1670e841-dbc4-11e6-8899-4357ff1f655e Version: $LATEST\n" } */ } }) ల։ͨ͠ͷΛ Kinesis Streams, Firehose ͳͲʹ͛Δͷ͕Α͍ͷͰ
·ͱΊ API Gateway + Lambda Ͱ GAE/Go Έ͍ͨͳ3 ͜ͱ͕Ͱ͖Δ Ridge
(github.com/fujiwara/ridge) Λ࡞Γ·ͨ͠ ༻్ʹΑͬͯطʹ 3 ಉ͡ͱ͍͑·ͤΜ