0

Greenplum Database - Bài học 5: Interconnect Layer: Giao thức mạng nội bộ (UDP/TCP) giúp các Segment giao tiếp tốc độ cao

Ở các bài học trước, chúng ta đã biết dữ liệu của một bảng lớn được băm nhỏ và rải đều ra hàng chục đến hàng trăm Segments độc lập (Shared-Nothing). Mỗi Segment chỉ nhìn thấy phần dữ liệu nằm trên ổ cứng của riêng mình.

Vậy điều gì sẽ xảy ra khi bạn chạy một câu lệnh JOIN hai bảng với nhau (ví dụ: SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id), trong khi dòng đơn hàng của khách hàng A nằm ở Segment 1, nhưng thông tin hồ sơ của khách hàng A lại nằm ở Segment 50?

Để thực hiện phép ghép nối này, các Segments buộc phải trao đổi hàng triệu bản ghi qua lại với nhau ngay trong lúc câu truy vấn đang chạy. Tầng hạ tầng và giao thức mạng đảm nhận nhiệm vụ vận chuyển dữ liệu siêu tốc giữa các tiến trình PostgreSQL trong cụm được gọi là Greenplum Interconnect.

1. Interconnect Layer là gì?

Interconnect không đơn thuần là sợi dây cáp mạng hay chiếc Switch vật lý nối các máy chủ lại với nhau. Trong kiến trúc Greenplum, Interconnect bao gồm cả hai lớp:

  1. Lớp phần cứng vật lý (Physical Network): Hệ thống card mạng tốc độ cao (10GbE, 25GbE, 40GbE hoặc 100GbE) và thiết bị chuyển mạch (Switch) riêng biệt nối giữa các Master Host và Segment Hosts.

  2. Lớp giao thức phần mềm (Software Protocol): Cách thức mà các tiến trình QE (Query Executor) trên các Segments đóng gói, truyền tải các dòng dữ liệu (Tuples) và kiểm soát luồng qua mạng.

[ Master Node (QD) ]
         │ (Phát lệnh Query Plan)
         ▼
┌─────────────────────────────────────────────────────────┐
│             GREENPLUM INTERCONNECT LAYER                │
│      (Mạng nội bộ tốc độ cao 10GbE / 25GbE / 100GbE)     │
└────────┬───────────────────┬───────────────────┬────────┘
         │                   │                   │
         ▼                   ▼                   ▼
   ┌───────────┐       ┌───────────┐       ┌───────────┐
   │ Segment 0 │◄─────►│ Segment 1 │◄─────►│ Segment N │
   │  (QE 0)   │       │  (QE 1)   │       │  (QE N)   │
   └───────────┘       └───────────┘       └───────────┘
     (Trao đổi Tuples trực tiếp ngang hàng Peer-to-Peer)

Ba nhiệm vụ chính của Interconnect:

  • Phát lệnh và thu thập trạng thái (Control Traffic): Master gửi kế hoạch thực thi (Query Plan) xuống các Segments và nhận kết quả báo cáo tiến độ.

  • Di chuyển dữ liệu ngang hàng (Data Motion Traffic — Nặng nhất): Các Segments bắn trực tiếp các dòng dữ liệu (Tuples) sang cho nhau khi thực hiện JOIN, GROUP BY, DISTINCT hoặc WINDOW FUNCTIONS.

  • Đồng bộ dữ liệu dự phòng (Mirror Replication Traffic): Truyền luồng nhật ký WAL từ Primary Segment sang Mirror Segment tương ứng.

2. Khi nào các Segments phải nói chuyện với nhau? (Motion Operators)

Trong một câu truy vấn phân tán, mỗi khi dữ liệu cần di chuyển từ Node này sang Node khác qua Interconnect, bộ lập lịch của Greenplum sẽ chèn vào kế hoạch thực thi một toán tử gọi là Motion Node. Có 3 kiểu dịch chuyển dữ liệu kinh điển trên Interconnect:

Loại Motion Cơ chế di chuyển trên Interconnect Khi nào xuất hiện? Mức độ tiêu tốn băng thông
1. Gather Motion (N→1N \to 1) Tất cả các Segments gửi kết quả cuối cùng tập trung về một nơi duy nhất là Master Node. Bước cuối cùng của hầu hết các câu lệnh SELECT để trả kết quả về cho Client. Thấp (nếu đã GROUP BY hoặc LIMIT), Rất cao (nếu kéo dữ liệu thô lớn).
2. Redistribute Motion (N→NN \to N) Mỗi Segment băm (Hash) lại dữ liệu theo cột cần JOIN hoặc GROUP BY rồi bắn chéo các dòng đó sang đúng các Segments đích. Khi JOIN 2 bảng lớn không cùng khóa phân phối (Distribution Key), hoặc GROUP BY trên cột không phải Distribution Key. Cao (Toàn bộ các Segments gửi và nhận dữ liệu chéo nhau cùng lúc - All-to-All).
3. Broadcast Motion (1/N→All1/N \to \text{All}) Mỗi Segment copy toàn bộ phần dữ liệu mình đang có và nhân bản gửi cho TẤT CẢ các Segments còn lại trong cụm. Khi JOIN một bảng rất lớn (Fact Table) với một bảng danh mục nhỏ (Dimension Table). Rất nguy hiểm nếu bảng bị Broadcast có dung lượng lớn (nhân lên NN lần qua mạng).

3. Tại sao Greenplum không dùng TCP truyền thống mà tự tạo ra UDPIFC?

Trong lập trình mạng thông thường, khi cần truyền dữ liệu tin cậy (không mất gói tin, đúng thứ tự), chúng ta luôn chọn giao thức TCP. Ngược lại, UDP tuy nhanh nhưng "vô trách nhiệm" (bắn gói tin đi mà không cần biết đích có nhận được hay không).

Vậy tại sao các kỹ sư thiết kế Greenplum lại chọn UDP làm giao thức mặc định cho Interconnect? Hãy làm một phép toán về sự bùng nổ kết nối (The N2N^2 Connection Problem):

Bài toán bùng nổ kết nối TCP trên cụm lớn

Giả sử bạn có một cụm Greenplum gồm 200 Segments.

  • Khi chạy 1 câu truy vấn có phép Redistribute Motion (mọi Segment đều phải gửi dữ liệu cho 199 Segments còn lại):

    Số lượng kết nối mạng hai chiều cần thiết lập cho riêng 1 bước đó là:

    200×199=39.800 keˆˊt noˆˊi200 \times 199 = 39.800 \text{ kết nối}

  • Một câu truy vấn phức tạp thường có từ 4 đến 5 bước Motion (Slices) chạy song song:

    39.800×5≈200.000 keˆˊt noˆˊi39.800 \times 5 \approx 200.000 \text{ kết nối}

  • Nếu có 20 người dùng cùng chạy báo cáo một lúc:

    200.000×20=4.000.000 keˆˊt noˆˊi TCP đoˆˋng thời!200.000 \times 20 = 4.000.000 \text{ kết nối TCP đồng thời!}

Với TCP (giao thức hướng kết nối - Connection-oriented): Mỗi kết nối đều đòi hỏi quá trình bắt tay 3 bước (3-way handshake), cấp phát một vùng bộ nhớ đệm (Socket Buffer) riêng trong Kernel Linux và tiêu tốn File Descriptor. Ở quy mô hàng triệu kết nối đan chéo nhau, nhân hệ điều hành Linux sẽ bị cạn kiệt bộ nhớ Kernel (Out of Socket Memory) và nghẽn CPU chỉ để quản lý trạng thái kết nối trước khi kịp truyền bất kỳ dòng dữ liệu nào!

Giải pháp của Greenplum: Giao thức UDPIFC

Để phá bỏ giới hạn của TCP nhưng vẫn đảm bảo không bao giờ mất dù chỉ 1 byte dữ liệu, Greenplum đã chế tạo ra giao thức UDPIFC (UDP with Interconnect Flow Control):

