0%

前言

在 Postgresql 世界裡每建立一個 Connection,都會有一個 process 來服務該請求,Postgresql 沒有 ThreadPool 概念所以在 Connection 使用量大時會發生一些問題

  • 資源浪費
  • 超過同時間超過 max_connection 後面連接會無法連接

一個 open source 插件 PgBouncer 就是幫我們解決上面問題,不過如果你是使用 AWS RDS 來當作 DB 就很適合使用 RDS Proxy

本次使用免費帳號範圍提供的機器 db.t2.micro

另外因為 RDS Proxy 在 EC2 內網才能連接,所以我也利用免費帳號準備一台 EC2 並安裝 pgbench 進行壓力測試

壓測前準備 & 說明

我把 max_connections 最大連接數量調整成 550

Read more »

前言

資料結構跟演算法是程式設計師的內功,在中小型系統懂這兩樣東西效用可能有限,但在大型系統中熟不熟用資料結構跟演算法做出來的效益會天差地遠

對於常使用的物件和變數我們會放置在 Redis 上( cache server ),但記憶體有限,我們想放的東西無限,造就無法將所有物件都存放在 Redis 或 Server Memory 上.

假如你有設定過 Redis config 你會看到一個 property maxmemory_policy 來管理如何淘汰,記憶體中的物件

  • volatile-lru
  • allkeys-lru

上面有個名稱 LRU (Least Recently Used Cache) 代表甚麼意涵呢?稍後會跟大家做解釋

Github Sample Project

LRU 算法概念

LRU (Least Recently Used Cache) 顧名思義,會記憶體不夠用時優先保留最近常使用的 Cache 資料,並剔除最舊的資料來緩解壓力

這個算法策略可以確保 Hot Data 在記憶體不足時不會被刪除

Read more »

前文

我認為 DB query optimizer (QO) 產生執行計畫並執行查詢和 使用地圖找尋最佳路徑很類似

下面會跟大家分享我心中 地圖理論 希望可以對於想了解 DB 運作的人更快上手

看見全貌

在了解一個事情跟技術,我們需要先用宏觀的角度來看待事情

下圖是 postgresql DB 運作核心概念圖

其中在執行語法前後最重要的幾個步驟是

  1. Parser:檢查語法是否有錯誤,如果錯誤就不執行後續步驟
  2. ReWriter:嘗試優化改寫 SQL
  3. Planner:利用統計資訊 & 演算法建立執行計畫
  4. Executor:挑選一個成本最低的執行計劃來查找資料

我認為資料 Search Engine 的 Planner & Executor 核心概念跟查找地圖( google map 很類似 )

Read more »

前言

我之前有寫透過 lock or CAS 來防治,Racing condition 問題,但如果這個問題延深到多台服務器甚至是 micor-services 架構我們要怎麼處理資料問題呢?

下面程式在單體服務或應用程式不會出問題,但如果服務器有多台問題可就大了,因為下面的 lock 只限於單體 Server 上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private readonly static object _lock = new object();
[HttpGet()]
public string Get()
{
int remainCount;
lock (_lock)
{

remainCount = (int)RedisConnection.GetDatabase().StringGet(_productId);
if (remainCount > 0)
{
RedisConnection.GetDatabase().StringSet(_productId, --remainCount);
}
}

string productMsg = remainCount <= 0 ? "沒貨了賣完了" : $"還剩下 {remainCount} 商品";
string result = $"{Dns.GetHostName()} 處理貨物狀態!! {productMsg}";
_logger.LogInformation(result);
return result;
}

如果有聽過 Redis 可能就會聽過 RedLock.net 來處理,但您知道 RedLock.net 底層大致上怎麼實作的嗎?

本篇文章會帶領大家透過 distlock 算法時做出,自己的Redlock

本篇只介紹核心概念,細部防錯我沒有寫出來,所以建議本篇程式不要用在 prod 環境

我使用 docker-compose 建立問題架構,架構圖如下

原始碼位置 Redlock-Csharp

Read more »

前言

執行計畫代表此次查詢要怎麼樣的演算法查詢我們的資料,而成本是決定使用哪個執行計畫的重要因素

在 postgreSQL DB query optimizer 會選擇成本最低的執行計劃,當作查詢資料使用算法

在 Sql-sevrer 成本計算封裝在程式內部,我們無法透過一些因子來調整,但 postgreSQL 可以

我認為 query optimizer 判斷成本概念有點類似 google map 在找尋最佳路徑

我對於資料庫有定義一個,地圖理論來說明 RDBMS 執行計畫相關的事情

本篇成本因子效能調教會涉 Linux kernel systemtap ,國中數學,postgreSQL 運作模型,篇幅可能會有點多且複雜

但我認為本篇學會可以對於 query optimizer 有更進一步了解

預設成本因子潛在問題

下面我使用一個例子來

Read more »

前言

AWS 在有眾多服務,其中我對於 Lambda 最有興趣 (因為 .net 有一個 Lambda 表達式 )

最近申辦帳號可以使用 12 個月部分免費服務(有條件限制),看我還不玩爆 AWS XD

經過了解得知 Lambda 是一個 EDA 架構並幫我們解決開發時需要煩惱硬體上配置(記憶體要多少,CPU,是否需要 load balance scale out…),做一個 serverless 服務

