Hướng dẫn HDFS: Archikiến trúc, Đọc & Viết Operasản xuất

⚡ Tóm tắt thông minh

HDFS là lớp lưu trữ phân tán của Hadoop, chia các tệp rất lớn thành các khối được sao chép trên các máy chủ thông thường để một NameNode duy nhất có thể xử lý tất cả. tracSiêu dữ liệu ks trong khi nhiều DataNode xử lý các yêu cầu đọc và ghi một cách đáng tin cậy.

  • 🔘 Archikiến trúc: NameNode lưu giữ hình ảnh không gian tên và nhật ký chỉnh sửa, trong khi DataNode lưu trữ các bản sao khối thực tế.
  • ☑️ Kích thước khối: Hadoop 1.x mặc định sử dụng khối 64 MB; Hadoop 2.x và 3.x mặc định sử dụng 128 MB.
  • Nhân rộng: Mặc định là ba bản sao cho mỗi khối, được phân bổ trên các giá đỡ để đảm bảo rằng lỗi phần cứng sẽ không bao giờ làm mất dữ liệu.
  • 🧪 Đọc đường dẫn: FSDataInputStream và DFSInputStream lấy vị trí khối từ NameNode, sau đó truyền trực tiếp các byte từ DataNodes.
  • 🛠️ Viết đường dẫn: DFSOutputStream xếp hàng các gói dữ liệu, DataStreamer xây dựng một đường dẫn DataNode, và Ack Queue bảo vệ chống mất gói dữ liệu.
  • 🧭 Tùy chọn truy cập: org.apache.hadoop.fs Java Cả API và shell hdfs dfs đều hỗ trợ các thao tác mở, đọc, ghi và đóng.

Hướng dẫn HDFS

HDFS là gì?

HDFS là một hệ thống tệp phân tán dùng để lưu trữ các tệp dữ liệu rất lớn, hoạt động trên các cụm phần cứng thông thường. Nó có khả năng chịu lỗi, mở rộng và cực kỳ dễ dàng để mở rộng. Hadoop được tích hợp sẵn HDFS (Hệ thống tệp phân tán Hadoop).

Khi dữ liệu vượt quá dung lượng lưu trữ trên một máy vật lý, việc chia dữ liệu đó thành một số máy riêng biệt là điều cần thiết. Một hệ thống tệp quản lý các hoạt động lưu trữ cụ thể trên mạng máy được gọi là hệ thống tệp phân tán. HDFS là một trong những phần mềm như vậy.

HDFS Archikiến trúc

Một cụm HDFS chủ yếu bao gồm: TênNode quản lý siêu dữ liệu hệ thống tệp và Mã dữ liệu Nơi lưu trữ dữ liệu thực tế.

  • TênNode: NameNode có thể được coi là trung tâm điều khiển của hệ thống. Nó duy trì cấu trúc cây thư mục và siêu dữ liệu cho tất cả các tệp và thư mục hiện có trong hệ thống. Hai tệp, 'namespace image' và 'edit log', được sử dụng để lưu trữ thông tin siêu dữ liệu. NameNode biết vị trí của tất cả các DataNode chứa các khối dữ liệu cho một tệp nhất định, tuy nhiên, nó không lưu trữ vị trí các khối một cách liên tục. Thông tin này được tái tạo lại từ các DataNode mỗi khi hệ thống khởi động.
  • Mã dữ liệu: DataNodes là các máy chủ phụ nằm trên mỗi máy trong cụm và cung cấp bộ nhớ lưu trữ thực tế. Chúng chịu trách nhiệm phục vụ các yêu cầu đọc và ghi từ máy khách.

Vì một NameNode đơn lẻ sẽ là điểm lỗi duy nhất, các cụm hiện tại vận hành một NameNode hoạt động song song với một NameNode dự phòng, chia sẻ nhật ký chỉnh sửa thông qua một nhóm các JournalNode, với cơ chế chuyển đổi dự phòng tự động giữa hai NameNode.

Các thao tác đọc và ghi trong HDFS hoạt động ở cấp độ khối. Các tệp dữ liệu trong HDFS được chia thành các khối có kích thước bằng khối dữ liệu, được lưu trữ dưới dạng các đơn vị độc lập. Kích thước khối mặc định là 64 MB trong Hadoop 1.x. Từ Hadoop 2.x trở đi, kích thước khối mặc định được thay đổi. dfs.blocksize là 128 MB.

HDFS hoạt động dựa trên khái niệm sao chép dữ liệu, trong đó nhiều bản sao của các khối dữ liệu được tạo ra và phân phối trên các nút trong toàn bộ cụm để đảm bảo tính khả dụng cao của dữ liệu trong trường hợp nút bị lỗi. Hệ số sao chép mặc định là ba (dfs.replication), và khi một DataNode ngừng gửi tín hiệu nhịp tim, NameNode sẽ tự động sao chép lại các khối dữ liệu của nó sang nơi khác.

