FastAPI 該用 async def 還是 def?

前言 FastAPI 是近幾年繼 Flask 之後更火紅的 Python web server,不僅能自動生成 OpenAPI-Swagger 的 API 文件,也增加了類似 Node.js 的 Async 異步機制,大幅的提升效能.儼然已成為 Python 開 API 的不二人選.但使用上有踩到 def 與 async def 的陷阱,所以有了這篇文章來解釋遇到的問題 Concurrency vs Parallelism 開始以前先複習一下,這兩個名詞是不等價的,描述的是不同的併發狀況 Concurrency 單一時間點,單一 worker 一次只做一件事情,但會交錯切換來完成任務,旨在快速處理任務 ex: 一個廚師同時切換工作項目來料理,如: 切菜, 煮飯, 燒水 多以 Thread 或 Async IO 來達成,因為 IO bound 的 task 更適合,例如: network 的連線等待或 file 的讀取 Parallelism 單一時間點,有多個 worker 會同時做多件事情,所以並行的執行任務,旨在處理更多的任務 ex: 銀行櫃檯有多個窗口,並行的處理任務 多以 Multiple Process 來達成,因為 CPU bound 的 task 更適合,例如: 大量耗時的 Machine Learning 矩陣計算 圖片來源: Async IO in Python: A Complete Walkthrough – Real Python...

<span title='2023-03-28 19:49:13 +0800 +0800'>March 28, 2023</span>&nbsp;·&nbsp;4 min&nbsp;·&nbsp;651 words&nbsp;·&nbsp;Madi

初探 Prometheus 與 Grafana

前言 前陣子公司團隊的 SRE 導入 Prometheus 和 Grafana 來監測我們 RD 開發的服務,因為好奇心使然,想說順帶了解一下這兩個監測服務,就整理了這篇文章來記錄一下使用的心得 Prometheus 簡介 Prometheus 是一套開源的 監測(monitor) 與 警示(alert) 工具,負責收集和儲存監測對象的指標(metric) metric 泛指一切需觀察的數據,例如 web server 的每秒 request 數量、DB 每秒的連線數量…等等 而這些 metric 都是隨著時間不斷更新,因此會以 Time series 的方式為數據本身壓一個 timestamp 來儲存,也可以為該 metric 建立一個 optional 的 key-value pair 的 label Prometheus 主要的 features 有: 多維的 data model,包含 time series 與 key-value pairs 的 label 自帶 query language PromQL,用於下一些 metric 的 query 語句 是一個基於 HTTP 協定的 pull-based model(會叫 pull-based 的原因是 Prometheus 會定期去跟監測對象索取 metrics) 符合微服務架構的 Application Metrics Pattern,集中式收集與監測各服務的指標 具體流程 Prometheus 會用一個 prometheus....

<span title='2023-03-18 19:49:13 +0800 +0800'>March 18, 2023</span>&nbsp;·&nbsp;4 min&nbsp;·&nbsp;756 words&nbsp;·&nbsp;Madi

[閱讀筆記] Design Data-Intensive Application - Storage and Retrieval (OLAP)

前言 本篇繼續探討 Design Data-Intensive Application 這本書的第三章:Storage and Retrieval 簡單整理一下本小節主要談論的架構: OLTP(Transaction) Row-orient storage Database engine Log-structure -> ex: LSM, SSTable, Lucene… page-orient(B tree) -> some RDBMs and NoSQL OLAP(Analytic) data warehouse(ETL) Column-orient storage bitmap encoding run-length encoding Column Families(Cassandra) 今天這篇主要要談論的是 OLAP 的部分 OLTP vs OLAP 兩者比較的關鍵是 事務處理(Transaction)還是分析(Analytic)? OLTP(OnLine Transaction Processing) 以往來說,資料庫交互都圍繞在商業交易這類跟錢相關的交易(commercial transcation),當應用拓展到不同領域後,漸漸已經跟錢無關,最後就剩下保留 交易/事務(transcation) 這個術語與概念,用於描述一組讀寫操作的邏輯單元 使用上,應用程式會需要透過索引(index)的方式查找某個鍵值對應的少量資料,依據 user 的 input(insert, update, delete)來更新紀錄 這種交互式的方式關心的是能否快速的回應 user 的 query 或 insert,在大量負載時能降低操作時的延遲,所以 disk search time 會是瓶頸,而 OLTP 應付的資料量相對於 OLAP 來說更少,也比較關心的是即時的資料....

<span title='2023-03-03 00:49:13 +0800 +0800'>March 3, 2023</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;352 words&nbsp;·&nbsp;Madi

