0%

前言

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 »

前言

在 Rabbitmq 官方 Github 有開源一個 k8s 操作管理 RabbitMQ clusters 環境 cluster-operator.

這個專案在2020啟動,我個人覺得官方有些說明還沒很完善,本篇文章跟大家介紹如何去使用

建立 operator

1
kubectl apply -f https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml

下面的yaml檔案是建立一個RabbitmqCluster

1
2
3
4
5
6
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
name: hello-world
spec:
replicas: 3

透過 kubectl apply -f {your yaml filename} 後就可以透過 kubectl get all 查看 RabbitMQ cluster 是否建立完成

如果建立完成會出現類似下圖

Read more »

前文

k8s前身是Google開發borg系統,用於管理Google系統,後面由許多borg核心開發人用利用Go語言改寫就造就Kubernetes

可以根據聲明式設定,管理、擴展我們的容器化應用編排系統

  • 有效安全幫我們執行Container Rollout
  • 能夠因應系統流量變化,進行伸縮擴容(Scaling)
  • Health check實現自動偵測故障及重啟功能
  • 透過Namespace有效幫我們做資源隔離

k8s協助我們方便掌控複雜容器系統架構,具有良好伸縮性

建議在閱讀k8s文章前先要有Docker相關知識,不然許多點會有看沒有懂

我們練習會使用k3d使用Docker建議k8s來練習

k8s 主要組件介紹

先來張圖(此圖來自wiki)wiki畫的很棒,我拿來借用一下XDD

Read more »

前文:

我們在撰寫C#時常常會聽到CLR(Common Lnguage Rumtime),但對於CLR又認知多少呢?

本篇會跟大家介紹CLR基本且核心的物件

CLR 簡介

編譯器在編譯時把(C#,VB,F#….)進行編譯檢查跟把程式碼轉成MSIL中繼資料,在運行期間透過JIT(just in time)會在程式運行期間把MSIL轉成每個機器可以執行組合語言

大概可以理解為下圖

這邊我不探討Management和UnManagement物件
MSIL也算是微軟開發語言的一個抽象

SOS Debuger

注意你的電腦是 x86 or x64

Read more »

前言

你知道object lock底層怎麼實作,可重入鎖是底層是怎麼運作的嗎?

本篇就跟大家分享這些細節.

可重入鎖Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Program
{
static object _object = new object();

static void Main(string[] args)
{
Task.WaitAll(Task.Run(() => { TryLockDemo(); }), Task.Run(() => { TryLockDemo(); }));

Console.WriteLine("Hello World!");
}

public static void TryLockDemo() {
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"[{threadId}] {DateTime.Now:HH:mm:ss} TryLockDemo Start");
try
{
Monitor.Enter(_object);
Console.WriteLine($"[{threadId}] {DateTime.Now:HH:mm:ss} get first lock");
try
{
Thread.Sleep(3000);
Monitor.Enter(_object);
Console.WriteLine($"[{threadId}] {DateTime.Now:HH:mm:ss} get second lock");
}
finally
{
Monitor.Exit(_object);
Console.WriteLine($"[{threadId}] {DateTime.Now:HH:mm:ss} release second lock");
}
}
finally
{
Thread.Sleep(3000);
Monitor.Exit(_object);
Console.WriteLine($"[{threadId}] {DateTime.Now:HH:mm:ss} release first lock");
}
}
}

上面這段程式碼,同時間會由2個Thread來呼叫處理TryLockDemo方法.

主要是演示lock中在對於同一個object lock一次且在multiple-Thread中會怎麼運作

為什麼Thread 1釋放first lock時,Thread 2會繼續blocking並等待Thread 1釋放second lock?

object中Syncblk

Read more »

前言

假如你寫過多執行緒系統一定會看過volatile,但你對他的了解有多少?

MSDN對於volatile關鍵字解釋如下.

volatile 關鍵字指出某個欄位可能是由同時執行的多個執行緒所修改。 編譯器、執行階段系統,甚至硬體都有可能基於效能因素,而重新排列對記憶體位置的讀取和寫入。 宣告為 volatile 的欄位不受限於這些最佳化考量。 加入 volatile 修飾詞可確保所有的執行緒都會依執行寫入的順序,觀察任何其他執行緒所執行的暫時性寫入。

MSDN上寫一堆文謅謅的解釋,如果沒有相對應OS或底層概念會很難理解上面敘述

volatile 三大特性

這裡我先總結volatile三大特性

  1. volatile修飾的變數具有可見性
  2. volatile避免指令優化重排
  3. volatile不保證Atomic

本文會針對這三大特性來一一解釋

注意在執行本文程式碼時要把Build Mode改成Release.

Read more »

前言

在多執行緒系統中,Thread的執行和長短是交由OS來幫我處理了

假如有一個面試題目是

  • 目前有三個Thread 每個Thread個別負責Print “A”,”B”,”C”

  • 要求:利用三個Thread並按照A,B,C順序打印出20次資訊,中間不能錯號

    ex:
    A
    B
    C
    A
    B
    C

程式碼框架如下,在Main函式建立3個Threads分別負責A,B,C字母打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Program
{
static void Main(string[] args)
{
Alternate c = new Alternate();
var t1 = new Thread(c.CallA);
var t2 = new Thread(c.CallB);
var t3 = new Thread(c.CallC);

t1.Start();
t2.Start();
t3.Start();

t1.Join();
t2.Join();
t3.Join();

Console.ReadKey();
}
}
public class Alternate
{
public void CallA()
{
for (int i = 0; i < 20; i++)
{
Console.WriteLine("A");
}

}

public void CallB()
{
for (int i = 0; i < 20; i++)
{
Console.WriteLine("B");
}

}
public void CallC()
{
for (int i = 0; i < 20; i++)
{
Console.WriteLine("C");
}
}
}

因為Thread被呼叫順序是由OS跟CPU來決定,目前執行如下圖所以目前打印出來的順序是無序的

期望可以打印出如下圖

Read more »