Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

系統設計機制完整比較指南

目錄

  1. I/O 處理機制
  2. 記憶體管理
  3. 排程策略
  4. 並行控制
  5. 資料結構選擇
  6. 快取策略
  7. 網路與通訊
  8. 儲存策略
  9. 一致性模型
  10. 執行模式
  11. 設計模式

I/O 處理機制

1. 中斷 vs 輪詢 (Interrupt vs Polling)

比較項目中斷 (Interrupt)輪詢 (Polling)
運作方式事件發生時硬體通知CPUCPU定期檢查是否有事件
白話比喻像門鈴:有客人按門鈴才去開門像不停看門:每隔幾秒就去門口看有沒有人
CPU使用率低(只在事件發生時處理)高(持續檢查浪費資源)
回應時間可能有中斷延遲立即(但有檢查間隔)
適用場景鍵盤輸入、滑鼠點擊、硬碟完成通知高速網卡、即時遊戲、感測器讀取
優點效率高,CPU可做其他事實作簡單,延遲可預測
缺點有切換開銷,頻繁中斷效能差浪費CPU資源,不適合低頻事件
實際範例USB裝置插入時通知系統高頻交易系統每微秒檢查市場資料

詳細說明:

  • 中斷機制:當你在電腦上按下鍵盤,鍵盤會發送一個中斷訊號給CPU,CPU暫停當前工作,處理鍵盤輸入,然後繼續原本的工作。
  • 輪詢機制:遊戲引擎每16毫秒檢查一次手把按鈕狀態,確保即時回應玩家操作。
  • 混合策略:Linux的NAPI在網路封包少時用中斷,封包多時切換到輪詢避免中斷風暴。

2. 同步 vs 異步 (Synchronous vs Asynchronous)

比較項目同步 (Synchronous)異步 (Asynchronous)
運作方式等待操作完成才繼續發起操作後立即返回,稍後通知
白話比喻像排隊買咖啡:站在櫃台等咖啡做好才離開像點外賣:下單後可以做其他事,做好了送來
執行流程阻塞式,依序執行非阻塞式,可併行處理
程式複雜度簡單,邏輯順序清晰複雜,需要callback或Promise
適用場景檔案讀取、資料庫查詢(簡單應用)網頁伺服器、聊天應用、大量I/O操作
優點易於理解和除錯高效率,不浪費等待時間
缺點效率低,等待時間無法做其他事錯誤處理複雜,除錯困難
實際範例file.read() 必須等檔案讀完Node.js的 fs.readFile() 繼續執行其他程式碼

詳細說明:

  • 同步範例:你打電話給客服,必須等電話接通、問題處理完才能掛斷,這段時間什麼都不能做。
  • 異步範例:你發email給客服,發送後可以繼續工作,收到回覆時再處理。
  • JavaScript範例
    // 同步
    const data = readFileSync('file.txt'); // 等待完成
    console.log(data);
    
    // 異步
    readFile('file.txt', (err, data) => {
      console.log(data); // 稍後執行
    });
    console.log('繼續執行'); // 立即執行
    

3. 阻塞 vs 非阻塞 (Blocking vs Non-blocking)

比較項目阻塞 (Blocking)非阻塞 (Non-blocking)
運作方式呼叫會等待直到有結果立即返回,可能還沒準備好
白話比喻像ATM提款:插卡後必須等到錢吐出來像查詢ATM餘額:按了馬上顯示,不用等
返回時機操作完成時返回立即返回(可能返回錯誤碼)
錯誤處理成功或失敗明確需要重複嘗試(EAGAIN)
適用場景簡單的單一操作需要同時處理多個連接
優點邏輯簡單,結果確定可同時監控多個操作
缺點無法同時處理多個任務需要額外邏輯處理「未準備好」狀態
實際範例recv() 等到收到資料才返回recv(O_NONBLOCK) 沒資料就返回EAGAIN

詳細說明:

  • 阻塞範例:你打電話訂餐,必須等店員接電話、記錄完訂單,電話才能掛斷。
  • 非阻塞範例:你用App訂餐,點擊送出後App立即回到主畫面,訂單在背景處理。
  • Socket範例
    # 阻塞模式
    data = socket.recv(1024)  # 等到收到資料
    
    # 非阻塞模式
    socket.setblocking(False)
    try:
        data = socket.recv(1024)  # 立即返回
    except BlockingIOError:
        # 資料還沒準備好
        pass
    

4. DMA vs PIO (Direct Memory Access vs Programmed I/O)

比較項目DMAPIO
運作方式硬體直接存取記憶體,CPU不參與資料搬移CPU負責在記憶體和I/O裝置間搬移資料
白話比喻像快遞直接送貨到府:你不用親自去搬像自己去郵局領包裹:要親自搬運
CPU使用率低(CPU可做其他事)高(CPU忙著搬資料)
傳輸速度快(硬體直接存取)慢(經過CPU)
適用場景大量資料傳輸(硬碟、網卡、音效卡)少量資料、簡單裝置(舊式鍵盤、簡單感測器)
優點效率高,不佔用CPU實作簡單,硬體成本低
缺點需要專用硬體支援佔用CPU資源
實際範例硬碟讀取1GB檔案到RAM舊式印表機逐字元傳輸

詳細說明:

  • DMA範例:你下載電影時,網卡收到的資料直接寫入記憶體,CPU可以同時執行其他程式。
  • PIO範例:早期電腦讀取軟碟時,CPU要一個一個位元組搬移資料,這時電腦會變得很慢。
  • 效能差異
    • DMA:1GB資料傳輸,CPU使用率 < 5%
    • PIO:1GB資料傳輸,CPU使用率接近 100%

5. 零拷貝 vs 傳統拷貝 (Zero-Copy vs Traditional Copy)

比較項目零拷貝 (Zero-Copy)傳統拷貝 (Traditional Copy)
運作方式資料直接從來源到目的地,不經過CPU資料經過多次CPU拷貝(Kernel→User→Kernel)
白話比喻像傳送帶:貨物直接從倉庫到卡車像人工搬運:貨物先搬到暫存區再搬上車
CPU使用率極低(幾乎不佔用)高(CPU忙著拷貝資料)
拷貝次數0-1次4次(Disk→Kernel→User→Kernel→Network)
適用場景大檔案傳輸、影片串流、Proxy伺服器需要處理資料內容的場景
優點效能極佳,減少CPU和記憶體頻寬佔用可以在User space處理資料
缺點無法修改資料內容效能差,多次拷貝浪費資源
實際範例Nginx sendfile、Kafka檔案傳輸傳統HTTP伺服器read+write

詳細說明:

  • 傳統拷貝流程:發送檔案給客戶端
    1. read(): Disk → Kernel buffer (DMA)
    2. read(): Kernel buffer → User buffer (CPU拷貝)
    3. write(): User buffer → Socket buffer (CPU拷貝)
    4. write(): Socket buffer → Network card (DMA)
    總共:2次DMA + 2次CPU拷貝 + 4次上下文切換
    
  • 零拷貝流程:使用sendfile()
    1. sendfile(): Disk → Kernel buffer (DMA)
    2. sendfile(): Kernel buffer → Network card (DMA或直接描述符傳遞)
    總共:2次DMA + 0次CPU拷貝 + 2次上下文切換
    
  • 實際程式碼對比:
    // 傳統方式
    char buffer[4096];
    while ((n = read(fd, buffer, 4096)) > 0) {
        write(socket, buffer, n);  // 2次CPU拷貝
    }
    
    // 零拷貝
    sendfile(socket, fd, NULL, file_size);  // 0次CPU拷貝
    
  • 效能提升:
    • 傳統方式:100MB檔案,CPU使用率30%,吞吐量500MB/s
    • 零拷貝:100MB檔案,CPU使用率5%,吞吐量2GB/s

6. 記憶體映射 I/O vs 標準 I/O (Memory-Mapped I/O vs Standard I/O)

比較項目記憶體映射 I/O (mmap)標準 I/O (read/write)
運作方式將檔案映射到記憶體位址,像存取陣列使用系統呼叫讀寫檔案
白話比喻像把整本書攤開在桌上:隨便翻哪一頁像看書:從第一頁依序看
存取方式記憶體指標存取系統呼叫(read/write)
效能特性隨機存取快,大檔案優勢明顯順序存取快,小檔案開銷小
適用場景大檔案隨機存取、資料庫、共享記憶體順序讀寫、小檔案、串流資料
優點隨機存取效率高,減少系統呼叫實作簡單,適合順序操作
缺點需要虛擬記憶體支援,小檔案開銷大隨機存取慢,系統呼叫開銷
實際範例資料庫索引(B-tree)、進程間共享記憶體日誌寫入、檔案複製

詳細說明:

  • mmap範例:隨機存取大檔案
    // 映射檔案到記憶體
    int fd = open("data.db", O_RDWR);
    char* addr = mmap(NULL, file_size, PROT_READ|PROT_WRITE,
                      MAP_SHARED, fd, 0);
    
    // 像存取陣列一樣存取檔案
    addr[1000] = 'A';      // 直接修改offset 1000
    addr[999999] = 'B';    // 跳到offset 999999,無需seek
    
    munmap(addr, file_size);
    
  • 標準I/O範例:順序讀取
    FILE* fp = fopen("data.txt", "r");
    char buffer[4096];
    while (fread(buffer, 1, 4096, fp) > 0) {
        process(buffer);
    }
    fclose(fp);
    
  • 效能對比(100MB檔案,隨機存取10000次):
    • mmap:約100ms(頁面錯誤後幾乎零開銷)
    • read/write + lseek:約5000ms(每次都要系統呼叫)
  • 共享記憶體應用:多程序通訊
    // 程序A
    void* shared = mmap(NULL, SIZE, PROT_READ|PROT_WRITE,
                        MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    fork();  // 子程序繼承映射
    
    // 父子程序共享這塊記憶體,無需pipe或socket
    
  • 注意事項:
    • mmap檔案修改不會立即寫入磁碟,需要msync()強制同步
    • 映射大檔案可能耗盡虛擬記憶體位址空間(32位元系統)
    • 適合大檔案(>幾MB),小檔案反而比read/write慢

記憶體管理

5. 分頁 vs 分段 (Paging vs Segmentation)

比較項目分頁 (Paging)分段 (Segmentation)
運作方式將記憶體分成固定大小的頁(如4KB)依邏輯單元分成不同大小的段
白話比喻像停車格:每個格子一樣大,不管車型像衣櫃分區:上衣區、褲子區、大小不同
記憶體單位固定大小(4KB、2MB等)可變大小(依據程式邏輯)
碎片問題內部碎片(頁內浪費)外部碎片(段間浪費)
適用場景現代作業系統(Windows、Linux)早期系統、或需要邏輯分離的場景
優點管理簡單,無外部碎片符合程式邏輯結構,保護容易
缺點有內部碎片,查表開銷有外部碎片,需要壓縮整理
實際範例程式佔用100頁(400KB)Code段50KB、Data段30KB、Stack段20KB

詳細說明:

  • 分頁範例:一個程式需要17KB記憶體,在4KB分頁系統中會分配5頁(20KB),浪費3KB。
  • 分段範例:程式的程式碼、資料、堆疊分別放在不同的段,每段有自己的起始位址和長度。
  • 混合使用:現代x86-64系統同時支援分頁和分段,但主要使用分頁。

6. 寫回 vs 寫透 (Write-back vs Write-through)

比較項目寫回 (Write-back)寫透 (Write-through)
運作方式先寫快取,稍後批次寫回記憶體同時寫入快取和記憶體
白話比喻像筆記本:先記在本子上,有空再整理到電腦像雙寫:同時寫筆記本和打電腦
寫入速度快(只寫快取)慢(等記憶體寫完)
資料一致性可能不一致一定一致
適用場景一般應用程式、資料庫快取關鍵系統、需要即時持久化
優點效能最佳,減少記憶體存取資料安全,不會遺失
缺點斷電可能遺失資料效能較差
實際範例CPU L1 Cache銀行交易系統

詳細說明:

  • 寫回範例:你在Word編輯文件,修改先存在記憶體,過一段時間或關閉時才存到硬碟。
  • 寫透範例:每次輸入都立即存檔,確保不會遺失任何內容,但存檔頻繁會變慢。
  • 混合策略:資料庫的Write-Ahead Log(WAL)先寫日誌(寫透),資料頁面用寫回。

7. 靜態分配 vs 動態分配 (Static vs Dynamic Allocation)

比較項目靜態分配動態分配
運作方式編譯時決定記憶體大小和位置執行時根據需要分配記憶體
白話比喻像固定座位:買票時就決定坐哪像自由座:上車後找空位坐
分配時機編譯期間執行期間
彈性無彈性,大小固定彈性高,依需求調整
適用場景全域變數、陣列大小確定時鏈結串列、動態陣列、物件建立
優點速度快,無overhead,可預測彈性使用記憶體,適應不同需求
缺點浪費記憶體,無法調整大小有分配/釋放開銷,可能記憶體洩漏
實際範例int arr[100];int* arr = malloc(n * sizeof(int));

詳細說明:

  • 靜態範例:宣告 char buffer[1024]; 直接在stack上配置1024 bytes,編譯時就決定了。
  • 動態範例std::vector 初始可能只配置8個元素空間,使用時自動擴充到16、32、64...
  • 記憶體區域
    • 靜態:放在 Stack(區域變數)或 Data Segment(全域變數)
    • 動態:放在 Heap

排程策略

8. 搶佔式 vs 非搶佔式 (Preemptive vs Non-preemptive)

比較項目搶佔式 (Preemptive)非搶佔式 (Non-preemptive)
運作方式可以強制中斷正在執行的任務等任務自願放棄CPU
白話比喻像急診室:重症病人可以插隊像銀行排隊:必須等前面的人辦完
任務切換時間到就強制切換只能等任務完成或主動讓出
回應時間快,高優先權任務可立即執行慢,可能等很久
適用場景現代多工系統、即時系統簡單系統、批次處理
優點回應快,公平,適合互動式應用實作簡單,無切換開銷
缺點有切換開銷,實作複雜一個任務可能霸佔CPU
實際範例Linux、Windows的程序排程早期MS-DOS、簡單嵌入式系統

詳細說明:

  • 搶佔式範例:你在看影片時下載檔案,作業系統每10毫秒切換一次,兩個程式都能執行。
  • 非搶佔式範例:舊系統執行一個程式,必須等它執行完或主動sleep才能執行下一個。
  • 即時系統:飛機控制系統用搶佔式,確保緊急任務(如引擎故障)能立即處理。

9. FCFS vs SJF vs RR (First-Come First-Served vs Shortest Job First vs Round Robin)

比較項目FCFSSJFRound Robin
運作方式依到達順序執行先執行最短的工作輪流執行,每次固定時間片
白話比喻排隊:先到先服務快速通關:短工作優先輪流玩遊戲:每人玩5分鐘
平均等待時間可能很長最短中等
公平性公平(但可能飢餓)不公平(長工作可能等很久)最公平
適用場景批次系統、簡單任務已知工作時間的系統多工互動式系統(Linux、Windows)
優點實作簡單最佳化平均等待時間公平,回應時間可預測
缺點長工作會阻塞後面所有工作長工作可能餓死有切換開銷
實際範例印表機佇列作業批次處理CPU時間分配

詳細說明:

  • FCFS範例:3個工作:A(24秒)、B(3秒)、C(3秒),B和C必須等A完成,平均等待時間=(0+24+27)/3=17秒
  • SJF範例:同樣3個工作,執行順序變成B(3秒)、C(3秒)、A(24秒),平均等待時間=(0+3+6)/3=3秒
  • RR範例:時間片4秒,執行順序:A→B→C→A→A→A→A→A→A,每個工作輪流執行

10. 時間分享 vs 空間分享 (Time-sharing vs Space-sharing)

比較項目時間分享空間分享
運作方式資源輪流給不同使用者資源分割給不同使用者
白話比喻像共用一台車:輪流開像停車場:每人有固定車位
資源使用同一資源,不同時間使用不同部分同時使用
隔離性時間隔離空間隔離
適用場景CPU、網路頻寬記憶體、硬碟空間
優點資源利用率高效能穩定,無競爭
缺點需要切換機制可能浪費未使用的空間
實際範例多個程序共用一顆CPU每個程序有獨立的記憶體空間

詳細說明:

  • 時間分享範例:一顆4核CPU同時運行100個程序,每個程序輪流使用CPU。
  • 空間分享範例:8GB記憶體分給4個程式,每個程式固定使用2GB。
  • 混合使用:現代系統CPU用時間分享,記憶體用空間分享。

並行控制

11. 鎖 vs 無鎖 (Lock-based vs Lock-free)

比較項目鎖 (Lock-based)無鎖 (Lock-free)
運作方式使用互斥鎖保護共享資源使用原子操作(CAS)避免鎖
白話比喻像廁所門鎖:進去就上鎖像搶座位:看到空位就快速坐下
阻塞情況會阻塞其他執行緒不會阻塞,失敗就重試
死鎖風險可能死鎖無死鎖
適用場景一般應用、資料庫高效能系統、即時系統
優點實作簡單,容易理解效能好,無死鎖
缺點可能死鎖、效能瓶頸實作複雜,難以除錯
實際範例pthread_mutex_lock()Java的 AtomicInteger.compareAndSet()

詳細說明:

  • 鎖範例:銀行帳戶轉帳時,先鎖定兩個帳戶,完成轉帳後解鎖。
    mutex.lock();
    balance += amount;
    mutex.unlock();
    
  • 無鎖範例:多個執行緒更新計數器,使用CAS操作。
    do {
        old_value = counter;
        new_value = old_value + 1;
    } while (!compare_and_swap(&counter, old_value, new_value));
    
  • 效能比較:無競爭時鎖快;高競爭時無鎖快。

12. 悲觀鎖 vs 樂觀鎖 (Pessimistic vs Optimistic Locking)

比較項目悲觀鎖樂觀鎖
運作方式假設會衝突,先鎖住再操作假設不會衝突,衝突時才重試
白話比喻像保險箱:先鎖起來,確保沒人動像購物車:放進去,結帳時才檢查還有沒有貨
鎖定時機讀取時就鎖定更新時才檢查
衝突處理預防衝突偵測衝突後重試
適用場景寫多讀少、衝突頻繁讀多寫少、衝突少
優點確保不會衝突效能好,無需等待
缺點效能差,可能造成等待衝突多時需要重試
實際範例SELECT ... FOR UPDATE資料庫版本號機制

詳細說明:

  • 悲觀鎖範例:電影訂票系統,選座位時立即鎖定,避免同時被兩人選到。
    BEGIN TRANSACTION;
    SELECT * FROM seats WHERE id = 10 FOR UPDATE;
    UPDATE seats SET booked = true WHERE id = 10;
    COMMIT;
    
  • 樂觀鎖範例:Wiki編輯,編輯時不鎖定,提交時檢查版本號是否變更。
    UPDATE articles 
    SET content = '新內容', version = version + 1
    WHERE id = 100 AND version = 5;
    -- 如果version已經變更,UPDATE會失敗
    
  • 選擇原則:衝突率低選樂觀鎖,衝突率高選悲觀鎖。

13. 粗粒度鎖 vs 細粒度鎖 (Coarse-grained vs Fine-grained Locking)

比較項目粗粒度鎖細粒度鎖
運作方式鎖住大範圍(整個資料庫/表)鎖住小範圍(單一記錄)
白話比喻像整棟樓的大門鎖:進樓就鎖門像每個房間的鎖:只鎖使用的房間
並發程度
實作複雜度簡單複雜
適用場景低並發、簡單應用高並發、大型系統
優點實作簡單,死鎖機率低並發高,效能好
缺點並發差,效能瓶頸實作複雜,可能死鎖
實際範例鎖整個資料表鎖單一資料列

詳細說明:

  • 粗粒度鎖範例:整個購物網站共用一個庫存鎖,任何人修改任何商品庫存都要等待。
    with global_lock:
        update_inventory(product_id, quantity)
    
  • 細粒度鎖範例:每個商品有自己的鎖,修改A商品不影響B商品。
    with product_locks[product_id]:
        update_inventory(product_id, quantity)
    
  • 死鎖風險:細粒度鎖如果同時鎖定多個資源需注意順序,避免死鎖。

資料結構選擇

14. 陣列 vs 鏈結串列 (Array vs Linked List)

比較項目陣列 (Array)鏈結串列 (Linked List)
運作方式連續記憶體空間儲存元素節點透過指標連接
白話比喻像公寓:房間連續排列像尋寶遊戲:每個線索指向下一個
記憶體配置連續分散
隨機存取O(1)O(n)
插入/刪除O(n)O(1)
適用場景需要快速查詢、大小固定頻繁增刪、大小不定
優點存取快、cache友善插入刪除快、動態大小
缺點插入刪除慢、大小固定存取慢、需要額外指標空間
實際範例int arr[100]struct Node { int data; Node* next; }

詳細說明:

  • 陣列範例:學生成績表,可以直接查詢第50個學生 grades[49],但插入新學生需要移動後面所有元素。
  • 鏈結串列範例:播放清單,可以輕鬆插入新歌曲,但要找第50首歌需要從頭走訪。
  • 效能對比
    • 陣列存取:arr[1000] 一次記憶體存取
    • 鏈結串列存取:需要走訪1000次指標
  • 記憶體使用:鏈結串列每個節點需要額外8 bytes(64位元)儲存指標

15. 堆疊 vs 佇列 (Stack vs Queue)

比較項目堆疊 (Stack)佇列 (Queue)
運作方式LIFO(後進先出)FIFO(先進先出)
白話比喻像盤子堆疊:最後放的最先拿像排隊:先到的先服務
操作push(放)、pop(取)enqueue(放)、dequeue(取)
適用場景函式呼叫、括號匹配、回溯演算法任務排程、廣度優先搜尋、緩衝區
優點簡單、適合遞迴公平、順序處理
缺點不適合需要順序處理的場景不適合需要回溯的場景
實際範例瀏覽器上一頁功能印表機列印佇列

詳細說明:

  • 堆疊範例:函式呼叫 main() → funcA() → funcB(),funcB執行完回到funcA,funcA執行完回到main。
    void funcA() {
        int x = 10;  // 壓入stack
        funcB();
    }  // x彈出stack
    
  • 佇列範例:訊息系統,使用者依序發送訊息1、2、3,伺服器依序處理1、2、3。
    queue.put("訊息1")
    queue.put("訊息2")
    msg = queue.get()  # 取得"訊息1"
    
  • 變體
    • 雙端佇列(Deque):兩端都可以插入和刪除
    • 優先佇列(Priority Queue):依優先權而非順序取出

16. Hash Table vs Tree (雜湊表 vs 樹)

比較項目Hash TableTree (如BST、B-tree)
運作方式用hash函數計算位置直接存取有序結構,用比較找到位置
白話比喻像字典:知道單字直接翻到該頁像圖書館分類:一層層找下去
查詢時間O(1) 平均O(log n)
範圍查詢不支援支援
排序無序有序
適用場景快速查詢、資料無序範圍查詢、需要排序
優點查詢最快支援範圍查詢、有序
缺點可能碰撞、無序查詢較慢、實作複雜
實際範例Python的dict、資料庫索引MySQL的B+tree索引

詳細說明:

  • Hash Table範例:查詢學生成績,用學號hash後直接找到。
    grades = {"A001": 85, "A002": 92}
    score = grades["A001"]  # O(1)
    
  • Tree範例:查詢薪水在50K-80K的員工,可以用樹快速範圍查詢。
    SELECT * FROM employees WHERE salary BETWEEN 50000 AND 80000;
    -- 使用B-tree索引
    
  • 碰撞處理:Hash Table碰撞時用鏈結串列(Chaining)或開放定址法(Open Addressing)。
  • 實務應用:資料庫同時使用Hash Index(點查詢)和B-tree Index(範圍查詢)。

快取策略

17. LRU vs LFU vs FIFO (替換演算法)

比較項目LRULFUFIFO
運作方式移除最近最少使用的移除最不常使用的移除最早進來的
白話比喻像整理書桌:丟掉很久沒用的像整理衣櫃:丟掉最少穿的像堆疊雜誌:丟掉最舊的
考量因素最近使用時間使用頻率進入時間
適用場景一般應用、網頁快取熱門資料重要的場景簡單系統
優點符合時間局部性保留熱門資料實作最簡單
缺點實作複雜新資料不易進入效能差
實際範例Redis、作業系統分頁CDN快取早期快取系統

詳細說明:

  • LRU範例:瀏覽器快取,最近看過的網頁保留,很久沒看的清除。
    快取容量3,存取順序:A B C A D
    - 初始:[]
    - A:[A]
    - B:[A, B]
    - C:[A, B, C]
    - A:[B, C, A](A移到最前)
    - D:[C, A, D](移除B)
    
  • LFU範例:影片推薦系統,記錄觀看次數,保留熱門影片。
    存取次數:A(5次) B(2次) C(8次) D(1次)
    快取滿時,移除D(最少被存取)
    
  • FIFO範例:簡單的緩衝區,先進先出。
    快取容量3,存取順序:A B C D
    - D進入時,移除A(最早的)
    - 結果:[B, C, D]
    

18. 直接映射 vs 全相聯 vs 組相聯 (Cache Mapping)

比較項目直接映射全相聯組相聯
運作方式每個區塊只能放一個固定位置可放任何位置分成多組,組內可任意放
白話比喻像固定車位:你的車只能停A區像自由停車:任何空位都能停像分區停車:A區內任何位置都可以
查找速度最快(直接計算)最慢(全部檢查)中等
命中率最低最高中等
適用場景簡單快取小容量快取CPU快取(最常用)
優點硬體簡單、快速彈性最大、命中率高折衷效能和成本
缺點衝突多硬體複雜、查找慢折衷方案
實際範例簡單微控制器TLB(Translation Lookaside Buffer)CPU L1/L2/L3 Cache

詳細說明:

  • 直接映射範例:記憶體位址0x1000只能映射到快取位置0,位址0x2000也映射到位置0,會產生衝突。
    快取8個位置(0-7)
    位址0x08 → 位置0
    位址0x10 → 位置0(衝突!)
    
  • 全相聯範例:任何記憶體位址都能放入任何快取位置,需要比較所有tag。
    位址0x1000可以放在位置0-7的任何一個
    查找時需要檢查全部8個位置
    
  • 組相聯範例:8-way組相聯,快取分成多組,每組8個位置。
    64個快取位置,分成8組
    位址0x1000 → 映射到組0,可放組0的任何8個位置
    查找時只需檢查組0的8個位置
    

網路與通訊

19. Push vs Pull (推送 vs 拉取)

比較項目Push(推送)Pull(拉取)
運作方式伺服器主動推送資料給客戶端客戶端主動向伺服器請求資料
白話比喻像新聞通知:有新聞主動推送給你像查郵件:你自己去查看有沒有新信
資料流向Server → ClientClient ← Server
即時性高(立即通知)低(需要定期查詢)
適用場景即時通訊、股票報價、社群通知電子郵件、RSS訂閱、定期同步
優點即時、不需輪詢客戶端可控制頻率
缺點需要保持連接、伺服器負擔大有延遲、可能錯過更新
實際範例WebSocket、FirebaseHTTP polling、Email POP3

詳細說明:

  • Push範例:Line訊息,朋友傳訊息時伺服器立即推送到你的手機。
    // WebSocket Push
    socket.on('message', (data) => {
        displayMessage(data); // 收到訊息立即顯示
    });
    
  • Pull範例:Email客戶端每15分鐘自動檢查一次新郵件。
    while True:
        emails = fetch_new_emails()  # 主動拉取
        time.sleep(900)  # 等15分鐘
    
  • 混合模式
    • Long Polling:Pull但保持連接直到有新資料
    • Server-Sent Events(SSE):單向Push

20. TCP vs UDP

比較項目TCPUDP
運作方式可靠、有序、連接導向快速、無連接、不保證送達
白話比喻像掛號信:確保收到、有順序像廣播:快速發送、不管有沒有收到
連接需要三次握手建立連接無需建立連接
可靠性保證送達、有順序不保證送達、可能亂序
適用場景網頁、檔案傳輸、Email線上遊戲、視訊通話、DNS
優點可靠、有序、流量控制快速、低延遲、開銷小
缺點慢、開銷大不可靠、需要應用層處理
實際範例HTTP/HTTPS、SSH、FTP線上遊戲、Zoom、DNS查詢

詳細說明:

  • TCP範例:下載檔案,必須確保每個byte都正確且依序到達。
    三次握手:
    1. Client → Server: SYN
    2. Server → Client: SYN-ACK
    3. Client → Server: ACK
    然後才能傳輸資料
    
  • UDP範例:視訊通話,掉幾個封包無所謂,重要的是即時性。
    sock.sendto(video_frame, (ip, port))  # 直接發送
    # 不等待確認,不重傳遺失的封包
    
  • 效能對比
    • TCP:100ms延遲(含握手、確認)
    • UDP:10ms延遲(直接發送)
  • 實務應用
    • HTTP/3使用QUIC(基於UDP但加入可靠性)
    • 遊戲混用:重要資料用TCP,位置更新用UDP

21. 短連接 vs 長連接 (Short-lived vs Persistent Connection)

比較項目短連接長連接
運作方式每次請求建立連接,完成後關閉建立一次連接,重複使用
白話比喻像計程車:每次叫新車像包車:司機一直等你
連接次數多(每次請求)少(只建立一次)
伺服器負擔建立連接的開銷大維持連接的資源佔用
適用場景低頻請求、簡單服務高頻請求、即時通訊
優點實作簡單、無需維護連接減少建立連接開銷、效能好
缺點每次建立連接有開銷佔用伺服器資源、需要心跳機制
實際範例HTTP/1.0WebSocket、資料庫連接池

詳細說明:

  • 短連接範例:每次瀏覽網頁都建立新連接。
    1. 建立TCP連接(三次握手)
    2. 發送HTTP請求
    3. 接收HTTP回應
    4. 關閉TCP連接(四次揮手)
    
  • 長連接範例:聊天應用,建立一次WebSocket連接後持續使用。
    const ws = new WebSocket('wss://chat.example.com');
    ws.send('Hello');  // 使用已建立的連接
    ws.send('World');  // 重複使用同一連接
    
  • HTTP演進
    • HTTP/1.0:短連接
    • HTTP/1.1:引入 Connection: keep-alive 支援長連接
    • HTTP/2:多路複用,一個連接處理多個請求
  • 心跳機制:長連接需要定期發送心跳包,確保連接存活。
    while True:
        send_heartbeat()
        time.sleep(30)
    

儲存策略

22. 順序讀寫 vs 隨機讀寫 (Sequential vs Random Access)

比較項目順序讀寫隨機讀寫
運作方式連續存取資料跳躍式存取資料
白話比喻像看書:從第一頁依序看到最後像查字典:直接翻到需要的頁
存取方式連續位址任意位址
效能差異HDD快、SSD差異小HDD慢、SSD快
適用場景日誌寫入、影片播放、備份資料庫索引、作業系統分頁
優點效能最佳(尤其HDD)彈性高、符合應用需求
缺點不彈性HDD效能差
實際範例影片檔案讀取資料庫B-tree查詢

詳細說明:

  • 順序讀寫範例:寫日誌檔案,每次追加到檔案尾端。
    with open('log.txt', 'a') as f:
        f.write('新的日誌\n')  # 順序寫入
    
  • 隨機讀寫範例:資料庫更新,可能要存取不同位置的資料。
    UPDATE users SET name = 'Alice' WHERE id = 1000;
    UPDATE users SET name = 'Bob' WHERE id = 50;
    -- 存取位置可能相距很遠
    
  • 效能差異(HDD)
    • 順序讀取:100-200 MB/s
    • 隨機讀取:0.5-2 MB/s(慢100倍!)
  • SSD優勢
    • 順序讀取:500-3500 MB/s
    • 隨機讀取:300-3000 MB/s(差異小很多)
  • 優化策略:資料庫使用寫前日誌(WAL),隨機寫轉換為順序寫。

23. 集中式 vs 分散式 (Centralized vs Distributed)

比較項目集中式分散式
運作方式單一節點處理所有請求多個節點協同處理
白話比喻像總公司:所有決策一個地方做像連鎖店:各分店獨立運作
單點故障有(節點故障全停)無(部分節點故障仍可運作)
複雜度簡單複雜(需要協調機制)
適用場景小型應用、單一地區大型應用、全球服務
優點實作簡單、一致性容易保證高可用、可擴展、容錯
缺點單點故障、擴展性差複雜、一致性難保證
實際範例傳統資料庫(單機)Google搜尋、Facebook

詳細說明:

  • 集中式範例:小型電商網站,單一伺服器處理所有訂單。
    [所有使用者] → [單一伺服器] → [單一資料庫]
    伺服器故障 = 整個網站停擺
    
  • 分散式範例:YouTube影片存儲,分散在全球數千台伺服器。
    [美國使用者] → [美國伺服器]
    [台灣使用者] → [台灣伺服器]
    任一伺服器故障不影響其他地區
    
  • CAP定理:分散式系統無法同時滿足一致性、可用性、分區容錯性。
  • 分散式挑戰
    • 資料同步:如何保持各節點資料一致
    • 時鐘同步:不同伺服器時間可能不一致
    • 網路分區:節點間無法通訊時如何處理

24. 複製 vs 分片 (Replication vs Sharding)

比較項目複製 (Replication)分片 (Sharding)
運作方式相同資料存多份到不同節點資料切分到不同節點
白話比喻像備份:每台電腦都有完整資料像圖書館分館:每館只有部分書
資料分佈每個節點都有全部資料每個節點只有部分資料
目的提高可用性和讀取效能提高容量和寫入效能
適用場景讀多寫少、需要高可用性資料量大、需要水平擴展
優點容錯好、讀取快容量無限、寫入分散
缺點寫入需要同步、儲存成本高跨分片查詢慢、複雜度高
實際範例MySQL主從複製、Redis SentinelMongoDB分片、分散式資料庫

詳細說明:

  • 複製範例:電商網站有3個資料庫副本。
    Master DB(主):處理寫入
    Slave DB 1(從):處理讀取
    Slave DB 2(從):處理讀取
    → 讀取效能提升3倍,任一故障不影響服務
    
  • 分片範例:社群網站依使用者ID分片。
    Shard 1:使用者 ID 0-999999
    Shard 2:使用者 ID 1000000-1999999
    Shard 3:使用者 ID 2000000-2999999
    → 每個分片只處理部分資料,容量可無限擴展
    
  • 混合使用:每個分片內部做複製。
    Shard 1 Master + 2 Slaves
    Shard 2 Master + 2 Slaves
    → 既能擴容又能容錯
    
  • 分片鍵選擇
    • 好的分片鍵:使用者ID(均勻分佈)
    • 壞的分片鍵:註冊日期(新使用者集中在一個分片)

一致性模型

25. 強一致性 vs 最終一致性 (Strong vs Eventual Consistency)

比較項目強一致性最終一致性
運作方式寫入後立即所有節點看到相同資料寫入後過一段時間才一致
白話比喻像廣播:所有人同時聽到消息像傳話遊戲:消息逐漸傳開
延遲高(需等待所有節點確認)低(不等待)
可用性較低(節點故障可能無法寫入)高(總是可以寫入)
適用場景金融交易、庫存系統社群媒體、快取、DNS
優點資料一定正確效能好、高可用
缺點效能差、可用性低短期內可能不一致
實際範例銀行轉帳Facebook按讚數

詳細說明:

  • 強一致性範例:銀行轉帳,A轉1000元給B,必須確保兩邊同時生效。
    1. A帳戶 -1000(所有副本都確認)
    2. B帳戶 +1000(所有副本都確認)
    3. 交易完成
    如果任一步驟失敗,整個交易回滾
    
  • 最終一致性範例:Facebook貼文按讚。
    時間 0秒:Alice按讚,美國伺服器記錄
    時間 1秒:按讚數顯示+1(在美國)
    時間 5秒:資料同步到亞洲伺服器
    時間 5秒:按讚數顯示+1(在台灣)
    → 短期內不同地區看到不同數字,但最終會一致
    
  • 一致性級別(由強到弱):
    1. 線性一致性(Linearizability):最強
    2. 順序一致性(Sequential Consistency)
    3. 因果一致性(Causal Consistency)
    4. 最終一致性(Eventual Consistency):最弱

26. CP vs AP (CAP定理)

比較項目CP(一致性+分區容錯)AP(可用性+分區容錯)
運作方式網路分區時犧牲可用性保證一致性網路分區時犧牲一致性保證可用性
白話比喻像嚴格的考試:寧可不考也不給錯答案像開卷考試:先給答案,對錯之後再說
網路分區時拒絕服務或返回錯誤繼續服務但可能不一致
適用場景金融系統、庫存管理、選舉DNS、快取、社群媒體
優點資料絕對正確服務永遠可用
缺點可能暫時無法使用可能讀到舊資料
實際範例銀行系統、訂票系統Amazon購物車、Twitter

詳細說明:

  • CAP定理:一致性(Consistency)、可用性(Availability)、分區容錯性(Partition Tolerance)三者只能取其二。
  • CP範例:訂票系統,網路分區時寧可停止售票,也不能超賣。
    情境:兩個資料中心失去連接
    CP做法:停止售票,等網路恢復
    → 確保不會把同一個座位賣給兩個人
    
  • AP範例:購物車,網路分區時繼續加商品,稍後合併。
    情境:使用者在美國加商品A,網路分區
    AP做法:先加入本地購物車
    → 稍後網路恢復,與其他資料中心的購物車合併
    可能出現:短期內不同地區看到不同購物車內容
    
  • 實務選擇
    • 金融:選CP(寧可暫停服務,不能出錯)
    • 社群:選AP(暫時不一致沒關係,服務可用更重要)

執行模式

27. 單執行緒 vs 多執行緒 vs 多程序 (Single-threaded vs Multi-threaded vs Multi-process)

比較項目單執行緒多執行緒多程序
運作方式一次只做一件事多個執行緒共享記憶體多個程序獨立記憶體
白話比喻像一人廚房:一次煮一道菜像團隊廚房:共用鍋碗瓢盆像多間廚房:各自獨立
記憶體共享全部共享同一程序記憶體完全獨立
切換開銷
適用場景簡單任務、I/O密集(Node.js)CPU密集、需要共享資料需要隔離、安全性高
優點簡單、無同步問題效能好、共享資料容易隔離好、穩定
缺點無法利用多核需要同步、可能死鎖通訊慢、記憶體佔用大
實際範例JavaScript(瀏覽器)Java應用、科學計算Chrome瀏覽器分頁、Nginx

詳細說明:

  • 單執行緒範例:Node.js使用事件迴圈處理多個請求。
    // 雖然只有一個執行緒,但可以處理多個請求
    server.on('request', (req, res) => {
        // 非阻塞I/O,不會卡住其他請求
        fs.readFile('file.txt', (err, data) => {
            res.end(data);
        });
    });
    
  • 多執行緒範例:影片處理軟體,每個執行緒處理一段影片。
    import threading
    
    def process_chunk(start, end):
        # 處理影片的一部分
        pass
    
    threads = []
    for i in range(4):  # 4個執行緒
        t = threading.Thread(target=process_chunk, args=(i*100, (i+1)*100))
        threads.append(t)
        t.start()
    
  • 多程序範例:Chrome每個分頁一個程序,一個分頁崩潰不影響其他。
    from multiprocessing import Process
    
    def worker(data):
        # 完全獨立的處理
        pass
    
    processes = []
    for i in range(4):
        p = Process(target=worker, args=(data[i],))
        processes.append(p)
        p.start()
    
  • 效能對比
    • 單執行緒:1核心100%,其他核心閒置
    • 多執行緒:4核心各100%(4倍效能)
    • 多程序:4核心各100%,但記憶體佔用是多執行緒的4倍

28. 事件驅動 vs 多執行緒 (Event-driven vs Multi-threaded)

比較項目事件驅動多執行緒
運作方式單執行緒+事件迴圈處理多個連接每個連接一個執行緒
白話比喻像櫃台人員:一個人服務多個客戶像私人助理:每個客戶一個助理
並發方式協作式多工(cooperative)搶佔式多工(preemptive)
資源佔用低(單執行緒)高(每個執行緒需要stack)
適用場景I/O密集(網頁伺服器、聊天)CPU密集(影片編碼)
優點低開銷、高並發連接數實作簡單、符合直覺
缺點不適合CPU密集執行緒多時開銷大
實際範例Node.js、NginxApache(傳統模式)

詳細說明:

  • 事件驅動範例:Node.js處理10000個同時連接。
    // 單執行緒處理多個連接
    const server = http.createServer();
    server.on('request', async (req, res) => {
        const data = await db.query();  // 非阻塞
        res.end(data);
    });
    // 10000個連接只需要一個執行緒
    
  • 多執行緒範例:Apache為每個連接建立執行緒。
    連接1 → 執行緒1
    連接2 → 執行緒2
    連接3 → 執行緒3
    ...
    → 10000個連接需要10000個執行緒(記憶體爆炸)
    
  • C10K問題:如何讓一台伺服器處理10000個同時連接。
    • 傳統多執行緒:失敗(記憶體不足)
    • 事件驅動:成功(低記憶體佔用)
  • 混合模式
    • Node.js:主執行緒事件驅動 + Worker執行緒處理CPU密集
    • Nginx:事件驅動處理連接 + Worker程序平行處理

29. 同步執行 vs 平行執行 vs 並發執行 (Synchronous vs Parallel vs Concurrent)

比較項目同步執行平行執行並發執行
運作方式依序執行,一次一個真正同時執行(多核)快速切換,看似同時
白話比喻一人排隊辦事:辦完一件再辦下一件多個櫃台同時辦事一人快速處理多件事
硬體需求單核即可需要多核心單核即可
真正同時否(輪流)
適用場景簡單任務CPU密集、科學計算I/O密集、多任務
優點簡單、可預測最快(利用硬體)高效使用單核
缺點需要多核、同步複雜不能加速CPU密集
實際範例簡單腳本影片渲染、機器學習訓練作業系統多工

詳細說明:

  • 同步執行範例:煮飯流程。
    煮飯()    # 30分鐘
    炒菜()    # 20分鐘
    煮湯()    # 15分鐘
    總時間:65分鐘
    
  • 平行執行範例:三個人同時煮。
    # 3個CPU核心
    Thread1: 煮飯()  # 30分鐘
    Thread2: 炒菜()  # 20分鐘
    Thread3: 煮湯()  # 15分鐘
    總時間:30分鐘(最長的任務)
    
  • 並發執行範例:一個人快速切換。
    # 單核心,快速切換
    0-10分鐘:煮飯
    10-15分鐘:炒菜
    15-20分鐘:煮湯
    20-25分鐘:煮飯
    ...(不斷切換)
    總時間:接近65分鐘(因為有切換開銷)
    
  • Python範例
    # 同步
    result1 = task1()
    result2 = task2()
    
    # 並發(I/O)
    import asyncio
    result1, result2 = await asyncio.gather(task1(), task2())
    
    # 平行(CPU)
    from multiprocessing import Pool
    pool = Pool(4)
    results = pool.map(task, data)
    

設計模式

30. 單體 vs 微服務 (Monolithic vs Microservices)

比較項目單體 (Monolithic)微服務 (Microservices)
運作方式所有功能在一個應用程式功能拆分成獨立服務
白話比喻像百貨公司:所有部門在一棟樓像商店街:每個店面獨立營運
部署單位整個應用一起部署每個服務獨立部署
技術棧統一可以不同
適用場景小型專案、快速開發大型專案、需要彈性擴展
優點開發簡單、部署容易獨立開發、獨立擴展、容錯
缺點難以擴展、一個bug影響全部複雜度高、需要服務治理
實際範例傳統電商網站Netflix、Uber

詳細說明:

  • 單體範例:傳統電商系統。
    單一應用程式包含:
    - 使用者管理
    - 商品管理
    - 訂單處理
    - 付款處理
    - 物流追蹤
    → 改一個功能要重新部署整個應用
    
  • 微服務範例:Netflix架構。
    獨立服務:
    - User Service(使用者服務)
    - Video Service(影片服務)
    - Recommendation Service(推薦服務)
    - Billing Service(計費服務)
    → 每個服務可以獨立開發、部署、擴展
    
  • 演進過程
    1. 小型新創:單體(快速開發)
    2. 業務成長:單體開始變慢、難維護
    3. 拆分服務:逐步轉為微服務
  • 挑戰
    • 服務間通訊:需要API Gateway
    • 資料一致性:分散式交易
    • 服務發現:如何找到其他服務
    • 監控除錯:需要分散式追蹤

31. 拉模型 vs 推模型 (Pull vs Push Model - 資料流)

比較項目拉模型 (Pull)推模型 (Push)
運作方式消費者主動拉取資料生產者主動推送資料
白話比喻像去餐廳點餐:你決定吃什麼像外送訂閱:固定送來你家
控制權消費者控制生產者控制
背壓處理天然支援(拉取速度自己控制)需要額外機制
適用場景Kafka消費者、批次處理WebSocket、即時通知
優點消費者可控制速率、避免過載即時性好、低延遲
缺點可能有延遲容易壓垮消費者
實際範例Kafka Consumer拉取訊息Firebase即時資料庫推送

詳細說明:

  • 拉模型範例:Kafka消費者。
    # 消費者主動拉取
    while True:
        messages = consumer.poll(timeout=1.0)
        for message in messages:
            process(message)
        # 處理完一批再拉取下一批,速度自己控制
    
  • 推模型範例:WebSocket推送。
    // 伺服器主動推送
    socket.on('connect', () => {
        socket.emit('newMessage', message);  // 有訊息就推送
    });
    // 消費者被動接收,無法控制速度
    
  • 背壓問題:推模型可能壓垮慢速消費者。
    生產者:每秒產生10000條訊息
    消費者:每秒只能處理1000條
    → 推模型:消費者記憶體爆炸
    → 拉模型:消費者慢慢拉,不會過載
    
  • 混合模式
    • RabbitMQ:支援推和拉兩種模式
    • gRPC Streaming:可以雙向推送

選擇決策樹

選擇技術時的考量順序:

1. 業務需求
   ├─ 一致性要求高? → 強一致性、CP
   └─ 可用性要求高? → 最終一致性、AP

2. 資料特性
   ├─ 資料量大? → 分片
   ├─ 讀多寫少? → 複製 + 快取
   └─ 寫多讀少? → 寫優化的資料結構

3. 效能需求
   ├─ 低延遲? → 快取、異步
   ├─ 高吞吐? → 平行處理、批次
   └─ 即時性? → Push、WebSocket

4. 系統規模
   ├─ 小型? → 單體、集中式
   ├─ 中型? → 垂直擴展、複製
   └─ 大型? → 微服務、分散式

5. 團隊能力
   ├─ 經驗少? → 選擇簡單方案
   └─ 經驗多? → 可選複雜但效能好的方案

實務建議

1. 不要過度設計

  • 從簡單開始,需要時再優化
  • 單體 → 垂直擴展 → 水平擴展 → 微服務

2. 測量再優化

  • 先測量瓶頸在哪
  • 不要憑感覺優化

3. 權衡取捨

  • 沒有完美方案,只有適合的方案
  • 考慮維護成本、開發時間、效能

4. 關注變化

  • 技術持續演進
  • 保持學習,適時調整

5. 文件化決策

  • 記錄為什麼選擇這個方案
  • 未來回顧時有依據

總結對照表

分類機制對比核心差異選擇關鍵
I/O中斷 vs 輪詢主動通知 vs 被動檢查事件頻率
I/O同步 vs 異步等待 vs 回調並發需求
I/O阻塞 vs 非阻塞等結果 vs 立即返回多工需求
I/ODMA vs PIO硬體搬移 vs CPU搬移資料量
記憶體分頁 vs 分段固定 vs 可變管理複雜度
記憶體寫回 vs 寫透延遲寫 vs 立即寫資料安全性
記憶體靜態 vs 動態編譯期 vs 執行期彈性需求
排程搶佔 vs 非搶佔強制切換 vs 自願讓出即時性
排程FCFS vs SJF vs RR順序 vs 最短 vs 輪流公平性
並行鎖 vs 無鎖互斥 vs 原子操作競爭程度
並行悲觀 vs 樂觀預防 vs 偵測衝突率
並行粗粒度 vs 細粒度大鎖 vs 小鎖並發需求
資料結構陣列 vs 鏈結串列連續 vs 分散存取模式
資料結構堆疊 vs 佇列LIFO vs FIFO處理順序
資料結構Hash vs Tree無序快速 vs 有序範圍查詢類型
快取LRU vs LFU vs FIFO時間 vs 頻率 vs 順序存取模式
快取直接映射 vs 全相聯 vs 組相聯固定 vs 任意 vs 分組硬體成本
網路Push vs Pull推送 vs 拉取即時性
網路TCP vs UDP可靠 vs 快速資料重要性
網路短連接 vs 長連接用完丟 vs 重複用請求頻率
儲存順序 vs 隨機連續 vs 跳躍資料存取模式
儲存集中式 vs 分散式單點 vs 多點規模
儲存複製 vs 分片備份 vs 分割目的
一致性強一致 vs 最終一致立即 vs 延遲業務需求
一致性CP vs AP一致性 vs 可用性CAP取捨
執行單執行緒 vs 多執行緒 vs 多程序一個 vs 共享 vs 隔離隔離需求
執行事件驅動 vs 多執行緒單執行緒多工 vs 多執行緒I/O vs CPU
執行同步 vs 平行 vs 並發依序 vs 同時 vs 輪流硬體資源
設計單體 vs 微服務一體 vs 拆分系統規模
資料流Pull vs Push拉取 vs 推送控制權

最後提醒: 選擇技術方案沒有絕對的對錯,關鍵是:

  1. 理解每種方案的優缺點
  2. 評估你的實際需求和限制
  3. 做出合理的權衡
  4. 持續監控和優化

希望這份整理能幫助你在系統設計時做出更好的決策! 🚀