File kecil adalah masalah besar di Hadoop — atau, setidaknya, jika jumlah pertanyaan pada daftar pengguna tentang topik ini cukup banyak. Dalam posting ini saya akan melihat masalahnya, dan memeriksa beberapa solusi umum.
Masalah dengan file kecil dan HDFS
File kecil adalah file yang secara signifikan lebih kecil dari ukuran blok HDFS (default 64MB). Jika Anda menyimpan file kecil, maka Anda mungkin memiliki banyak file (jika tidak, Anda tidak akan beralih ke Hadoop), dan masalahnya adalah HDFS tidak dapat menangani banyak file.
Setiap file, direktori, dan blok di HDFS direpresentasikan sebagai objek dalam memori namenode, yang masing-masing menempati 150 byte, sebagai aturan praktis. Jadi 10 juta file, masing-masing menggunakan satu blok, akan menggunakan sekitar 3 gigabyte memori. Meningkatkan jauh melampaui level ini adalah masalah dengan perangkat keras saat ini. Tentu saja satu miliar file tidak layak.
Selain itu, HDFS tidak dirancang untuk mengakses file kecil secara efisien:ini terutama dirancang untuk akses streaming file besar. Membaca melalui file kecil biasanya menyebabkan banyak pencarian dan banyak lompatan dari datanode ke datanode untuk mengambil setiap file kecil, yang semuanya merupakan pola akses data yang tidak efisien.
Masalah dengan file kecil dan MapReduce
Tugas peta biasanya memproses blok input sekaligus (menggunakan FileInputFormat
default) ). Jika file sangat kecil dan jumlahnya banyak, maka setiap tugas peta memproses input yang sangat sedikit, dan ada lebih banyak tugas peta, yang masing-masing membebankan overhead pembukuan tambahan. Bandingkan file 1GB yang dipecah menjadi 16 blok 64MB, dan 10.000 atau lebih file 100KB. 10.000 file menggunakan satu peta masing-masing, dan waktu kerja bisa puluhan atau ratusan kali lebih lambat daripada yang setara dengan satu file input.
Ada beberapa fitur untuk membantu meringankan overhead pembukuan:tugas JVM digunakan kembali untuk menjalankan beberapa tugas peta dalam satu JVM, sehingga menghindari beberapa overhead startup JVM (lihat mapred.job.reuse.jvm.num.tasks
properti), dan MultiFileInputSplit
yang dapat menjalankan lebih dari satu pemisahan per peta.
Mengapa file kecil diproduksi?
Setidaknya ada dua kasus
- File adalah bagian dari file logis yang lebih besar. Karena HDFS baru-baru ini mendukung penambahan, pola yang sangat umum untuk menyimpan file yang tidak dibatasi (misalnya file log) adalah dengan menuliskannya dalam potongan-potongan ke dalam HDFS.
- File pada dasarnya kecil. Bayangkan sekumpulan besar gambar. Setiap gambar adalah file yang berbeda, dan tidak ada cara alami untuk menggabungkannya menjadi satu file yang lebih besar.
Kedua kasus ini membutuhkan solusi yang berbeda. Untuk kasus pertama, di mana file terdiri dari catatan, masalah dapat dihindari dengan memanggil sync()
HDFS metode sesering mungkin untuk terus menulis file besar. Atau, Anda dapat menulis program untuk menggabungkan file-file kecil menjadi satu.
Untuk kasus kedua, beberapa jenis wadah diperlukan untuk mengelompokkan file dengan cara tertentu. Hadoop menawarkan beberapa opsi di sini.
File HAR
Arsip Hadoop (file HAR) diperkenalkan ke HDFS di 0.18.0 untuk meringankan masalah banyak file yang menekan memori namenode. File HAR bekerja dengan membangun sistem file berlapis di atas HDFS. File HAR dibuat menggunakan hadoop archive
perintah, yang menjalankan tugas MapReduce untuk mengemas file yang diarsipkan ke dalam sejumlah kecil file HDFS. Untuk klien yang menggunakan sistem file HAR, tidak ada yang berubah:semua file asli dapat dilihat dan diakses (walaupun menggunakan har:// URL). Namun, jumlah file dalam HDFS telah berkurang.
Membaca file dalam HAR tidak lebih efisien daripada membaca file dalam HDFS, dan bahkan mungkin lebih lambat karena setiap akses file HAR memerlukan dua pembacaan file indeks serta file data yang dibaca (lihat diagram). Dan meskipun file HAR dapat digunakan sebagai input ke MapReduce, tidak ada keajaiban khusus yang memungkinkan peta untuk beroperasi pada semua file di HAR co-resident pada blok HDFS. Seharusnya dimungkinkan untuk membangun format input yang dapat memanfaatkan lokalitas file yang ditingkatkan di HAR, tetapi belum ada. Perhatikan bahwa MultiFileInputSplit, bahkan dengan peningkatan dalam HADOOP-4565 untuk memilih file dalam pemisahan yang merupakan node lokal, akan memerlukan pencarian per file kecil. Akan menarik untuk melihat kinerja ini dibandingkan dengan SequenceFile, katakanlah. Saat ini HAR mungkin paling baik digunakan murni untuk tujuan pengarsipan.
File Urutan
Tanggapan biasa untuk pertanyaan tentang "masalah file kecil" adalah:gunakan SequenceFile. Idenya di sini adalah Anda menggunakan nama file sebagai kunci dan konten file sebagai nilainya. Ini bekerja sangat baik dalam praktiknya. Kembali ke 10.000 file 100KB, Anda dapat menulis sebuah program untuk memasukkannya ke dalam satu SequenceFile, dan kemudian Anda dapat memprosesnya dalam mode streaming (langsung atau menggunakan MapReduce) yang beroperasi di SequenceFile. Ada beberapa bonus juga. SequenceFiles dapat dipisah, sehingga MapReduce dapat memecahnya menjadi beberapa bagian dan beroperasi pada setiap bagian secara independen. Mereka mendukung kompresi juga, tidak seperti HAR. Kompresi blok adalah opsi terbaik dalam banyak kasus, karena kompresi blok beberapa record (bukan per record).
Mungkin lambat untuk mengubah data yang ada menjadi SequenceFiles. Namun, sangat mungkin untuk membuat kumpulan SequenceFiles secara paralel. (Stuart Sierra telah menulis posting yang sangat berguna tentang mengonversi file tar menjadi SequenceFile — alat seperti ini sangat berguna, dan akan lebih baik untuk melihat lebih banyak lagi). Untuk selanjutnya, sebaiknya rancang saluran data Anda untuk menulis data di sumber langsung ke SequenceFile, jika memungkinkan, daripada menulis ke file kecil sebagai langkah perantara.
Tidak seperti file HAR, tidak ada cara untuk membuat daftar semua kunci dalam SequenceFile, selain membaca seluruh file. (MapFiles, yang seperti SequenceFiles dengan kunci yang diurutkan, mempertahankan indeks parsial, sehingga mereka juga tidak dapat mencantumkan semua kuncinya — lihat diagram.)
SequenceFile agak Java-sentris. TFile dirancang untuk lintas platform, dan menjadi pengganti SequenceFile, tetapi belum tersedia.
HBase
Jika Anda memproduksi banyak file kecil, maka, tergantung pada pola aksesnya, jenis penyimpanan yang berbeda mungkin lebih sesuai. HBase menyimpan data dalam MapFiles (Indexed SequenceFiles), dan merupakan pilihan yang baik jika Anda perlu melakukan analisis streaming gaya MapReduce dengan pencarian acak sesekali. Jika latensi menjadi masalah, maka ada banyak pilihan lain — lihat survei Richard Jones yang luar biasa tentang key-value store.