┌────────────────────────────────────────────────────────┐
│           Tầng Ứng Dụng (Greenplum Process)            │
│  ┌──────────────────────────────────────────────────┐  │
│  │ Cơ chế tự kiểm soát của UDPIFC:                  │  │
│  │ • Đánh số thứ tự gói tin (Sequence Number)       │  │
│  │ • Xác nhận đã nhận (ACK) & Tự động gửi lại (Retry)│  │
│  │ • Kiểm soát luồng chống tràn bộ đệm (Flow Control)│  │
│  └────────────────────────┬─────────────────────────┘  │
├───────────────────────────┼────────────────────────────┤
│      Tầng Hệ Điều Hành    ▼                            │
│              [ Giao thức UDP (Connectionless) ]        │
│    (Chỉ cần 1 Socket duy nhất để nói chuyện với N Node)│
└────────────────────────────────────────────────────────┘

  1. Dùng UDP ở tầng dưới (Connectionless): Mỗi tiến trình QE trên Segment chỉ cần mở 1 UDP Socket duy nhất để vừa gửi vừa nhận dữ liệu với tất cả 199 Segments còn lại, thay vì phải mở 199 kết nối riêng biệt như TCP. Chi phí bộ nhớ trong Kernel giảm đi hàng trăm lần!

  2. Đưa tính năng bảo đảm tin cậy của TCP lên tầng Application:

    • Mỗi gói tin dữ liệu gửi qua UDPIFC đều được Greenplum gắn số thứ tự (Sequence Number) và mã kiểm tra lỗi.

    • Bên nhận phải gửi phản hồi xác nhận (ACK). Nếu quá thời gian chờ (Timeout) mà chưa thấy ACK, bên gửi sẽ tự động truyền lại gói tin đó.

    • Cơ chế Kiểm soát luồng (Flow Control / Capacity-based): Nếu một Segment đích đang bận tính toán chưa kịp đọc dữ liệu từ bộ đệm mạng, UDPIFC sẽ báo cho các Segment gửi tạm dừng bắn dữ liệu tới Node đó, tránh hiện tượng rớt gói tin hàng loạt (Packet Drop) trên card mạng.

4. So sánh các loại cấu hình Interconnect (gp_interconnect_type)

Trong Greenplum, bạn có thể kiểm soát giao thức mạng nội bộ thông qua tham số cấu hình gp_interconnect_type:

Giá trị tham số Cơ chế hoạt động Ưu điểm Nhược điểm & Giới hạn
udpifc (Mặc định) Sử dụng UDP kết hợp cơ chế kiểm soát luồng và sửa lỗi ở tầng ứng dụng của Greenplum. Khả năng mở rộng cực cao (hàng trăm đến hàng ngàn Segments), tiết kiệm RAM hệ điều hành, hiệu năng cao nhất. Đòi hỏi cấu hình bộ đệm UDP của Linux Kernel (sysctl.conf) chuẩn xác.
tcp Sử dụng giao thức TCP/IP chuẩn của hệ điều hành. Không cần tinh chỉnh nhiều về UDP buffer, hoạt động ổn định trên các môi trường mạng ảo hóa chất lượng kém hay rớt gói. Bị giới hạn quy mô (không nên dùng cho cụm quá 64–100 Segments hoặc tải truy vấn đồng thời cao vì tốn RAM Kernel).
proxy (Greenplum 6/7) Các tiến trình QE trên cùng một máy chủ vật lý gom dữ liệu qua một tiến trình Proxy trung gian trên máy đó rồi mới gửi đi qua TCP/UDP. Giảm mạnh số lượng kết nối vật lý giữa các máy chủ khi chạy nhiều Segments trên một Host. Thêm một bước chuyển tiếp nội bộ (IPC) trên máy chủ.

Để kiểm tra xem cụm Greenplum hiện tại đang dùng giao thức gì, bạn có thể chạy lệnh sau trên Master:

SQL

SHOW gp_interconnect_type;
-- Kết quả mặc định thường là: udpifc

5. Thiết kế Mạng Vật lý & Tinh chỉnh Linux Kernel cho Interconnect (Production Best Practices)

Trong thực tế vận hành, rất nhiều trường hợp câu lệnh SQL chạy chậm không phải do CPU yếu hay ổ cứng chậm, mà do nghẽn mạng Interconnect (Network Bottleneck) hoặc rớt gói tin UDP (UDP Packet Drop) khiến các Segments phải gửi đi gửi lại gói tin hàng ngàn lần.

Dưới đây là 3 chuẩn mực thiết kế hạ tầng mạng cho Greenplum:

5.1. Tách biệt mạng Client (External) và mạng Interconnect (Internal)

  • Mạng External (Public/LAN): Chỉ gắn vào Master Node để ứng dụng Backend và người dùng kết nối vào.

  • Mạng Internal (Interconnect): Gắn giữa Master và toàn bộ các Segment Hosts trên một dải mạng riêng biệt (Dedicated VLAN/Switch), tốc độ tối thiểu 10GbE (khuyến nghị 25GbE – 100GbE nếu dữ liệu hàng chục TB). Tuyệt đối không cho lưu lượng mạng văn phòng hay các dịch vụ khác chạy chung vào dải mạng này.

5.2. Bật Jumbo Frames (MTU = 9000)

Mặc định, một gói tin Ethernet chuẩn chỉ chở được tối đa 1500 bytes dữ liệu (MTU = 1500). Khi các Segments cần bắn hàng Gigabyte dữ liệu qua lại, việc cắt nhỏ dữ liệu thành hàng triệu gói tin 1500 bytes làm CPU tốn rất nhiều chu kỳ xử lý ngắt mạng (Network Interrupts).

  • Trên toàn bộ các card mạng Interconnect và trên Switch nội bộ, hãy cấu hình Jumbo Frames (MTU = 9000).

  • Việc tăng kích thước mỗi gói tin lên gấp 6 lần giúp giảm mạnh tải CPU và tăng thông lượng truyền tải dữ liệu giữa các Segments lên thêm 15% – 25%.

5.3. Mở rộng bộ đệm UDP trên Linux (sysctl.conf)

Vì UDPIFC bắn dữ liệu với tốc độ cực nhanh, bộ đệm mạng mặc định nhỏ bé của Linux sẽ bị tràn ngay lập tức, gây rớt gói tin. Trên tất cả các máy chủ trong cụm, bắt buộc phải mở rộng bộ đệm nhận/gửi UDP trong file /etc/sysctl.conf:

Ini, TOML

# Tăng kích thước bộ đệm nhận (Receive) và gửi (Send) tối đa của Socket lên 16MB - 32MB
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 4194304
net.core.wmem_default = 4194304

# Tăng độ dài hàng đợi gói tin của card mạng trước khi Kernel kịp xử lý
net.core.netdev_max_backlog = 250000

Mẹo kiểm tra lỗi mạng nhanh: Bạn có thể dùng công cụ đi kèm của Greenplum là gpcheckperf -f hostfile_all -r N -d /tmp để đo tốc độ truyền tải mạng thực tế giữa tất cả các máy chủ trong cụm trước khi đưa hệ thống vào sử dụng.

Tóm tắt Bài học 5

  • Interconnect Layer là hệ thống mạng nội bộ (cả phần cứng lẫn giao thức phần mềm) giúp Master điều phối và giúp các Segments trao đổi dữ liệu trực tiếp ngang hàng (Peer-to-Peer) trong quá trình thực thi truy vấn.

  • Dữ liệu di chuyển qua Interconnect thông qua 3 toán tử Motion: Gather Motion (gom về Master), Redistribute Motion (băm và chia lại dữ liệu giữa các Segments), và Broadcast Motion (nhân bản bảng nhỏ ra toàn cụm).

  • Greenplum sử dụng giao thức mặc định là UDPIFC (UDP kết hợp kiểm soát luồng và sửa lỗi ở tầng Application) để giải quyết bài toán bùng nổ hàng triệu kết nối (N2N^2) của TCP trên các cụm quy mô lớn.

  • Để Interconnect đạt tốc độ tối đa trên Production: cần dùng mạng riêng tốc độ cao (10GbE+), bật Jumbo Frames (MTU 9000) và tăng dung lượng UDP Buffer trong Linux Kernel.

Vậy là chúng ta đã nắm vững toàn bộ lý thuyết cốt lõi về kiến trúc của Greenplum qua 5 bài đầu tiên! Ở bài học tiếp theo (Bài học 6), chúng ta sẽ bắt tay vào thực hành: Triển khai cụm Greenplum nhanh với Docker Compose: Dựng môi trường Lab đa Node trong 10 phút để bạn có ngay một cụm Greenplum thật chạy trên máy cá nhân và trực tiếp gõ lệnh trải nghiệm.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí