初探傳統關聯式資料庫如何處理高併發情境

前言 近年來隨著網路發展愈來愈快,高併發的場景愈來愈常見,高併發性能是指系統能夠有效地處理大量同時訪問和操作數據的能力,這在網路應用、金融系統、電子商務等領域愈來愈重要.隨著數據量的不斷增長和用戶需求的不斷擴展,我們需要確保我們的資料庫系統能夠承受高負載、高併發的壓力,同時保持良好的性能和穩定性。在這樣的背景下,優化資料庫的設計和架構、實施有效的併發控制策略成為至關重要的任務。 本篇是研究了一般 RDBMs 如何處理高併發問題的常見解法 Lock 機制 我們都知道寫程式的時候,如果有兩個 process/thread 要對同筆資料進行操作,為了避免資料的不一致,我們常會加上鎖的機制,臨時將該資源上鎖,僅允許一次只能被一個 process/thread 更動.同樣的,RDBMs 也有相同的機制來處理這種情形,這也是傳統資料庫處理高併發的最基本原理 SELECT … FOR UPDATE 為了避免兩個 transaction 同時對同筆資料進行操作,造成資料不一致的問題,一般常見的 RDBMs 都有提供底下這個 SQL 語法 BEGIN SELECT ... FOR UPDATE <各式針對該資料的操作, ex: UPDATE, DELETE...> COMMIT 一旦開啟新的 transaction 並執行這段 SQL 語法,在還沒 COMMIT 以前,資料庫將會替當前這筆資料加上鎖,鎖住這些即將要被更動的資料,因為資料庫悲觀的認為他們隨時有可能被修正(悲觀鎖),一旦上鎖後,下一個 tx 要進行操作時,都需要等待該鎖釋放後才能進行 至於這個鎖是行級鎖還是表級鎖,以及這個排他鎖會鎖哪些操作(SELECT? INSERT? UPDATE? DELETE?),則因各種資料庫背後的機制而不同 以 MySQL(InnoDB)為例,如果 SELECT 的對象加上 WHERE 條件是主鍵或有加上索引,則僅會加上行級鎖,鎖住當前查詢到的資料.但如果 WHERE 條件不是主鍵或非索引,則整個資料表都會被鎖住.正因如此,一旦 SELECT ... FOR UPDATE 沒寫好,MySQL 是有可能把整個資料表都鎖住,造成其他 transaction 需要等待鎖釋放才能進行操作,進而增加 latency 而影響使用者體驗.(以上前提要是 MySQL 的 InnoDB 作為 storage engine,因為 MyISAM 預設都是表級鎖)...

<span title='2024-05-05 00:49:13 +0800 +0800'>May 5, 2024</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;611 words&nbsp;·&nbsp;Madi

深究 PostgreSQL 底層架構

前言 PostgreSQL 是我目前工作與專案上最常用到的 RDBMs,為了能夠更了解 PostgreSQL 的運行以彌補底層的知識,就找到了 這系列 的文章,覺得內容非常的詳細與完整,很適合做為 PostgreSQL 進階的學習教材,就花了些時間整理了一下 底下的內容都是整理自 Distributed Systems Authority 的文章 PostgreSQL 底層架構 開始以前先放上 Distributed Systems Authority 繪製的架構圖,底下會依據各元件一一說明 整體來說,PostgreSQL 是採用近幾年蔚為流行的 Client-Server 架構 Client (frontend) 泛指一系列 client 連線方式,包含:psql, createdb, dropdb, createuser… 等 command line 指令 Server (backend) 可以概括稱之為 server process,負責管理 database files,接受 client 的連線,並執行 client 一系列相關的操作 當 server 收到每一筆 client 的連線,main process 都會 fork 出新的 process 來處理,所以 client 和 server 的溝通是與 main process 無關的 整體而言,backend 可分成底下四個元件: Process Manager 當執行 /usr/local/pgsql/bin/postgres 後就會建立第一個 daemon process,監聽每一個 client 對 server 發起的連線請求,在 max_connections 的數量限制下,daemon process 會為每一個連線 spawn 出 backend process 來讓 client query...

<span title='2023-05-30 19:49:13 +0800 +0800'>May 30, 2023</span>&nbsp;·&nbsp;4 min&nbsp;·&nbsp;750 words&nbsp;·&nbsp;Madi

Redis - 被挖礦病毒入侵攻擊的事件紀錄

前言 前幾天在 Linode 上開了一台 VPS 部署我的程式,裏頭用到 JWT token 與 Redis 作登入登出的機制,本來想說這個 VM 是做為測試用途,就沒有把 Redis 加密,也沒有限定 ip 連線,意外導致 redis 對外開放,受到挖礦病毒的攻擊,查了一下網路上的心得,發現蠻多人像我一樣一時疏忽而中招,因此寫了這篇文章來簡單紀錄一下過程。 事出必有因 整件事情的起頭是這樣,我在 VPS 上用 docker-compose 部署三個服務,分別是我的 api server、PostgreSQL、Redis,前端則是部署在 Netlify 上。 剛開始一切運行都很正常,但測試了一下馬上就發現有個小問題,我前端登入之後,沒多久 cookie 就失效被強制登出,由於我的 expire 設定 24 小時,沒道理這麼快就過期,所以直覺地去查了一下 Redis 內存的 session,看了一下記憶體用量也沒有發現什麼異常現象,就暫時沒有追蹤下去。 隔天我再測試,發現前端已經無法登入了,再次連到 VM 上看一下 api-server 的 log,發現源源不絕的 error 從 Redis 那邊不斷噴出來 1:S 15 May 2023 20:47:34.995 * Non blocking connect for SYNC fired the event. 1:S 15 May 2023 20:47:36.398 # Failed to read response from the server: No error information 1:S 15 May 2023 20:47:36....

<span title='2023-05-16 00:49:13 +0800 +0800'>May 16, 2023</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;303 words&nbsp;·&nbsp;Madi

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