[閱讀筆記] Design Data-Intensive Application - Storage and Retrieval (OLTP)

前言 本篇繼續探討 Design Data-Intensive Application 這本書的第三章:Storage and Retrieval 簡單整理一下本小節主要談論的架構: OLTP(Transaction) Row-orient storage Database engine Log-structure -> ex: LSM, SSTable, Lucene… page-orient(B tree) -> some RDBMs and NoSQL OLAP(Analytic) data warehouse(ETL) Column-orient storage bitmap encoding run-length encoding Column Families(Cassandra) 今天這篇主要要談論的是 OLTP 的部分,以 index structure 的設計為主題 Database storage engine 書中從被應用至 RDBMs 和 NoSQL 底層的 database storage engine 談起 Log-structured 許多資料庫都會有內部的日誌(log),本身是一個 append-only 的文件,用於描述應用程式正在發生的事情的紀錄,或許是二進位制的,因為本來就不是設計給人類看的.但當紀錄變多時,查詢時間會很久,所以為了加速搜尋,就需要有額外的結構來輔助我們,這個 additional structure 就是 index 但為了維護這個額外的結構,會多多少少的影響到寫入的速度,因為每增加一筆資料都要更新 index,正因如此,資料庫預設都不會加上 index,而是交給程式開發者或是 DBA 來設計該用什麼樣的 index 來增快查詢,避免額外的開銷...

<span title='2023-03-03 00:49:13 +0800 +0800'>March 3, 2023</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;361 words&nbsp;·&nbsp;Madi

JWT & SendGrid - 實作電商忘記密碼

前言 前陣子參與一個電商的開發案,參考一些開源專案的設計,包含火紅的 Shopify 替代方案-Medusa,研究完後大致了解該怎麼實作和設計一系列跟密碼重設、忘記密碼、註冊登入…等電商功能,所以就有了此篇文章來紀錄一下過程,實作內容是 Medusa 的原始碼,會以一個 high-level 的設計來闡述設計的流程與該注意的事項 以使用者觀點來看忘記密碼/重設密碼這件事 一般來說,我們在用任何有登入、註冊相關的網站,都會有「忘記密碼」的按鈕,但實際上網站後台的資料庫並不會存我們密碼的明碼(理論上都不應該 QQ),所以當按下忘記密碼後,我們會收到一個電子信箱,裡頭並不會原封不動地將我們的密碼傳回來,因為該網站的資料庫存的是 hashed 過後的密碼,而 hash 是無法被逆向回推的,所以這時候信件裡應該是一組 url,點擊後會跳轉到該網站寫好的重設密碼的頁面,讓該使用者輸入密碼與確認密碼,以便重新設定一組新密碼. 例如下圖的 email 截圖,圖片來源: https://designmodo.com/reset-password-emails/ 以上就是一般使用者的操作流程,這些流程大家都再熟悉不過,但背後的系統流程是怎麼運做的呢? 簡述設計流程 既然要收發信件,肯定需要有寄信服務,寄送信件的服務有很多種,最常見的就是SendGrid,我在實作中有註冊一組帳號來取得發送 email 的 token,但後來開發上有受到一些阻礙與問題,最終改用 這篇文章 和 這篇文章 提到的 GCP 支援的 SendGrid Email API 免費方案來完成寄信功能,目前運作起來一切正常 有了寄信服務之後,接下來要解決的是怎麼確保重設密碼的人就是該帳號的擁有者,避免中間過程被盜取身份,竄改該使用者的密碼? 這個問題是最關鍵的,也就是身份認證的資安議題 一般來說,身份認證(Authentication)肯定會需要 DB 來儲存該 user 的個人資料與帳號密碼,因此實作中我使用 PostgreSQL 作為 DB 的選用,而現今認證機制大多使用 JWT,好處是省去 server 再拿 session id 撈一次資料庫的成本,直接用 base64 將 payload 內容 decode,拿到其中就算公開也沒差的無隱私資料,例如:user id,接著服務當場拿該 user id 去問 DB 該 user 的資料,當然也會帶著 JWT token 去詢問,此時 JWT 的第三部分(signature)的 secret 就是判斷該 token 是否有被篡改的依據,若成功驗證,就能成功取得該 user 的資料,完成身份認證(Authentication)甚至授權(Authorization)的流程...

<span title='2023-02-27 00:49:13 +0800 +0800'>February 27, 2023</span>&nbsp;·&nbsp;5 min&nbsp;·&nbsp;923 words&nbsp;·&nbsp;Madi