Kiểm tra Tài nguyên và Thoát Khỏi Chế độ An toàn trong Quá trình Khởi động NameNode HDFS

Tổng quan về quá trình khởi động NameNode

Quá trình khởi tạo NameNode trong Hadoop Distributed File System (HDFS) bao gồm nhiều giai đoạn quan trọng, từ việc tải siêu dữ liệu đến khởi động các dịch vụ RPC và HTTP. Một trong những phần cốt lõi của quá trình này là việc kiểm tra tài nguyên và quản lý chế độ an toàn (Safe Mode), đảm bảo tính toàn vẹn và ổn định của hệ thống trước khi sẵn sàng phục vụ các yêu cầu của client.

Luồng khởi động chính có thể được hình dung như sau:

  • Phương thức NameNode.main() là điểm vào chính.
  • Khởi tạo một thể hiện NameNode thông qua createNameNode().
  • Giai đoạn initialize() bắt đầu, bao gồm:
    • Khởi động máy chủ HTTP.
    • Tải siêu dữ liệu (metadata) của hệ thống tệp thông qua loadNamesystem().
    • Tạo và thiết lập máy chủ RPC.
    • Gọi startCommonServices() để khởi động các dịch vụ chung.
  • Bên trong startCommonServices(), một bước quan trọng là namesystem.startCommonServices(), nơi các kiểm tra tài nguyên và các dịch vụ nền tảng khác được kích hoạt.
    • Khởi tạo NameNodeResourceChecker để chuẩn bị các đường dẫn ổ đĩa cần kiểm tra.
    • Thực hiện checkAvailableResources() để kiểm tra không gian ổ đ đĩa.
    • Lấy thể hiện StartupProgress để theo dõi tiến độ khởi động NameNode.
    • Đặt tổng số khối (block) để xác định điều kiện thoát chế độ an toàn.
    • Kích hoạt BlockManager và các luồng nền liên quan đến quản lý bản sao khối.
  • Sau đó, máy chủ RPC được khởi động thông qua rpcServer.start().
  • Cuối cùng, join() để chờ NameNode hoàn tất công việc.

Khởi động các dịch vụ chung với startCommonServices

Phương thức startCommonServices của NameNode có trách nhiệm chính trong việc thiết lập các dịch vụ thiết yếu, bao gồm kiểm tra tài nguyên hệ thống, quyết định trạng thái chế độ an toàn và kích hoạt BlockManager, đồng thời khởi động máy chủ RPC.

// Cấu trúc đơn giản của startCommonServices
private void startCommonServices(Configuration cauHinh) throws IOException {
    // 1. Kiểm tra tài nguyên, xác định chế độ an toàn, và kích hoạt BlockManager
    heThongTen.khoiDongDichVuChung(cauHinh, nguCanhHA);
    
    dangKyNNSMXBean(); // Đăng ký MBean để theo dõi trạng thái NameNode
    
    // Khởi động HttpServer nếu vai trò không phải là NameNode chính
    if (vaiTro != NamenodeRole.NAMENODE) {
        khoiDongMayChuHttp(cauHinh);
        mayChuHttp.datDiaChiNameNode(layDiaChiNameNode());
        mayChuHttp.datFSImage(layFSImage());
    }
    
    // 2. Khởi động máy chủ RPC
    mayChuRpc.khoiDong();
    
    // Tải và khởi động các plugin dịch vụ
    for (ServicePlugin plugin : cacPlugin) {
        try {
            plugin.start(this);
        } catch (Throwable e) {
            LOG.warn("Không thể khởi động ServicePlugin " + plugin, e);
        }
    }
    LOG.info(layVaiTro() + " RPC đã khởi động tại: " + mayChuRpc.layDiaChiRpc());
}

Trong đó, heThongTen.khoiDongDichVuChung(cauHinh, nguCanhHA) là điểm then chốt để xử lý các vấn đề liên quan đến tài nguyên và chế độ an toàn.

Kiểm tra tài nguyên hệ thống bởi FSNamesystem

Phương thức startCommonServices của FSNamesystem đảm nhiệm việc khởi tạo trình kiểm tra tài nguyên, thực hiện các kiểm tra ban đầu và chuẩn bị cho việc quản lý khối.

// Cấu trúc đơn giản của FSNamesystem.startCommonServices
void khoiDongDichVuChung(Configuration cauHinh, HAContext nguCanhHA) throws IOException {
    this.dangKyMBean(); 
    ghiKhoa(); // Khóa ghi
    this.nguCanhHA = nguCanhHA;
    try {
        // NameNodeResourceChecker chịu trách nhiệm kiểm tra tài nguyên ổ đĩa.
        // Các thư mục siêu dữ liệu cần kiểm tra bao gồm: fsimage, editlog, 
        // và các thư mục của JournalNode trong chế độ HA.
        trinhKiemTraTaiNguyenNN = new NameNodeResourceChecker(cauHinh);
        
        // Thực hiện kiểm tra tài nguyên. Nếu không đủ, hệ thống sẽ vào chế độ an toàn.
        kiemTraTaiNguyenKhaDung();
        
        // Đảm bảo chế độ an toàn đã được thiết lập và hàng đợi sao chép chưa hoạt động.
        assert cheDoAnToan != null && !dangDienRaSaoChepKhoi();
        
        // Lấy StartupProgress để theo dõi tiến độ khởi động NameNode.
        StartupProgress tienDoKhoiDong = NameNode.layTienDoKhoiDong();
        
        // NameNode chuyển sang giai đoạn chế độ an toàn, chờ báo cáo khối.
        tienDoKhoiDong.batDauGiaiDoan(Phase.SAFEMODE);
        tienDoKhoiDong.datTong(Phase.SAFEMODE, STEP_AWAITING_REPORTED_BLOCKS, layTongSoKhoiHoanTat());
        
        // Đặt tổng số khối để xác định điều kiện thoát chế độ an toàn.
        datTongSoKhoi();
        
        // Kích hoạt BlockManager để xử lý bản sao khối.
        quanLyKhoi.kichHoat(cauHinh);
    } finally {
        moKhoaGhi(); // Mở khóa ghi
    }
    // ... các bước đăng ký MBean và khởi động khác ...
}