Bạn có biết? Một tệp trong HDFS, nhỏ hơn một khối, không chiếm toàn bộ bộ nhớ của khối.

Đọc Operatrong HDFS

Yêu cầu đọc dữ liệu được xử lý bởi HDFS, NameNode và DataNodes. Chúng ta hãy gọi bên đọc là 'client'. Sơ đồ bên dưới mô tả hoạt động đọc tập tin trong Hadoop.

Luồng dữ liệu thao tác đọc HDFS giữa máy khách, NameNode và DataNodes.

  1. Một máy khách khởi tạo yêu cầu đọc bằng cách gọi phương thức 'open()' của đối tượng FileSystem; đây là một đối tượng thuộc loại DistributedFileSystem.
  2. Đối tượng này kết nối với NameNode bằng RPC và lấy thông tin siêu dữ liệu như vị trí của các khối trong tệp. Xin lưu ý rằng các địa chỉ này là của một vài khối đầu tiên của tệp.
  3. Để đáp lại yêu cầu siêu dữ liệu này, địa chỉ của các DataNode có bản sao của khối đó sẽ được trả về.
  4. Sau khi nhận được địa chỉ của các DataNode, một đối tượng thuộc loại FSDataInputStream sẽ được trả về cho máy khách. FSDataInputStream chứa DFSInputStream, đối tượng này đảm nhiệm việc tương tác với DataNode và NameNode. Ở bước 4 được hiển thị trong sơ đồ trên, máy khách gọi phương thức 'read()', phương thức này khiến DFSInputStream thiết lập kết nối với DataNode đầu tiên chứa khối dữ liệu đầu tiên của tệp.
  5. Dữ liệu được đọc dưới dạng luồng, trong đó máy khách gọi phương thức 'read()' lặp đi lặp lại. Quá trình đọc này tiếp tục cho đến khi đạt đến cuối khối lệnh.
  6. Khi kết thúc một khối, DFSInputStream sẽ đóng kết nối và chuyển sang tìm DataNode tiếp theo cho khối tiếp theo.
  7. Sau khi khách hàng đọc xong, nó sẽ gọi phương thức close().

Viết Operatrong HDFS

Trong phần này, chúng ta sẽ tìm hiểu cách dữ liệu được ghi vào HDFS thông qua các tập tin. Sơ đồ bên dưới minh họa điều này. tracnhững thứ viết đường dẫn.

Quy trình ghi dữ liệu vào HDFS với DataQueue, DataStreamer và Ack Queue

  1. Một máy khách khởi tạo thao tác ghi bằng cách gọi phương thức 'create()' của đối tượng DistributedFileSystem, phương thức này tạo ra một tệp mới – Bước số 1 trong sơ đồ trên.
  2. Đối tượng DistributedFileSystem kết nối với NameNode bằng lệnh gọi RPC và khởi tạo việc tạo tệp mới. Tuy nhiên, thao tác tạo tệp này không liên kết bất kỳ khối nào với tệp. Trách nhiệm của NameNode là xác minh rằng tệp (đang được tạo) không tồn tại và máy khách có quyền phù hợp để tạo tệp mới. Nếu tệp đã tồn tại hoặc máy khách không có đủ quyền để tạo tệp mới, thì một ngoại lệ IOException sẽ được ném về phía máy khách. Ngược lại, thao tác thành công và một bản ghi mới cho tệp được tạo bởi NameNode.
  3. Sau khi một bản ghi mới được tạo trong NameNode, một đối tượng thuộc loại FSDataOutputStream sẽ được trả về cho máy khách. Máy khách sử dụng đối tượng này để ghi dữ liệu vào HDFS. Phương thức ghi dữ liệu được gọi (bước 3 trong sơ đồ).
  4. FSDataOutputStream chứa một đối tượng DFSOutputStream chịu trách nhiệm giao tiếp với các DataNode và NameNode. Trong khi máy khách tiếp tục ghi dữ liệu, DFSOutputStream tiếp tục tạo các gói dữ liệu. Các gói này được đưa vào một hàng đợi có tên là DataQueue.
  5. Còn một thành phần nữa gọi là DataStreamer, thành phần này tiêu thụ DataQueue. DataStreamer cũng yêu cầu NameNode phân bổ các khối mới, từ đó chọn ra các DataNode mong muốn để sử dụng cho việc sao chép.
  6. Bây giờ, quá trình sao chép bắt đầu bằng cách tạo một đường dẫn sử dụng DataNodes. Trong trường hợp của chúng tôi, chúng tôi đã chọn mức độ sao chép là 3 và do đó có 3 DataNode trong quy trình.
  7. DataStreamer đổ các gói vào DataNode đầu tiên trong đường ống.
  8. Mỗi DataNode trong một pipeline sẽ lưu trữ gói dữ liệu nhận được và chuyển tiếp gói dữ liệu đó đến DataNode thứ hai trong pipeline.
  9. Một hàng đợi khác, 'Hàng đợi xác nhận', được DFSOutputStream duy trì để lưu trữ các gói tin đang chờ xác nhận từ các DataNode.
  10. Sau khi nhận được xác nhận cho một gói trong hàng đợi từ tất cả các DataNode trong đường ống, gói đó sẽ bị xóa khỏi 'Hàng đợi Ack'. Trong trường hợp có bất kỳ lỗi DataNode nào, các gói từ hàng đợi này sẽ được sử dụng để bắt đầu lại hoạt động.
  11. Sau khi máy khách hoàn tất việc ghi dữ liệu, nó sẽ gọi phương thức close() (Bước 9 trong sơ đồ). Lệnh gọi close() sẽ đẩy các gói dữ liệu còn lại vào đường dẫn xử lý, sau đó chờ xác nhận.
  12. Sau khi nhận được xác nhận cuối cùng, NameNode sẽ được liên hệ để thông báo rằng thao tác ghi tệp đã hoàn tất.

Truy cập HDFS bằng cách sử dụng Java API

Trong phần này, chúng ta sẽ cố gắng hiểu về Java giao diện được sử dụng để truy cập hệ thống tệp của Hadoop.

Để tương tác với hệ thống tập tin của Hadoop theo chương trình, Hadoop cung cấp nhiều Java Các lớp. Gói có tên org.apache.hadoop.fs chứa các lớp hữu ích trong việc thao tác với tệp trong hệ thống tệp của Hadoop. Các thao tác này bao gồm mở, đọc, ghi và đóng. API tệp của Hadoop mang tính tổng quát và có thể được mở rộng để tương tác với các hệ thống tệp khác ngoài HDFS.

Đọc tệp từ HDFS, theo chương trình

Đối tượng java.net.URL được sử dụng để đọc nội dung của một tập tin. Để bắt đầu, chúng ta cần thực hiện Java nhận diện hdfs của Hadoop URL kế hoạch. Điều này được thực hiện bằng cách gọi tập hợp.URLPhương thức StreamHandlerFactory trên URL đối tượng và truyền một thể hiện của FsUrlStreamHandlerFactory cho nó. Phương thức này chỉ cần được thực thi một lần cho mỗi JVM, do đó nó được đặt trong một khối tĩnh.

Một mã ví dụ là-

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

Đoạn mã này mở và đọc nội dung của một tập tin. Đường dẫn của tập tin này trên HDFS được truyền cho chương trình dưới dạng đối số dòng lệnh.

Truy cập HDFS bằng giao diện dòng lệnh

Đây là một trong những cách đơn giản nhất để tương tác với HDFS. Giao diện dòng lệnh hỗ trợ các thao tác hệ thống tệp như đọc tệp, tạo thư mục, di chuyển tệp, xóa dữ liệu và liệt kê thư mục.

Chúng ta có thể chạy '$HADOOP_HOME/bin/hdfs dfs -help' Để nhận được trợ giúp chi tiết về từng lệnh. Ở đây, 'dfs' là một lệnh shell của HDFS hỗ trợ nhiều lệnh con. Trong các phiên bản Hadoop hiện tại hdfs dfs là hình thức được ưa chuộng hơn, trong khi hình thức cũ hơn thì không. hadoop fs Lệnh này thực hiện cùng một công việc cho bất kỳ hệ thống tệp nào được hỗ trợ.

Dưới đây là danh sách một số lệnh được sử dụng rộng rãi cùng với thông tin chi tiết của từng lệnh.

1. Sao chép tệp từ hệ thống tệp cục bộ sang HDFS

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

Lệnh này sao chép tệp temp.txt từ hệ thống tệp cục bộ sang HDFS, như hiển thị bên dưới.

Lệnh hdfs dfs -copyFromLocal sao chép tệp temp.txt vào HDFS

2. Chúng ta có thể liệt kê các tệp có trong một thư mục bằng lệnh -ls.

$HADOOP_HOME/bin/hdfs dfs -ls /

Trong danh sách bên dưới, chúng ta có thể thấy tệp 'temp.txt' (đã sao chép trước đó) nằm trong thư mục '/'.

Lệnh `hdfs dfs -ls output listing temp.txt` hiển thị danh sách tệp temp.txt trong thư mục gốc của HDFS.

3. Lệnh sao chép tệp vào hệ thống tệp cục bộ từ HDFS

$HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

Lệnh này tương tự như lệnh -get và chấp nhận đường dẫn đích cục bộ rõ ràng làm đối số thứ hai. Kết quả bên dưới cho thấy tệp temp.txt đã được sao chép vào hệ thống tệp cục bộ.

Kết quả lệnh hdfs dfs -copyToLocal cho thấy tệp temp.txt đã được sao chép vào hệ thống tệp cục bộ.

4. Lệnh tạo thư mục mới

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

Lệnh được thực thi một cách im lặng, như thông báo bên dưới cho thấy.

Lệnh hdfs dfs -mkdir tạo thư mục /mydirectory trong HDFS.

Kiểm tra xem thư mục đã được tạo hay chưa. Giờ thì bạn đã biết cách làm rồi đấy 😉

Câu Hỏi Thường Gặp

Các khối lớn giúp giữ cho siêu dữ liệu NameNode nhỏ gọn và cho phép trình ánh xạ đọc một chuỗi byte dài liên tiếp trước khi tìm kiếm lại. Do đó, thời gian tìm kiếm trên đĩa chỉ chiếm một phần nhỏ trong tổng thời gian truyền tải, điều này giúp cho việc quét toàn bộ tập tin diễn ra nhanh chóng.

NameNode ngừng nhận tín hiệu nhịp tim, đánh dấu nút đó là đã chết và lên lịch sao chép lại mọi khối dữ liệu có số lượng sao chép thấp hơn hệ số sao chép của nó lên các DataNode khỏe mạnh. Quá trình ghi đang diễn ra sẽ được khôi phục từ hàng đợi xác nhận (Ack Queue), do đó máy khách sẽ không bị mất gói dữ liệu.

Không nằm trong một cụm được cấu hình đúng cách. HDFS High Availability vận hành một NameNode hoạt động và một NameNode dự phòng, chúng chia sẻ các chỉnh sửa thông qua JournalNodes, và bộ điều khiển chuyển đổi dự phòng ZooKeeper sẽ tự động nâng cấp NameNode dự phòng khi NameNode hoạt động ngừng phản hồi.

Cả hai đều tải dữ liệu lên HDFS. Tùy chọn -copyFromLocal giới hạn nguồn dữ liệu chỉ trong hệ thống tệp cục bộ, trong khi -put chấp nhận bất kỳ nguồn nào được hỗ trợ, bao gồm cả đường dẫn HDFS khác hoặc stdin. Về cơ bản, hành vi của cả hai tùy chọn đều giống nhau, vì vậy -copyFromLocal chỉ đơn giản là ghi lại mục đích.

Mỗi tập tin, thư mục và khối đều chiếm bộ nhớ trong NameNode, vì vậy hàng triệu tập tin nhỏ sẽ làm đầy bộ nhớ heap rất lâu trước khi ổ đĩa đầy. Việc kết hợp chúng thành các tập tin tuần tự, các tệp lưu trữ Avro, ORC, Parquet hoặc HAR giúp quản lý siêu dữ liệu dễ dàng hơn.

Sao chép dữ liệu giữ lại ba bản sao đầy đủ, tiêu tốn thêm 200% dung lượng lưu trữ. Mã hóa xóa lỗi, được thêm vào trong Hadoop 3, lưu trữ các ô chẵn lẻ thay thế và đạt được độ bền tương tự với chi phí tăng thêm khoảng 50%, đánh đổi dung lượng lưu trữ rẻ hơn lấy chi phí CPU và mạng cao hơn trong quá trình phục hồi.

Các mô hình học máy được huấn luyện dựa trên nhật ký kiểm toán NameNode và số liệu DataNode có thể dự báo tình trạng cạn kiệt dung lượng, gắn cờ các khối dữ liệu bị lỗi và phát hiện các ổ đĩa bị lỗi trước khi chúng ngừng hoạt động hoàn toàn. Phát hiện bất thường trên các mẫu truy cập cũng giúp phát hiện sớm các tác vụ chạy quá tải.

Copilot nhanh chóng hoàn thành các đoạn mã mẫu quen thuộc của org.apache.hadoop.fs, chẳng hạn như FileSystem.get, vòng lặp FSDataInputStream và các lệnh gọi IOUtils.copyBytes. Luôn kiểm tra mã được tạo ra so với phiên bản Hadoop đang sử dụng, vì tên API và các phương thức đã lỗi thời khác nhau đáng kể giữa Hadoop 2.x và 3.x.

Tóm tắt bài viết này với: