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でRouter自作実装寄りな話
Search
bmf_san
June 23, 2021
Programming
260
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GoでRouter自作実装寄りな話
bmf_san
June 23, 2021
More Decks by bmf_san
See All by bmf_san
桃太郎で始めるRego入門‐今日から使えるRegoの基本編
bmf_san
0
77
完璧を求めない意思決定-アクセス制御基盤における制約との向き合い方
bmf_san
5
20k
AAPについて調べてみた
bmf_san
0
140
レーダーをつくる
bmf_san
0
85
契約テストとPactについて
bmf_san
0
130
5分でわかるSLO
bmf_san
2
180
権限について考える
bmf_san
2
170
自作HTTPルーターから新しいServeMuxへ
bmf_san
3
1.9k
古くなってしまったPHPフレームワークとPHPのバージョンアップ戦略
bmf_san
1
520
Other Decks in Programming
See All in Programming
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
240
ALB ログから Trace を気合で繋げる技術
fohte
5
490
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
260
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
260
バグを直したら useEffect が消えた
colorful12
3
700
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
7.8k
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
550
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
160
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
240
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
3
1.9k
typoなんかねぇよ
raspython3
0
540
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
1
2k
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
390
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
420
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
900
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
My Coaching Mixtape
mlcsv
0
280
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
470
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
360
Into the Great Unknown - MozCon
thekraken
41
2.7k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
220
Transcript
GoでRouter⾃作 実装寄りな話 @bmf_san 2021.06.23 社内LT
なんの話 • net/httpを拡張したrouterのライブラリ • net/httpの”⾜りないところ”を補う • /user/:idのような動的なルーティングができな い
ϒϩάͱ͔-5ͱ͔Ͱ͍·Θͨ͠ωλ
Github https://github.com/bmf-san/goblin
Goblin仕様 • net/http準拠 • 動的なルーティング • 名前付きのパラメータ(パスパラーメーター)をサポート/ users/:id • 正規表現も使える
/users/:id[^\d+$] • ミドルウェアをサポート • net/httpのhttp.Handlerインターフェースに従った関数をミドル ウェアとしてルーティングの処理に組み込める
Goblin例 IUUQTHJUIVCDPNCNGTBOHPCMJOCMPCNBTUFS@FYBNQMFTNBJOHPΛࢀর
有名どころ • ライブラリ • https://github.com/fasthttp/router • https://github.com/julienschmidt/httprouter • http://github.com/go-chi/chi •
FW • https://github.com/gin-gonic/gin • https://github.com/labstack/echo • https://github.com/gorilla/mux
Routerの役⽬ NJEEMFXBSFIBOEMFSͷखલͰॲཧ͞ΕΔΠϝʔδ
Routerの役⽬ • リクエストされたURLやHTTP Methodに応じて、 処理の実⾏を制御するアプリケーション • URLとアプリケーションの処理を結びつける
データ構造を考える ・Router≒⽂字列マッチング ・URLの階層構造と相性が良いデータ構造 →⽊構造
⽊構造
トライ⽊(プレフィックス⽊) ・⽂字列の集合を扱う⽊構造の⼀種 ・ざっくりいうと、⽂字列を探索しやすいように⽊に 格納したやつ ・ex. サジェスト、IPアドレス探索、形態素解析とか ⽂字列を扱う系のやつのベースだったりするぽい
もっと良い⽊ • 時間的計算量(処理時間)、空間的計算量(メモ リ)の効率を追求するなら他に選択肢がある • ex. Radix(Prefix) tree https://www.cs.usfca.edu/ ~galles/visualization/RadixTree.html
• 実装できなかった。ムズい。 • strings.Replacerは内部でRadix tree 実装してい る
トライ⽊を知る • https://www.cs.usfca.edu/~galles/visualization/ Trie.html • アルゴリズムのビジュアライズ • https://github.com/bmf-san/road-to-algorithm- master/tree/master/data_structures/tree/trie •
参照実装
オレオレトライ⽊
オレオレトライ⽊(旧) • 最初のリリースで実装していた⽊ • HTTPメソッドをノードに⼊れてしまうのはアンチパターンだった • ルーティングの処理にHTTPメソッドの⼀致を前提としてしまう • HandlerがHTTPメソッドに依存するような実装になってしまう •
middlewareの対応で不都合に • cf. https://bmf-tech.com/posts/⾃作ルーティングをアップデートした
主な構造体 NBQͱMJOLFEMJTUͷ߹ମͰΛදݱͨ͠Α͏ͳΠϝʔδʁ
Goでrouterを実装する上で知っておきたいこと • net/httpの概観 • どんな構造体があるか、どこを拡張したら良いか、どんなイン ターフェースに従うべきか • cf. https://golang.org/pkg/net/http/ •
HTTPサーバーの処理 • http.ListenAndServeから内部を⾒る • cf. https://bmf-tech.com/posts/GolangのHTTPサーバーのコード リーディング
HTTPサーバーのコードにdeep dive • 良く⾒るGoのHTTPサーバーのコード(⾊々省略さ れている)
HTTPサーバーのコードにdeep dive • 省略しないで書いたパターン
HTTPサーバーのコードにdeep dive • ServeHTTPは関数型のaliasであるHandlerFuncに置き換えることができる • cf. • func (f HandlerfFunc)
ServeHTTP(w ResponseWriter, r *Request) • https://golang.org/src/net/http/server.go?s=64180:64240#L2058
HTTPサーバーのコードにdeep dive • Mux(http.NewServeMux( ))は作らなくても良い。DefaultServeMuxを使うことができ る。 • DefaultServeMuxはServeMux型の構造体を持っており、HandlerFuncというmuxにルー ティングを登録する関数を実装している。 •
cf. • DefaultServeMux • https://golang.org/src/net/http/server.go?s=77627:77714#L2269 • func (mux *ServeMux) HandlerFunc(pattern string, handler func(ResponseWriter, *Request))
HTTPサーバーのコードにdeep dive • Server構造体(http.Server{})もわざわざ作らなくても良い。net/httpには ListenAndServe( )が⽤意されている。 • cf. • func
(*Server) ListenAndServe • https://golang.org/pkg/net/http/#ListenAndServe • func ListenAndServe(addr string, handler Handler) error
Routerを実装するには • →http.Handlerインターフェース を意識して、muxを作れば良い
ルーティングを登録する部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/router.go • メソッドチェーンでrouteを登録する処理 • ServeHTTPの実装(≒http.Handlerインターフェースの実装)した構造体を作る • ServeHTTP内では、ルーティング、ミドルウェア・ハンドラの実⾏を順番にやる
• 作った構造体はListenAndServeに渡される想定 • cf. https://github.com/bmf-san/goblin/blob/master/_examples/main.go
middleware対応のための実装 • cf. https://github.com/bmf-san/goblin/blob/master/ middleware.go • Sliceに保持したミドルウェアを順番に処理していく • 処理をラップしていくように実⾏する •
cf. https://github.com/bmf-san/goblin/blob/ master/_examples/main.go • いわゆるDecorator patternってやつだと思う
muxにあたる部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/trie.go • オレオレトライ⽊を頑張ってかく • 単純なトライ⽊を書いて、それを発展させていく • データ構造を考えきった時点で6~7割くらい完成ではある
• テストとデバッガを有効につかう • テストがないと前に進めないくらいテストを有⽤ • ⾊々なパターンのルート定義を考慮する必要があり、テストケースが結構悩ましい • デバッガは⽊の⽣成が上⼿くできているか確認したり、脳内デバッグで間に合わないときに有⽤ • 正規表現の利⽤ • 正規表現を使ったルーティングのケースに対応するためにregexpを使っている • strings.Replacerで代⽤できるならそっちが良い • Goでは正規表現はコストがかかる処理なのでキャッシュして再利⽤性を⾼めると良い • 後で対応しようと思っていたらPRもらえた • https://github.com/bmf-san/goblin/pull/17
ベンチマーク • ϕϯνϚʔΫςετ • cf. https://github.com/julienschmidt/go-http-routing-benchmark • go test -bench=“Goblin|Gin|GorillaMux|HttpRouter|Chi|Beego|Echo”
• ϕϯνϚʔΫ݁Ռ • cf. https://github.com/bmf-san/goblin/issues/ 34#issuecomment-864978325 • Routerબఆͷ؍ύϑΥʔϚϯε͚ͩͰͳ͘ɺػೳ໘net/ httpͷΠϯλʔϑΣʔεΛҙ͍ࣝͯ͠Δ͔Ͳ͏͔ͷόϥϯε͕େࣄ ͦ͏ • cf. https://github.com/julienschmidt/go-http-routing- benchmark#conclusions
ベンチマーク • cf. https://github.com/julienschmidt/go-http-routing- benchmark • GoblinՃ͠·ͨ͠ରઓΑΖ͓͘͠Ͷ͕͍͠·͢PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/97
• READMEߋ৽͍ͯ͠ͳ͍͔ΒϦετݟͨͧ͠PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/96