Lớp NameNodeResourceChecker: Trình kiểm tra tài nguyên ổ đĩa

NameNodeResourceChecker đóng vai trò quan trọng trong việc đảm bảo NameNode có đủ không gian ổ đĩa để hoạt động một cách an toàn. Các chức năng chính của lớp này bao gồm:

  1. Khai báo ngưỡng dung lượng đĩa: Thiết lập một ngưỡng dung lượng đĩa tối thiểu (ví dụ: 100MB) mà NameNode có thể chịu đựng trước khi chuyển sang chế độ an toàn. Giá trị này thường được định nghĩa bởi duReserved.
  2. Xác định các đường dẫn cần kiểm tra: Thu thập và đóng gói các đường dẫn thư mục liên quan đến siêu dữ liệu (ví dụ: fsimage, editlog) cần được giám sát.
  3. Thêm đường dẫn vào danh sách kiểm tra: Các đường dẫn này được thêm vào một tập hợp (thường là một Map có tên volumes). Sau đó, một luồng giám sát nền gọi là NameNodeResourceMonitor sẽ liên tục kiểm tra tài nguyên của các đường dẫn này bằng cách gọi phương thức hasAvailableDiskSpace().

Phương thức areResourcesAvailable là cốt lõi, nó duyệt qua tất cả các đường dẫn trong tập hợp volumes và kiểm tra xem mỗi đường dẫn có đủ không gian đĩa khả dụng hay không thông qua isResourceAvailable. Phương thức này tính toán xem liệu số lượng tài nguyên khả dụng có đáp ứng được yêu cầu tối thiểu để NameNode tiếp tục hoạt động hay không.

checkAvailableResources() được gọi một lần khi NameNode khởi tạo. Sau đó, luồng NameNodeResourceMonitor sẽ định kỳ (thường là mỗi giây) gọi lại phương thức này để giám sát liên tục, đảm bảo NameNode luôn có đủ tài nguyên hoạt động.

Quản lý Chế độ An toàn (Safe Mode)

Sau khi khởi động và kiểm tra tài nguyên ban đầu, NameNode sẽ chuyển vào chế độ an toàn. Đây là một trạng thái tạm thời, trong đó NameNode chờ đợi các DataNode báo cáo đầy đủ các khối dữ liệu mà chúng lưu trữ.

  • Đối tượng StartupProgress được sử dụng để theo dõi và báo cáo trạng thái khởi động của NameNode.
  • NameNode sẽ ở chế độ an toàn cho đến khi số lượng khối được báo cáo đạt đến một ngưỡng nhất định (ví dụ: 0.999f tổng số khối hoàn chỉnh).

getCompleteBlocksTotal()setBlockTotal()

Để xác định khi nào có thể thoát chế độ an toàn, NameNode cần biết tổng số khối hoàn chỉnh trong hệ thống. Phương thức getCompleteBlocksTotal() được sử dụng để tính toán con số này bằng cách lấy tổng số khối trừ đi các khối không đọc được.

Sau khi có tổng số khối, setBlockTotal() sẽ thiết lập giá trị này. Một biến quan trọng khác là blockSafe, theo dõi số lượng khối đã được DataNode báo cáo cho NameNode. Giá trị này tăng lên khi các DataNode báo cáo khối mới và giảm đi khi các khối bị xóa.

Kiểm tra Chế độ An toàn với checkMode()

Phương thức checkMode() chịu trách nhiệm quản lý trạng thái của chế độ an toàn. Nó thực hiện hai chức năng chính:

  1. Xác định điều kiện vào chế độ an toàn: Sử dụng phương thức needEnter() để kiểm tra xem có cần thiết phải đưa NameNode vào chế độ an toàn hay không, thường là do thiếu tài nguyên hoặc khi khởi động.
  2. Xác định điều kiện thoát chế độ an toàn: Nếu NameNode đang trong chế độ an toàn, nó sẽ kiểm tra xem các điều kiện thoát đã được đáp ứng chưa thông qua canLeave(). Một luồng nền khác, SafeModeMonitor, sẽ định kỳ (mỗi giây) kiểm tra điều kiện này. Khi NameNode vào chế độ an toàn, biến this.reached thường được đặt lại về 0.

Luồng Giám sát Chế độ An toàn: SafeModeMonitor

SafeModeMonitor là một luồng nền chạy liên tục trong NameNode khi nó đang ở chế độ an toàn. Nhiệm vụ chính của luồng này là định kỳ gọi phương thức canLeave() để kiểm tra xem liệu NameNode đã đáp ứng đủ các tiêu chí để thoát khỏi chế độ an toàn hay chưa. Các tiêu chí này thường bao gồm:

  • Phần trăm khối đã được báo cáo từ DataNode đạt ngưỡng tối thiểu (ví dụ: 99.9%).
  • Các điều kiện khác liên quan đến tình trạng siêu dữ liệu và sự ổn định của hệ thống.

Khi canLeave() trả về true, NameNode sẽ tự động thoát khỏi chế độ an toàn và sẵn sàng xử lý các yêu cầu ghi/đọc dữ liệu từ client.

Thẻ: hdfs NameNode SafeMode DistributedFileSystem ResourceManagement

Đăng vào ngày 15 tháng 7 lúc 13:08