讓我們可以專心開發程式,本篇會針對 .net core 建立一個 sample 專案到上傳到 AWS Lambda 服務上說明

安裝aws cli & 設定 profile

首先我們需要先安裝 aws cli,如果是 windows 我們可以透過 powershell,來完成

1
C:\> msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
1
2
$ aws --version
aws-cli/2.2.44 Python/3.8.8 Windows/10 exe/AMD64 prompt/off

確定安裝完後我們可以執行 aws configure 設定我們 AWS 服務相關 IAM 資訊

Read more »

前言

WAL 是一種 Tx Log實踐機制

WAL 核心概念是先寫 tx log,在把資料寫資料,資料的修改必须發生在寫入 Tx Log之後,使用 WAL 紀錄資料庫系統在commit transaction

使用 WAL 機制後我們不需要在每次 Commit Transaction 後就把資料 flush 到 Disk 上(提高IO效率), WAL 需要保證 Dirty Block flush 到 Disk 之前,該 Block 對應 Tx log 紀錄已經 flush 到 Disk 中

因為假如系統突然崩潰我們可以藉由 WAL 寫入 Tx Log 來 roll-forward recovery (REDO)

WAL 寫入時機簡介

LSN序號是一個 globale 變數(透過 info_lck 輕量鎖設計避免同一時間取得同一個 LSN )

寫入資料會經由下面幾個步驟

  1. Log (LSN–Log) 是一個有順序性標誌的紀錄 (可以想像是一個 sequence ) ,一開始存在 RAM 中,在 RAM 中有一個 flushLSN 位置會記錄 log LSN 寫入 Disk 最後位置.
  2. 每個 block 在 pageheader 會有一個欄位 PageXLogRecPtr pd_lsn; 指到 log 紀錄位置,此位置在 Dirty Block 存在 buffer Pool 時就會決定
  3. 最後把 Dirty Block flush 到 Disk 之前 postgresSQL 會檢查是否滿足此條件 pd_lsn <= flushLSN ,確保 Log 已經寫入 Disk 上才會把資料 flush 到資料庫中
  4. 如果是 synchronous_commit = ON 代表同步提交,在 Transaction commit 時會把對應的 Tx Log 馬上 flush 進 Disk中才能返回成功

經過上面步驟我們就可以確保 先寫 Tx Log 歷程,後寫 Dirty Block

Read more »

前言

Postgresql DB 目前預設在更新資料時會在 Heap Table 新增一條新版本資料,舊版本會先存在直到使用 VACUUM 回收

HOT update 作用在,當資料更新時通過 Heap Block 內部串聯所有 tuple 版本,則 Index 索引不變

HOT update 必須滿足以下兩個條件:

  1. 索引欄位值不變。(其中任意一個索引字段的值發生了變化,則所有索引都需要新增版本)
  2. 新版本資料和舊版本資料在同一個HEAP Block中。

在測試前我們要先開啟 pageinspect 了解查看 block 底層訊息

sample data

1
create extension pageinspect -- 打開可以查看底層 Page 功能,需要有 admin 權限
1
2
3
4
5
6
7
CREATE TABLE tt2(id int,a int,b int);  

INSERT INTO tt2
SELECT generate_series(1,10), random()*100, random()*100;

CREATE INDEX ix_tt2_id ON tt2 (ID);
CREATE INDEX ix_tt2_a ON tt2 (a);

接著我們透過 bt_page_items 查看 Index 儲存資料,heap_page_items 查看 heap table 儲存資料

Read more »

前言

因為工作需要最近在研究 postgresql DB,發現跟 sql-server 相比有許多不同之處,所以一開始就先研究 Page 差別,沒想到還真的有不少細節上的差異

在postgresql DB Page size 預設是 8KB

我們想要看page使用大小在 Sql-Server 可以用 DBCC命令在 postgresql DB 沒有 DBCC 還好有其他方式可以查看 Page 儲存原理

如果要了解存儲怎麼辦呢?

關於 page 存儲

使用sample data

1
2
3
4
CREATE TABLE t1 (id int PRIMARY KEY);

insert into t1 select generate_series(1,2000);
insert into t1 select generate_series(2001,4000);

建立完表後我們透過 \d+ t1 指令查看資料表訊息,可以看到PK成功被建立

1
2
3
4
5
6
7
postgres=# \d+ t1
Table "public.t1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+---------+--------------+-------------
id | integer | | not null | | plain | |
Indexes:
"t1_pkey" PRIMARY KEY, btree (id)
Read more »

前文

在處理高併發系統架構時,非同步是一個很好的手段和提升效率的方式.

我今天跟大家分享,如何利用 MQ 搭配 Worker Pool 來提高系統吞吐量且又不失彈性

原始碼連結 MQ Woker

本篇會包含兩個部分解說

  1. 如何使用 k3d (k8s) 和 docker-compose 來 Run 起我們 MQ 服務
  2. 主要核心程式解說

系統簡介

我們透過 MQ 來幫系統作解耦合,前台要處理事情都會先統一打到 MQ 中之後就可以先回覆,使用者結果,後續處理就交給 MQ 來幫我們派發任務到我們指定的 Worker 上處理業務邏輯,這樣可以把原本架構前台後台高偶合的問題解決提供可承受且快速響應的架構.

目前支援兩種 Worker.

  • ThreadPool:使用 Thread 當作 Worker 來幫我們處理任務
Read more »