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

Golang 
PostgreSQL Libraries Comparison With Wireshark

E91a24de5f8858932171b35bd47c8485?s=47 Rueian
June 23, 2020

Golang 
PostgreSQL Libraries Comparison With Wireshark

透過 Wireshark 比較 lib/pq, gorm, go-pg, pgx 實作上的差異,希望能幫助大家了解各個 library 如何與資料庫溝通。

Medium 版:
https://medium.com/dcardlab/postgresql-%E4%BD%BF%E7%94%A8-extended-query-protocol-%E9%81%BF%E5%85%8D%E9%A0%BB%E5%AF%AC%E8%88%87%E6%95%88%E8%83%BD%E6%B5%AA%E8%B2%BB-b708af73882e

E91a24de5f8858932171b35bd47c8485?s=128

Rueian

June 23, 2020
Tweet

Transcript

  1. Ruian Huang @Golang Taipei 2020/06/23 Golang 的熱⾨ 
 PostgreSQL Library

    比較 透過觀察封包比較實作上的差異
  2. Dcard ⼯程師 • 交⼤資⼯畢業 • 偶爾寫點⽂章
 https://medium.com/@ruian
 
 包含 PG

    Wire Protocol 與 Query Optimizer 相關⽂章 Ruian Huang
  3. 回顧去年同樣於 Golang Taipei 分享的主題

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

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

  6. 這次比較的 lib • lib/pq v1.7.0 • Gorm (同 lib/pq) •

    go-pg/v10 • pgx/v4
  7. 我們希望這些 lib 能幫我們做什麼?怎麼做的? • 傳送 SQL 讀取結果 -> ⽤什麼形式? •

    預防 SQL Injection -> 怎麼預防的?
  8. 使⽤範例: lib/pq

  9. 使⽤範例: gorm

  10. 使⽤範例: go-pg

  11. 使⽤範例: pgx

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

    Printable SQL Representation? • 預防 SQL Injection -> 怎麼預防的? • Parameter Placeholder?
  13. None
  14. 範例 Users 表 先插入⼀個有 200 bytes 的 secret 的 foo

    user 然後⽤不同 lib 讀出來看看
  15. go-pg

  16. go-pg 預設即便使⽤ Parameter Placeholder 寫法,
 依然使⽤ Simple Query 與 PG

    溝通。
 SQL Injection 的防範仰賴 go-pg 做正確的參數跳脫
  17. 並且在 Simple Query 下,回傳 bytea 以 Hex 表⽰
 體積變成原本的兩倍

  18. lib/pq

  19. lib/pq

  20. lib/pq

  21. lib/pq lib/pq 則使⽤ Extended Query Protocol
 避免 SQL Injection,並且指定 bytea

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

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

  24. Extended Query Protocol 的好處 • 避免 SQL Injection • 重複利⽤

    Parse 結果? • Binary Format 節省頻寬?
  25. 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
  26. Extended Query Protocol 的⽀援程度 ⾃動使⽤ EQP Binary Parameter Binary Data

    Result 重複使⽤ Parse lib/pq V gorm V go-pg X pgx V
  27. lib/pq

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

    Format,
 回傳的 Timestampz 使⽤ Text Format
  29. None
  30. lib/pq + binary_parameters=yes

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

  32. 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
  33. gorm (與 lib/pq 不使⽤顯性 Prepare 呼叫相同)

  34. None
  35. gorm + binary_parameters=yes

  36. gorm 與 lib/pq 比較特別的是
 當不使⽤ Prepare 顯興呼叫,並且開啟
 binary_parameters 後,P/B/D/E 這幾個


    訊息會⼀起送給 PG,取得結果只有 1 RTT
 
 但 Bytea 的回傳它會改回使⽤ Hex Format
  37. 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
  38. None
  39. go-pg

  40. go-pg 完全不⽀援 Binary Format

  41. 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
  42. pgx

  43. None
  44. None
  45. pgx 搭配 pgtype 即可⽀援多達 70 多種的 Binary Format

  46. 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
  47. 重複使⽤ Parse 
 減少 RTT 與解析 SQL 次數? 預期中的實作應該像右邊流程圖
 go-pg

    ⽬前卻不是這樣
  48. lib/pq 將 Connection Pool ⼤⼩設定成 2
 並送 6 個慢 query

    觀察 lib/pq 如何使⽤
 Extended Query Protocol
  49. 不顯性呼叫 Prepare 時
 lib/pq 並不會重⽤ Parse
 因此這邊可以看到 6 次 Parse

  50. lib/pg + Prepare

  51. lib/pg + Prepare 顯性呼叫 Prepare 時
 lib/pq 重⽤ Parse
 因此這邊只看到

    2 次 Parse
 並且後續的查詢只需要 1 RTT
  52. 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
  53. go-pg 53

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

  55. 這是因為 go-pg 在 prepare stmt 創建的的當下
 會立刻綁定⼀個 connection 給它。
 


    這個 stmt 雖然可以 concurrently 呼叫,但它的
 concurrency 被限制在只有 1,容易有效能問題。
  56. 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
  57. pgx

  58. None
  59. 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
  60. Q&A

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