Greenplum Database - Bài học 4: Segment Instances (Primary & Mirror): Nơi dữ liệu thực sự sống và cơ chế tự phục hồi
Ở Bài học 3, chúng ta đã khám phá "bộ não" Master Node (Coordinator) — nơi nắm giữ bản đồ toàn cục nhưng không lưu trữ bất kỳ một dòng dữ liệu người dùng nào. Vậy hàng chục Terabyte hay hàng tỷ bản ghi thực sự nằm ở đâu? Câu trả lời chính là ở tầng Segment Instances.
Nếu Master là vị tướng chỉ huy, thì các Segments chính là đội quân công nhân tinh nhuệ trực tiếp giữ kho lương thực (dữ liệu) và gánh vác 99% sức nặng tính toán (CPU, RAM, Disk I/O). Trong bài học này, chúng ta sẽ giải phẫu kiến trúc bên trong một Segment Host, tìm hiểu cách bố trí các cặp Primary – Mirror để chống mất dữ liệu, và xem cơ chế tự phục hồi (Self-Healing) của Greenplum diễn ra như thế nào khi một ổ cứng hoặc cả một máy chủ vật lý bốc khói.
1. Phân biệt rạch ròi: Segment Host vs Segment Instance
Người mới tiếp cận Greenplum thường nhầm lẫn giữa hai khái niệm Segment Host và Segment Instance (gọi tắt là Segment). Hãy làm rõ ngay từ đầu:
-
Segment Host (Máy chủ vật lý / Máy ảo): Là một chiếc máy chủ chạy hệ điều hành Linux (ví dụ:
sdw1,sdw2...), có địa chỉ IP riêng, CPU nhiều nhân, dung lượng RAM lớn và hệ thống ổ cứng tốc độ cao. -
Segment Instance (Tiến trình cơ sở dữ liệu): Là một cơ sở dữ liệu PostgreSQL độc lập chạy bên trong Segment Host đó. Mỗi Segment Instance có:
-
Một thư mục lưu trữ dữ liệu riêng trên ổ cứng (
PGDATA, ví dụ:/data1/primary/gpseg0). -
Một cổng mạng lắng nghe riêng (
port, ví dụ:6000,6001...). -
Bộ nhớ đệm riêng (
shared_buffers) và tập hợp các tiến trình nền riêng (postmaster,bgwriter,walwriter...).
-
┌─────────────────────────────────────────────────────────────────────────┐
│ SEGMENT HOST 1 (Máy chủ vật lý: sdw1) │
│ 64 CPU Cores | 256GB RAM | 4x NVMe │
│ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ Primary Segment 0 (gpseg0) │ │ Primary Segment 1 (gpseg1) │ │
│ │ Port: 6000 │ │ Port: 6001 │ │
│ │ Data: /data1/primary/gpseg0 │ │ Data: /data2/primary/gpseg1 │ │
│ │ (Postgres Engine độc lập) │ │ (Postgres Engine độc lập) │ │
│ └───────────────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ Mirror Segment 2 (gpseg2) │ │ Mirror Segment 3 (gpseg3) │ │
│ │ Port: 7000 (Standby) │ │ Port: 7001 (Standby) │ │
│ │ Data: /data1/mirror/gpseg2 │ │ Data: /data2/mirror/gpseg3 │ │
│ └───────────────────────────────┘ └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Tại sao phải chạy nhiều Segment Instances trên 1 máy chủ vật lý?
Giả sử bạn có một máy chủ vật lý mạnh mẽ với 64 CPU Cores, 256GB RAM và 8 ổ cứng SSD NVMe.
-
Nếu bạn chỉ cài 1 Segment Instance duy nhất trên máy chủ này: Khi thực thi một câu truy vấn, một tiến trình thực thi đơn lẻ (
QE - Query Executor) của PostgreSQL chỉ tận dụng được tối đa 1 nhân CPU và một phần nhỏ băng thông của 1 ổ đĩa. 63 nhân CPU còn lại sẽ ngồi chơi! -
Ngược lại, nếu bạn chia máy chủ này thành 8 Primary Segment Instances (mỗi Segment gắn với 1 ổ NVMe): Khi câu lệnh SQL chạy xuống, cả 8 Segments trên cùng máy chủ này sẽ đồng loạt bung 8 luồng đọc từ 8 ổ đĩa khác nhau và sử dụng 8 nhân CPU cùng lúc.
-
Quy tắc thực tế (Best Practice): Thông thường, các kỹ sư sẽ cấu hình từ 4 đến 8 Primary Segments trên mỗi Segment Host (tùy thuộc vào số lượng CPU Cores và số lượng ổ đĩa/RAID Controller của máy chủ) để vắt kiệt 100% công suất phần cứng.
Lưu ý đặc biệt: Bạn không thể (hoặc bị khóa mặc định) dùng DBeaver hay
psqlkết nối trực tiếp vào cổng6000của một Segment để chạy câu lệnhSELECThayINSERT. Mọi lệnh bắt buộc phải đi qua cổng5432của Master Node để đảm bảo tính nhất quán toàn cục. (Chỉ trong trường hợp khẩn cấp khi bảo trì, DBA mới dùng chế độ đặc biệt gọi là Utility Mode để đăng nhập trực tiếp vào từng Segment).
2. Primary Segment và Mirror Segment: Lá chắn chống mất dữ liệu
Trong kiến trúc MPP Shared-Nothing, dữ liệu của một bảng được chia nhỏ (Sharding) ra tất cả các Segments. Giả sử bạn có 100 Primary Segments, mỗi Segment giữ 1% tổng dữ liệu của công ty.
Câu hỏi đặt ra: Nếu 1 trong 100 Segment đó bị cháy ổ cứng và mất sạch 1% dữ liệu của nó, chuyện gì sẽ xảy ra? Toàn bộ các câu truy vấn SELECT SUM(...) hay JOIN trên bảng đó sẽ thất bại hoàn toàn vì dữ liệu bị khuyết 1 mảnh ghép! Trong một cụm có hàng chục máy chủ chạy hàng trăm ổ cứng liên tục 24/7, xác suất một ổ cứng bị hỏng mỗi tháng là điều chắc chắn xảy ra.
Để giải quyết bài toán sống còn này, Greenplum thiết kế cơ chế Mirroring (Nhân bản dự phòng ở cấp độ Segment):
| Loại Segment | Vai trò trong cụm | Trạng thái hoạt động | Mô tả chi tiết |
|---|---|---|---|
Primary Segment (role = 'p') |
Phiên bản chính. Trực tiếp nhận lệnh từ Master để đọc/ghi dữ liệu và tính toán câu truy vấn. | Active (Chủ động) | Gánh toàn bộ tải về CPU, RAM và I/O thường xuyên trong quá trình xử lý query. |
Mirror Segment (role = 'm') |
Bản sao dự phòng 1-1 của một Primary Segment cụ thể (cùng content_id). |
Passive (Thụ động) | Không tham gia trả lời câu lệnh SELECT. Chỉ âm thầm nhận luồng dữ liệu đồng bộ (WAL Replication) từ Primary tương ứng. |
Quy tắc vàng khi đặt Mirror:
Một Mirror Segment KHÔNG BAO GIỜ được phép nằm trên cùng một máy chủ vật lý (Segment Host) với Primary Segment mà nó bảo vệ!
Nếu đặt cả Primary seg0 và Mirror seg0 trên cùng máy chủ sdw1, thì khi máy chủ sdw1 bị cháy nguồn hoặc đứt cáp mạng, cả bản chính lẫn bản sao đều chết cùng lúc. Khi đó cơ chế dự phòng hoàn toàn vô nghĩa.
3. Hai chiến lược bố trí Mirror (Mirroring Topologies) trên cụm đa máy chủ
Khi thiết kế cụm Greenplum từ 3 hoặc 4 máy chủ Segment trở lên, có 2 cách bố trí các cặp Primary – Mirror phổ biến nhất:
3.1. Group Mirroring (Đặt Mirror sang máy kế tiếp)
Tất cả các Mirror của Máy 1 sẽ được đặt hết sang Máy 2; Mirror của Máy 2 đặt sang Máy 3;... và Mirror của Máy cuối cùng quay vòng đặt về Máy 1.
[ Host 1 (sdw1) ] [ Host 2 (sdw2) ] [ Host 3 (sdw3) ]
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Primary: P0 ├────────►│ Mirror: M0 │ │ Primary: P4 ├───┐
│ Primary: P1 ├────────►│ Mirror: M1 │ │ Primary: P5 ├───┼───┐
├───────────────┤ ├───────────────┤ ├───────────────┤ │ │
│ Mirror: M4 │◄────────┼─Primary: P2 ├────────►│ Mirror: M2 │ │ │
│ Mirror: M5 │◄───┐ │ Primary: P3 ├────────►│ Mirror: M3 │ │ │
└───────────────┘ │ └───────────────┘ └───────────────┘ │ │
▲ └──────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
-
Ưu điểm: Cấu hình đơn giản, dễ hiểu.
-
Nhược điểm lớn: Khi
Host 1bị sập hoàn toàn, cả 2 bản saoM0vàM1nằm trênHost 2sẽ đồng loạt thức dậy làm việc thay thế. Lúc này, một mìnhHost 2phải gánh 4 Primary Segments đang hoạt động (P2, P3, M0, M1) — tức là tải công việc trênHost 2bị tăng gấp đôi (200%), trong khiHost 3vẫn chỉ chạy 2 Segments bình thường. Do hiệu ứng "chiếc thùng gỗ", toàn bộ cụm sẽ bị chậm đi một nửa vì phải chờHost 2!
3.2. Spread Mirroring (Rải đều Mirror ra các máy khác nhau — Khuyên dùng cho Production)
Thay vì gom tất cả Mirror của Máy 1 bỏ sang Máy 2, Greenplum sẽ xé lẻ: Mirror của P0 bỏ sang Máy 2, Mirror của P1 bỏ sang Máy 3, Mirror của P2 bỏ sang Máy 4...
[ Host 1 (sdw1) ] [ Host 2 (sdw2) ] [ Host 3 (sdw3) ]
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Primary: P0 ├────────►│ Mirror: M0 │ │ Primary: P4 │
│ Primary: P1 ├─────────┼────────────────────────►│ Mirror: M1 │
├───────────────┤ ├───────────────┤ ├───────────────┤
│ Mirror: M2 │◄────────┼─Primary: P2 │ │ Primary: P5 │
│ Mirror: M5 │ │ Primary: P3 ├────────►│ Mirror: M3 │
└───────────────┘ │ Mirror: M4 │ └───────────────┘
└───────────────┘
-
Ưu điểm vượt trội: Khi
Host 1bị cháy (P0vàP1chết),M0trênHost 2thức dậy vàM1trênHost 3thức dậy. Lúc này, gánh nặng của máy bị chết được chia đều cho tất cả các máy còn sống trong cụm (mỗi máy chỉ phải gánh thêm 1 Segment thay vì ôm trọn toàn bộ). Hiệu năng toàn cụm gần như ít bị suy giảm nhất! -
Lưu ý: Để dùng Spread Mirroring, số lượng máy chủ Segment Host trong cụm phải lớn hơn số lượng Primary Segments trên mỗi Host.
4. Cơ chế Tự phục hồi (Fault Tolerance & Self-Healing) hoạt động ra sao?
Làm thế nào Greenplum phát hiện một Segment bị chết và tự động chuyển đổi (Failover) trong tích tắc mà ứng dụng đang chạy không bị gián đoạn?
Bước 1: Dò tìm sự cố (Fault Probing - Tiến trình ftsprobe)
Trên Master Node có một tiến trình ngầm cực kỳ quan trọng tên là FTS (Fault Tolerance Server - ftsprobe). Định kỳ mỗi vài chục giây, ftsprobe sẽ đi "điểm danh" sức khỏe toàn bộ các Segments trong cụm.
Bước 2: Kích hoạt Mirror (Automatic Failover)
Giả sử ổ cứng chứa Primary Segment 0 (P0) trên máy sdw1 bị hỏng vật lý:
-
P0ngừng phản hồi. Tiến trìnhftsprobetrên Master phát hiệnP0đã chết. -
Ngay lập tức, Master cập nhật bảng hệ thống
gp_segment_configuration:-
Đánh dấu
P0(trênsdw1) thànhstatus = 'd'(Down). -
Thăng cấp
Mirror Segment 0 (M0)(nằm trênsdw2) từ vai trò dự phòng (role = 'm') lên thành Primary mới (role = 'p'). -
Do lúc này
M0đang chạy một mình mà không còn bản sao bảo vệ nữa, trạng thái đồng bộ của nó chuyển sangmode = 'n'(Not in sync / Change Tracking).
-
-
Mọi câu truy vấn tiếp theo từ ứng dụng được Master tự động điều hướng sang
M0trên máysdw2. Hệ thống tiếp tục chạy bình thường!
TRƯỚC KHI SỰ CỐ (Bình thường):
[P0 trên sdw1: Role=p, Status=u, Mode=s] ──(WAL Sync)──► [M0 trên sdw2: Role=m, Status=u, Mode=s]
KHI P0 BỊ CHẾT (Automatic Failover):
[P0 trên sdw1: Role=m, Status=d, Mode=n] X [M0 trên sdw2: Role=p, Status=u, Mode=n]
(Đã chết - Ngừng hoạt động) (Lên làm Primary mới & Ghi nhật ký thay đổi)
Bước 3: Khôi phục và Cân bằng lại cụm (gprecoverseg)
Sau khi bộ phận hạ tầng thay ổ cứng mới cho máy sdw1 (hoặc khởi động lại máy chủ):
-
Quản trị viên chạy lệnh
gprecoverseg(khôi phục tại chỗ) hoặcgprecoverseg -F(khôi phục toàn phần). -
Nhờ tính năng Differential Recovery (trên Greenplum 6/7 dùng
pg_rewind), hệ thống không cần copy lại hàng trăm GB dữ liệu từ đầu, mà chỉ đồng bộ đúng phần dữ liệu vừa thay đổi trong khoảng thời gianP0bị chết từM0trả ngược vềP0. -
Khi cả hai đã đồng bộ 100% (
mode = 's'), lúc nàyM0trên máysdw2vẫn đang giữ chức Primary tạm thời (khiến máysdw2phải gánh nhiều việc hơn bình thường). -
Quản trị viên chạy lệnh cuối cùng:
gprecoverseg -r(Rebalance). Lệnh này sẽ trả lại ngai vàng Primary choP0trênsdw1và đưaM0trênsdw2về lại đúng vị trí Mirror ban đầu (role = preferred_role). Cụm máy chủ trở về trạng thái cân bằng hoàn hảo!
5. Khám phá thực tế: Cách kiểm tra sức khỏe Segment trên dòng lệnh
Khi vận hành thực tế, có 2 cách nhanh nhất để kiểm tra xem có Segment nào đang bị chết hoặc lệch vai trò (role != preferred_role) hay không:
Cách 1: Truy vấn SQL trực tiếp trên Master
SQL
-- Tìm tất cả các Segment đang bị chết (status = 'd')
-- hoặc đang không chạy đúng vai trò thiết kế ban đầu (role <> preferred_role)
-- hoặc đang mất đồng bộ (mode <> 's')
SELECT dbid, content, role, preferred_role, mode, status, hostname, port, datadir
FROM gp_segment_configuration
WHERE status <> 'u'
OR role <> preferred_role
OR mode <> 's'
ORDER BY content;
(Nếu câu lệnh này trả về 0 dòng, xin chúc mừng: Cụm Greenplum của bạn đang khỏe mạnh 100%!)
Cách 2: Sử dụng công cụ CLI gpstate
Trên terminal của Master Host, bạn có thể chạy lệnh:
-
gpstate -e: Kiểm tra nhanh các Segment đang có vấn đề (Down, lệch Role, đang Resync). -
gpstate -m: Xem danh sách chi tiết toàn bộ các Mirror Segments và trạng thái đồng bộ của chúng.
Tóm tắt Bài học 4
-
Segment Host là máy chủ vật lý, còn Segment Instance là tiến trình PostgreSQL độc lập chạy bên trong máy chủ đó. Một máy chủ vật lý thường chạy 4–8 Primary Segments để tận dụng tối đa CPU và băng thông ổ cứng.
-
Primary Segment (
p) trực tiếp xử lý truy vấn và lưu trữ dữ liệu; Mirror Segment (m) là bản sao dự phòng 1-1 nằm trên một máy chủ vật lý khác, được đồng bộ liên tục qua WAL Streaming Replication. -
Hai mô hình bố trí Mirror là Group Mirroring và Spread Mirroring (Spread Mirroring giúp chia đều tải cho toàn cụm khi có 1 máy chủ bị sập).
-
Tiến trình
ftsprobetrên Master tự động phát hiện Segment chết và chuyển đổi sang Mirror không gây gián đoạn. Công cụgprecoversegvàgprecoverseg -rgiúp khôi phục và cân bằng lại vai trò các Segments về trạng thái ban đầu.
Ở bài học tiếp theo (Bài học 5), chúng ta sẽ giải mã "hệ thần kinh" kết nối tất cả các Master và Segments lại với nhau: Interconnect Layer — tìm hiểu tại sao Greenplum lại tự chế tạo giao thức truyền tải qua UDP (UDPIFC) thay vì dùng TCP truyền thống, và cách mạng nội bộ ảnh hưởng trực tiếp đến tốc độ phép JOIN như thế nào.
All rights reserved