Slide 1

Slide 1 text

Ruian Huang @Golang Taipei 2020/06/23 Golang 的熱⾨ 
 PostgreSQL Library 比較 透過觀察封包比較實作上的差異

Slide 2

Slide 2 text

Dcard ⼯程師 • 交⼤資⼯畢業 • 偶爾寫點⽂章
 https://medium.com/@ruian
 
 包含 PG Wire Protocol 與 Query Optimizer 相關⽂章 Ruian Huang

Slide 3

Slide 3 text

回顧去年同樣於 Golang Taipei 分享的主題

Slide 4

Slide 4 text

回顧去年同樣於 Golang Taipei 分享的主題

Slide 5

Slide 5 text

這次分享的內容主要來⾃ Medium 上的⽂章,
 改⽤ Wireshark 展⽰,並補充 Connection Pool 細節

Slide 6

Slide 6 text

這次比較的 lib • lib/pq v1.7.0 • Gorm (同 lib/pq) • go-pg/v10 • pgx/v4

Slide 7

Slide 7 text

我們希望這些 lib 能幫我們做什麼?怎麼做的? • 傳送 SQL 讀取結果 -> ⽤什麼形式? • 預防 SQL Injection -> 怎麼預防的?

Slide 8

Slide 8 text

使⽤範例: lib/pq

Slide 9

Slide 9 text

使⽤範例: gorm

Slide 10

Slide 10 text

使⽤範例: go-pg

Slide 11

Slide 11 text

使⽤範例: pgx

Slide 12

Slide 12 text

我們希望這些 lib 能幫我們做什麼?怎麼做的? • 傳送 SQL 讀取結果 -> ⽤什麼形式? • Printable SQL Representation? • 預防 SQL Injection -> 怎麼預防的? • Parameter Placeholder?

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

範例 Users 表 先插入⼀個有 200 bytes 的 secret 的 foo user 然後⽤不同 lib 讀出來看看

Slide 15

Slide 15 text

go-pg

Slide 16

Slide 16 text

go-pg 預設即便使⽤ Parameter Placeholder 寫法,
 依然使⽤ Simple Query 與 PG 溝通。
 SQL Injection 的防範仰賴 go-pg 做正確的參數跳脫

Slide 17

Slide 17 text

並且在 Simple Query 下,回傳 bytea 以 Hex 表⽰
 體積變成原本的兩倍

Slide 18

Slide 18 text

lib/pq

Slide 19

Slide 19 text

lib/pq

Slide 20

Slide 20 text

lib/pq

Slide 21

Slide 21 text

lib/pq lib/pq 則使⽤ Extended Query Protocol
 避免 SQL Injection,並且指定 bytea 使⽤
 Binary Format 回傳

Slide 22

Slide 22 text

lib/pq bytea 使⽤ Binary Format 回傳
 沒有浪費頻寬

Slide 23

Slide 23 text

關於 PG 的 Protocol 細節可以於⼿冊 52 章節找到

Slide 24

Slide 24 text

Extended Query Protocol 的好處 • 避免 SQL Injection • 重複利⽤ Parse 結果? • Binary Format 節省頻寬?

Slide 25

Slide 25 text

PostgreSQL Binary Format vs Text Format Binary Format Size Text Format Size Text Example UUID 16 bytes 36 bytes d4d1d263-4f5c-49bb -ae36-1e26d4adf44a Timestampz 8 bytes ~ 30 bytes 2020-06-22 17:16:28.87282+00 Bigint 8 bytes 1 ~ 19 bytes 9223372036854775807 Bytea Variable Hex
 2x size \x1feb6644e0

Slide 26

Slide 26 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary Data Result 重複使⽤ Parse lib/pq V gorm V go-pg X pgx V

Slide 27

Slide 27 text

lib/pq

Slide 28

Slide 28 text

lib/pq 在使⽤ Prepare 時,預設使⽤ Text 傳參數
 回傳的 Bytea 使⽤ Binary Format,
 回傳的 Timestampz 使⽤ Text Format

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

lib/pq + binary_parameters=yes

Slide 31

Slide 31 text

Prepare 在開啟 binary_parameter 參數後,
 Bytea 參數也會使⽤ Binary Format 傳遞給 PG

Slide 32

Slide 32 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary Data Result 重複使⽤ Parse lib/pq + Parepare - X Bytea Only lib/pq + Parepare binary_parameters=yes - Bytea Only Bytea Only gorm(lib/pq) V gorm(lib/pq) + binary_parameters=yes V go-pg X pgx V

Slide 33

Slide 33 text

gorm (與 lib/pq 不使⽤顯性 Prepare 呼叫相同)

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

gorm + binary_parameters=yes

Slide 36

Slide 36 text

gorm 與 lib/pq 比較特別的是
 當不使⽤ Prepare 顯興呼叫,並且開啟
 binary_parameters 後,P/B/D/E 這幾個
 訊息會⼀起送給 PG,取得結果只有 1 RTT
 
 但 Bytea 的回傳它會改回使⽤ Hex Format

Slide 37

Slide 37 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT 重複使⽤ Parse lib/pq + Parepare - X Bytea Only 2 lib/pq + Parepare binary_parameters= yes - Bytea Only Bytea Only 2 gorm(lib/pq) V X Bytea Only 2 gorm(lib/pq) + binary_parameters= yes V Bytea Only X 1 go-pg X pgx V

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

go-pg

Slide 40

Slide 40 text

go-pg 完全不⽀援 Binary Format

Slide 41

Slide 41 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT 重複使⽤ Parse lib/pq + Parepare - X Bytea Only 2 lib/pq + Parepare binary_parameters= yes - Bytea Only Bytea Only 2 gorm(lib/pq) V X Bytea Only 2 gorm(lib/pq) + binary_parameters= yes V Bytea Only X 1 go-pg + Parepare - X X 2 pgx V

Slide 42

Slide 42 text

pgx

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

pgx 搭配 pgtype 即可⽀援多達 70 多種的 Binary Format

Slide 46

Slide 46 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT 重複使⽤ Parse lib/pq + Parepare - X Bytea Only 2 lib/pq + Parepare binary_parameters= yes - Bytea Only Bytea Only 2 gorm(lib/pq) V X Bytea Only 2 gorm(lib/pq) + binary_parameters= yes V Bytea Only X 1 go-pg + Parepare - X X 2 pgx V 70 types 70 types 2

Slide 47

Slide 47 text

重複使⽤ Parse 
 減少 RTT 與解析 SQL 次數? 預期中的實作應該像右邊流程圖
 go-pg ⽬前卻不是這樣

Slide 48

Slide 48 text

lib/pq 將 Connection Pool ⼤⼩設定成 2
 並送 6 個慢 query 觀察 lib/pq 如何使⽤
 Extended Query Protocol

Slide 49

Slide 49 text

不顯性呼叫 Prepare 時
 lib/pq 並不會重⽤ Parse
 因此這邊可以看到 6 次 Parse

Slide 50

Slide 50 text

lib/pg + Prepare

Slide 51

Slide 51 text

lib/pg + Prepare 顯性呼叫 Prepare 時
 lib/pq 重⽤ Parse
 因此這邊只看到 2 次 Parse
 並且後續的查詢只需要 1 RTT

Slide 52

Slide 52 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT(重複使⽤) 重複使⽤ Parse lib/pq + Parepare - X Bytea 2(1) V lib/pq + Parepare binary_parameters= yes - Bytea Bytea 2(1) V gorm(lib/pq) V X Bytea 2 X gorm(lib/pq) + binary_parameters= yes V Bytea X 1 X go-pg + Parepare - X X 2 pgx V 70 types 70 types 2

Slide 53

Slide 53 text

go-pg 53

Slide 54

Slide 54 text

go-pg 在相同的測試中只看到 1 次 Parse
 與預期中看到 2 次 Parse 不符。

Slide 55

Slide 55 text

這是因為 go-pg 在 prepare stmt 創建的的當下
 會立刻綁定⼀個 connection 給它。
 
 這個 stmt 雖然可以 concurrently 呼叫,但它的
 concurrency 被限制在只有 1,容易有效能問題。

Slide 56

Slide 56 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT(重複使⽤) 重複使⽤ Parse lib/pq + Parepare - X Bytea 2(1) V lib/pq + Parepare binary_parameters= yes - Bytea Bytea 2(1) V gorm(lib/pq) V X Bytea 2 X gorm(lib/pq) + binary_parameters= yes V Bytea X 1 X go-pg + Parepare - X X 2(1) concurrency=1 pgx V 70 types 70 types 2

Slide 57

Slide 57 text

pgx

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary
 Data Result RTT(重複使⽤) 重複使⽤ Parse lib/pq + Parepare - X Bytea 2(1) V lib/pq + Parepare binary_parameters= yes - Bytea Bytea 2(1) V gorm(lib/pq) V X Bytea 2 X gorm(lib/pq) + binary_parameters= yes V Bytea X 1 X go-pg + Parepare - X X 2(1) concurrency=1 pgx V 70 types 70 types 2(1) V

Slide 60

Slide 60 text

Q&A

Slide 61

Slide 61 text

夥伴招募中,歡迎投履歷~