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
実践!Go/GAE+DDDでのクローラー構築
Search
Seiji Takahashi
March 25, 2017
Technology
32k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
実践!Go/GAE+DDDでのクローラー構築
Go Conference 2017 Springでの講演スライドです。
Seiji Takahashi
March 25, 2017
More Decks by Seiji Takahashi
See All by Seiji Takahashi
AIエージェントのデータガバナンスの最新事情。そしてプロダクトのAIファースト化
timakin
0
3.8k
営業、広報、開発。 多面的なAIネイティブ化のための 基盤について
timakin
0
250
権限と承認 〜ユーザー信頼性に繋がる管理画面の根幹について〜
timakin
0
1k
Go Backends for frontends with GraphQL and gRPC
timakin
6
4.3k
Design Pattern for Image and Text Composition in Go
timakin
5
6.9k
Golang API Testing the HARD way
timakin
13
7.3k
Head First Golang Image Package
timakin
2
10k
React Native Beyond Prototype
timakin
2
1.7k
Performance Optimization on Google AppEngine
timakin
5
6.7k
Other Decks in Technology
See All in Technology
Azure Cost Management の FOCUS コストデータを迷わず読むための“3つの軸”
tetsuyaooooo
0
140
動画配信アプリでの Engage SDK 導入 — TVer Android が Play ストアにコンテンツを届けるまで
techtver
PRO
0
110
GuardDuty 検知対応を DevOps Agent で効率化しようとしている話 / GuardDuty Investigations with DevOps Agent
masahirokawahara
1
300
Bet AI Day 2026丨バクラク Autopilot、業務システムの再設計
layerx
PRO
2
1.2k
深夜のクラウド懺悔室 1:29:300 or 1:0:0
kazzpapa3
0
170
Bet AI Day 2026丨AIを「使う」から、AIが「働く」へ ― LayerXが進める「組織AI」の社会実装
layerx
PRO
3
2.2k
AIで仕事のやり方を変える
matsu7874
1
530
【Oracle AI Spotlight ウェビナー】AWSか、Azureか、Google Cloudか。その議論にオラクルを含める意義。
oracle4engineer
PRO
2
230
IoTハンズオンの舞台裏
shirouz
2
130
#jawssonic2026 あの時代が悪かった ~動かなかったSageMakerと共に迎えたイベント当日~
ktkn1129
0
130
コスト最適化の「めんどくさい」を AWS FinOps Agent でチョット楽にする
classmethod_kaz
0
180
Beyond the Hype: Practical AI for Your Oracle Database with MCP
thatjeffsmith
1
260
Featured
See All Featured
How STYLIGHT went responsive
nonsquared
100
6.3k
For a Future-Friendly Web
brad_frost
183
10k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
840
Evolving SEO for Evolving Search Engines
ryanjones
0
280
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Building an army of robots
kneath
306
46k
The Limits of Empathy - UXLibs8
cassininazir
1
640
Facilitating Awesome Meetings
lara
57
7.1k
KATA
mclloyd
PRO
35
15k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
810
Rails Girls Zürich Keynote
gr2m
96
14k
Transcript
࣮ફ!Go/GAE+DDD ͰͷΫϩʔϥʔߏங @__timakin__ GoConference 2017 Spring
ࣗݾհ
ࣗݾհ • twitter: @__timakin__ • github: timakin • גࣜձࣾGunosy ৽نࣄۀ։ൃࣨ
← New! • ओͳGoϥΠϒϥϦ։ൃ • gopli (DBϨϓϦέʔγϣϯπʔϧ) • gonvert (จࣈίʔυมϥΠϒϥϦ) • octop (githubͷissue, PRϏϡʔ༻CLIπʔϧ) • ts (ٕज़ɾϏδωεܥχϡʔε८ճCLIπʔϧ)
Copyright© Gunosy Inc. All Rights Reserved 4 Go / Python
ΤϯδχΞืूத ▶https://gunosy.co.jp/recruit/ Gunosyɺ౦ژେֶʹ௨͏3ਓͷֶੜͷ ʮใΛੈքதͷਓʹ࠷దʹಧ͚͍ͨʯͱ͍͏͍͔Β࢝·Γ·ͨ͠ɻ ౦ূϚβʔζ্ɺຊώϧζͷΦϑΟεҠసΛܦͯɺ େ͖͍ͯ͘͠ΔձࣾͰ׆༂͍ͨ͠ϝϯόʔΛืू͍ͯ͠·͢ɻ
ΞδΣϯμ
ΞδΣϯμ • Go/GAE + DDDͰ࡞ΔΫϩʔϥʔ • APIͷ֓ཁ • σΟϨΫτϦߏ •
ڞ௨ॲཧɺݸผͷυϝΠϯͷৄࡉ • Go/GAEͰ٧·ͬͨϙΠϯτ • ·ͱΊ
ࠓճͷ։ൃϓϩηε
APIͷ֓ཁ
APIͷ֓ཁ • ओͳ༻ٕज़ • GAE SDK: go version go1.6.3 (appengine-1.9.48)
darwin/amd64 • Web Framework: echo v3.0.3 • Vendoring: dep • ػೳཁ݅ • Facebook, TwitterͷAPI & Σϒϖʔδ͔ΒίϯςϯπΛऔಘ • ͋Β͔͡ΊऔಘઌͷީิΛDBʹొ͓͖ͯ͠ɺcronδϣϒͰదٓΫϩʔϧ • λΠτϧɺbodyɺαϜωΠϧͷڞ௨ϓϩύςΟʹ֨ೲ • ҎલΫϩʔϧͨ͠λΠϛϯά͔Βߋ৽͕ͳ͔ͬͨΒಡΈࠐ·ͳ͍ • Ϋϩʔϧ݁ՌJSONΦϒδΣΫτʹ·ͱΊͯ࠷ޙʹS3ʹΞοϓϩʔυ͢Δ • ը૾ͷՃͱ͔ͳ͠ɻ͍͔ͭإೝࣝͱ͔γϡοͱΓ͍ͨɻ
ίϯςΩετϚοϓ(DDD) ఆظऩू Ϋϩʔϧδϣϒͷ ൃՐ ίϯςϯπऔಘ औಘઌͷཧ ίϯςϯπऔಘ ʢੜͷϨεϙϯεʣ ༰ͷՃ औಘͨ͠ใΛՃͯ͠+40/༻ͷ
ύϥϝʔλʔʹม͢Δ อଘ ετϨʔδ 4 ʹΞοϓϩʔυ A B calls Worker Fetcher Parser Uploader
σΟϨΫτϦߏ
σΟϨΫτϦߏ GAEͷίϯςΩετੜ ϧʔςΟϯά GAEͷδϣϒఆٛ ίΞػೳͷ࣮෦ ґଘύοέʔδ GAEϏϧυͷ߹্ىಈεΫϦϓτͱ࣮ɺvendorσΟϨΫτϦผʹ͚Δ (package໊ͷিಥɺunsafeͷඇਪػೳͱ͔ͰΞϥʔτ͕ग़Δ)
σΟϨΫτϦߏ ΞϓϦͷڞ௨ઃఆ Λѻ͏Օॴʢޙड़ʣ ֤υϝΠϯͷ࣮ DBΞΫηεΛ୲͏ ϦϙδτϦ܈ Contextઃఆ
DDDߏʹͯ͠Α͔ͬͨͱ͜Ζ • ࣮ݱ͍ͨ͠ϏδωεϩδοΫ୯ҐͰ package໊͕౷Ұ͞ΕΔͷͰɺ package໊ͷিಥ͕ى͜Γʹ͘͘ͳͬͨɻ • Ϧιʔεͱ͍͏ʮϞϊʯͰͳ͘ɺ υϝΠϯͱ͍͏ʮߦҝʯʹͯ͠ ίʔυΛॻ͘͜ͱͰɺʮ͍ͭ͜ԿΛͯ͘͠ΕΔͭͳͷʁʯ ͱ͍͏ٙͷղ͕͙͢ʹಘΒΕͯɺ୯७ʹಡΈਐΊ͘͢ͳͬͨɻ
• repositoryΛΓ͢ͱɺ࣮ͱσʔλΞΫηεͷ͕ؔ ૄʹͳΓɺϝϯςφϯε͔ͬͨ͢͠ɻ (CloudSQL͔ΒDataStoreͷҠߦͱ͔͔ͬͨ͢͠)
ڞ௨ॲཧ ݸผͷυϝΠϯͷৄࡉ
࣮ɿڞ௨ॲཧ GAEϏϧυʹඞཁͳechoͷίʔυҎԼΛࢀߟʹ͍ͯͩ͘͠͞ɻ https://echo.labstack.com/cookbook/google-app-engine
࣮ɿڞ௨ॲཧ GAEϏϧυʹඞཁͳechoͷίʔυҎԼΛࢀߟʹ͍ͯͩ͘͠͞ɻ https://echo.labstack.com/cookbook/google-app-engine ʁ
࣮ɿڞ௨ॲཧ GAEͷίϯςΩετΛɺ ɾtimeout limitΛઃఆ ɾίϯςΩετʹrepositoryͷΠϯελϯεΛ࣋ͨͤΔ ͱ͍͏͜ͱΛ্ͨ͠ͰɺechoͷΧελϜίϯςΩετͱͯ͠ઃఆ͢Δ
࣮ɿڞ௨ॲཧ echo.Contextɺඪ४ύοέʔδͷcontext.Context͡Όͳ͍… echo.ContextΛར༻ͨ͠GrawlerCtxͱ͍͏ΧελϜίϯςΩετΛ࡞ͯ͠ɺ Contextͷ1มͱͯ͠AppEngineCtxΛ࣋ͭɻ
Fetcherɿίϯςϯπऔಘઌొ ϦΫΤετύϥϝʔλʔΛͱʹɺ”Entity”Λ࡞ͬͯɺ ίϯςΩετ෦ͷrepository͔ΒɺίϯςϯπऔಘઌΛొ͢Δ
ิɿrepositoryͷར༻ํ๏ ΧελϜίϯςΫετͷத͔ΒAppEngineͷContextΛऔಘ͠ɺ ͦͷContext͕࣋ͭFetcher(·ͨଞͷυϝΠϯͷ) DBͷΞΫηαϝιουΛݺͼग़͢
ิɿrepositoryͷ෦ Entity(ࣝผࢠΛ࣋ͬͨσʔλߏ)Λࡐྉʹͯ͠σʔλΞΫηε͢Δɻ ݸผͷϦϙδτϦΛ ೖΕࢠͰࢀরͯ͠ɺ ୯ҰίϯςΩετ ͔ΒશϦϙδτϦʹ ΞΫηεͰ͖Δ Α͏ʹ͢Δɻ
ิɿrepositoryͷ෦ Entity(ࣝผࢠΛ࣋ͬͨσʔλߏ)Λࡐྉʹͯ͠σʔλΞΫηε͢Δɻ
FetcherɿΠϯλʔϑΣʔε
FetcherɿΠϯλʔϑΣʔε
FetcherɿΠϯλʔϑΣʔε ϨεϙϯεΛ ͦͷ··interface{} ͱͯ͠ฦ͢ ֎෦ͷϦΫΤετ appengine/urlfetchΛ ͏
ParserɿΠϯλʔϑΣʔε HTMLύʔαʔͱ͔ɺαΠτʹΑͬͯେ෯ʹparseͷํ͕ࣜҟͳΔɻ ͦͷͨΊɺParserFactory.CreateΛܦ༝ͯ͠ɺParseServiceΛ࡞͢Δ fetcherInstanceϖʔδϯά࣌ͷϦΫΤετ༻
ParserɿHTMLύʔαͷఆٛ FactoryͰͲͷ ύʔαʔΛ࡞͢Δ͔ ಛఆ͢Δͱ͖ʹ͏ ʢεϥΠυͰ ߹্໊લΛมߋͯ͠·͢ʣ appengineͷόʔδϣϯ ͷ߹্ɺcontext.Context x/netͷͷΛ͏ɻ
ParserɿParserFactory ࢦఆ͞ΕͨparserKeyʹԠͯ͡ParseServiceΛ࡞ɻ FactoryTypeߏମΛ࡞Δ্Ͱக͠ํͳ͘༻ҙ͍ͯͯ͠ɺ ”html”ͱ͍͏จࣈྻΛೖΕͯΔ͚ͩɻ
ParserɿParse࣮Օॴ ίϯςΫετΛड͚औͬͯFetch͠ɺͦͷ݁ՌΛparse͢Δɻ ) ຊParserʹFetcherΛ͢ͷݏͩͬͨͷͰ͕͢ɺ ɹ ϖʔδϯάͰͲ͏ͯ͠ඞཁͩͬͨͷͰɺFetcherΛ ɹ ࣋ͨͤΔ͜ͱʹ͠·ͨ͠ɻͭΒ͍ʂ FacebookParserͱ͔ϖʔδϯά͍Βͳ͍ͷͰɺ શʹFetcherͱParser͕͍ͯ͠·͢ɻ
ParserɿParse࣮Օॴ yhat/scrapeΛͬͯ ཁૉΛऔΓग़͢ɻ goqueryΈ͍ͨʹ ίʔϧόοΫͷॻ͖ํ ͠ͳ͍͠γϯϓϧͰ͢ɻ ྫ) aλά͕ΘΕͯͯɺ ͕h1λάɺͦͯ͠ ֘NodeͷΫϥε͕
“skin-entryTitle”Ͱ͋Δ ͷɺ”title”ͱͯ͠ ύʔε͢Δ
ParserɿParse࣮Օॴ ϒϩάهࣄҰཡ͔Βɺ هࣄৄࡉϖʔδͷ༰Λ ࠶Fetch ͦͷதͷTitleཁૉͱ͔Λ औಘ͢Δॲཧ
UploaderɿΠϯλʔϑΣʔε JSONΞοϓϩʔυ༻ͷڞ௨σʔλߏʹ parse݁ՌΛ٧Ίͨͷʢ[]feeditem.FeedItemʣΛͯ͠ɺ ಛఆετϨʔδʹΞοϓϩʔυ͢Δ
UploaderɿॳظԽॲཧ(ྫ: S3) S3ΞοϓϩʔμͷॳظԽॲཧɻ γʔΫϨοτͳใΛͯ͠ɺS3ΞΫηε༻ͷΦϒδΣΫτΛ࡞
Uploaderɿ࣮Օॴ ͜͜Ͱappengine/urlfetch Ͱੜͨ͠HTTPClientΛ ઃఆ͠ͳ͍ͱɺϦΫΤετ͕௨Βͳ͍ ॗʑͱbodyΒ credentialsΛઃఆͯ͠ɺ S3ClientΛ࡞ ͜ΕҎ߱requestΛ send()͢Δ͚ͩͳͷͰ লུ
Workerɿϋϯυϥ GAEͷcronͰୟ͘ΤϯυϙΠϯτͷϋϯυϥΛ༻ҙ͢Δ workerΛ࡞ͬͯɺCrawlϝιουΛݺͿ͚ͩɻ
Workerɿϋϯυϥ GAEͷcronͰୟ͘ΤϯυϙΠϯτͷϋϯυϥΛ༻ҙ͢Δ workerΛ࡞ͬͯɺCrawlϝιουΛݺͿ͚ͩɻ
Workerɿ࣮Օॴ fetch -> parse·Ͱɻ ΈΜͳେ͖goroutineɻ sync/errgroupΛ͑ɺ ΤϥʔϋϯυϦϯάͯ͘͢͠ ͓͢͢ΊͰ͢ɻ
Workerɿ࣮Օॴ context.ContextΛड͚औͬͯΔͷͰɺ δϣϒ࣮ߦதʹλΠϜΞτͨ͠Β ΤϥʔΛฦ͢ɻ Ξοϓϩʔυॲཧ Ξοϓϩʔυ͕ ྃͨ͠Βɺ ࠷ऴऩू࣌ࠁΛߋ৽
cron cron.yamlͱ͍͏ͷΛ༻ҙ͢Δͱɺ ಛఆͷΤϯυϙΠϯτʹܾ·ͬͨසͰGETϦΫΤετΛૹͬͯ͘ΕΔͷͰɺ ͜ΕΛͬͯworkerͷΤϯυϙΠϯτΛୟ͘
Go/GAEͰ٧·ͬͨϙΠϯτ
σΟϨΫτϦߏͷݟ͠ • ͍ܰؾ࣋ͪͰGAEࢼͯ͠ΈΑ͏ͱɺ ॳظσϓϩΠΛ͠ͳ͍··ਐΊͯͨΒɺ ͋ͱ͋ͱมߋ͕͍ͬͺ͍ೖΔɻ • ಛʹvendoringπʔϧΛ͏ͱɺ package໊িಥͱ͍͏ΫϦςΟΧϧͳॴͰ Ϗϧυ͕௨Βͳ͍ͷͰɺGAE্ʹσϓϩΠ͢ΔͳΒ ࠷ॳ͔Β༷ࣜʹ߹ΘͤΔɻ
None
ൿີใͷཧ • access tokenͱ͔ΛͲ͜ʹஔ͔͘ɻ • ࠷ॳtomlͰཧͯͨ͠Μ͚ͩͲɺgoapp deployͨ͠Β srcҎԼͷtoml͕ফ໓͢ΔɻࠔΔɻ • app.yamlͷenvʹઃఆ͢Δͱ͍͏ํ๏͋Δ͕ɺ
gitignoreͰ͖ͳ͍ͷͰौ͍ɻ • ConfigurationRepositoryΛ࡞ͬͯɺDataStore্ʹ อଘ͢Δͱ͍͏ํΛͱͬͨɻɹ
ൿີใͷཧ
CloudSQL or DataStore • ࠷ॳCloudSQL(gormܦ༝)Λར༻͍͕ͯͨ͠ɺ ͳʹΒ ͕͔͔͍ͬͯΔɻ ͜ͷAPIࣗମͷϦΫΤετଟ͘ͳ͍ͣͳͷͰɺ খنͰ͔͔ۚΔͷौ͍ɻ •
ConfigurationRepositoryΛ࡞ΔλΠϛϯάͰɺ શ෦ετϨʔδΛDataStoreҠߦͨ͠ɻ • RepositoryΛ͍ͯ͠ΕҠߦָͩ͠ɺ ίϯιʔϧ͔ΒΤϯςΟςΟใݟΕΔͷͰ DataStoreͷํ͕Αͦ͞͏ɻ
before after
·ͱΊ • ΫϩʔϥʔΛ࡞Γ·ͨ͠ɻ • DDDݟ௨͕͠Α͘ɺpackage໊ͷিಥආ͚ΒΕͯΑ͍ɻ • ಛʹɺͪΌΜͱinterfaceΛఆٛ͢Εɺ υϝΠϯ͝ͱͷίʔυͷՄಡੑ͕ඈ༂తʹ্͕ΔͷͰɺ Goͱ૬ੑ͕͍͍ͱࢥ͏ɻ •
GAEσΟϨΫτϦߏͷ໘ͰΫη͋Γ·͕͢ɺ cronΒDataStoreΒͰԸܙ͕͋ΔͷͰɺҰ୴ڥΛ ߏங͢Δͱେมศརɻඪ४ύοέʔδͷcontext͕ ར༻Ͱ͖ΔΑ͏ʹͳΔͱ͍͍ͳɻ
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ twitter: @__timakin__ github: timakin