HBase
 sql >> Teknologi Basis Data >  >> NoSQL >> HBase

Apache HBase + Apache Hadoop + Xceiver

Pengantar

Beberapa properti konfigurasi yang ditemukan di Apache Hadoop memiliki efek langsung pada klien, seperti Apache HBase. Salah satu properti tersebut disebut “dfs.datanode.max.xcievers”, dan milik subproyek HDFS. Ini mendefinisikan jumlah utas sisi server dan - sampai batas tertentu - soket yang digunakan untuk koneksi data. Menyetel jumlah ini terlalu rendah dapat menyebabkan masalah saat Anda mengembangkan atau meningkatkan pemanfaatan klaster Anda. Postingan ini akan membantu Anda memahami apa yang terjadi antara klien dan server, dan cara menentukan jumlah yang wajar untuk properti ini.

Masalahnya

Karena HBase menyimpan semua yang dibutuhkannya di dalam HDFS, batas atas keras yang diberlakukan oleh properti konfigurasi “dfs.datanode.max.xcievers” dapat mengakibatkan terlalu sedikitnya resource yang tersedia untuk HBase, yang memanifestasikan dirinya sebagai IOExceptions di kedua sisi koneksi. Berikut adalah contoh dari milis HBase [1], di mana pesan berikut awalnya dicatat di sisi RegionServer:

2011-11-11 19:55:52.451 INFO org.apache.hadoop.dfs.DFSClient: Pengecualian di createBlockOutputStream java.io.IOException:Tidak dapat membaca dari streaming
2008-11-11 19:55:52.451 INFO org.apache.hadoop.dfs.DFSClient: Meninggalkan blok blk_-5467014108758633036_595771
2008-11- 11 19:55:58,455 WARN org.apache.hadoop.dfs.DFSClient: Pengecualian DataStreamer:java.io.IOException:Tidak dapat membuat blok baru.
11-11 2008 19:55:58,455 WARN org.apache .hadoop.dfs.DFSClient:Error Recovery for block blk_-5467014108758633036_595771 bad datanode[0]
2008-11-11 19:55:58,482 FATAL org.apache.hadoop.hbase.regionserver.Flusher:Perlu memutar ulang hlog . Memaksa server dimatikan

Menghubungkan ini dengan log Hadoop DataNode mengungkapkan entri berikut:

ERROR org.apache.hadoop.dfs.DataNode: DatanodeRegistration(10.10.10.53:50010,storageID=DS-1570581820-10.10.10.53-50010-1224117842339,infoPort=50075, ipcPort=50020):DataXceiver:java.io.IOException: xceiverCount 258 melebihi batas xciever bersamaan 256

Dalam contoh ini, rendahnya nilai “dfs.datanode.max.xcievers” untuk DataNodes menyebabkan seluruh RegionServer dimatikan. Ini adalah situasi yang sangat buruk. Sayangnya, tidak ada aturan keras dan cepat yang menjelaskan cara menghitung batas yang diperlukan. Biasanya disarankan untuk menaikkan angka dari default 256 menjadi sekitar 4096 (lihat [1], [2], [3], [4], dan [5] untuk referensi). Ini dilakukan dengan menambahkan properti ini ke file hdfs-site.xml dari semua DataNodes (perhatikan bahwa salah eja):

    dfs.datanode.max.xcievers
4096

Catatan:Anda harus memulai ulang DataNodes Anda setelah membuat perubahan ini pada file konfigurasi.

Ini akan membantu mengatasi masalah di atas, tetapi Anda mungkin masih ingin tahu lebih banyak tentang bagaimana semua ini bekerja bersama, dan apa yang dilakukan HBase dengan sumber daya ini. Kami akan membahas ini di sisa posting ini. Tapi sebelum kita melakukannya, kita harus jelas tentang mengapa Anda tidak bisa begitu saja menetapkan angka ini sangat tinggi, katakanlah 64K dan selesai.

Ada alasan untuk batas atas, dan itu ada dua:pertama, utas membutuhkan tumpukannya sendiri, yang berarti mereka menempati memori. Untuk server saat ini, ini berarti 1MB per utas[6] secara default. Dengan kata lain, jika Anda menggunakan semua 4096 utas DataXceiver, Anda memerlukan sekitar 4GB tumpukan untuk menampungnya. Ini memotong ruang yang telah Anda tetapkan untuk memstore dan memblokir cache, serta semua bagian JVM yang bergerak lainnya. Dalam skenario terburuk, Anda mungkin mengalami OutOfMemoryException, dan proses RegionServer bersulang. Anda ingin menyetel properti ini ke angka yang cukup tinggi, tetapi juga tidak terlalu tinggi.

Kedua, dengan mengaktifkan banyak utas ini, Anda juga akan melihat CPU Anda menjadi semakin dimuat. Akan ada banyak sakelar konteks yang terjadi untuk menangani semua pekerjaan bersamaan, yang menghilangkan sumber daya untuk pekerjaan nyata. Seperti halnya kekhawatiran tentang memori, Anda ingin jumlah utas tidak bertambah tanpa batas, tetapi berikan batas atas yang masuk akal – dan untuk itulah “dfs.datanode.max.xcievers”.

Detail Sistem File Hadoop

Dari sisi klien, perpustakaan HDFS menyediakan abstraksi yang disebut Path. Kelas ini mewakili file dalam sistem file yang didukung oleh Hadoop, diwakili oleh kelas FileSystem. Ada beberapa implementasi konkret dari kelas FileSystem abstrak, salah satunya adalah DistributedFileSytem, ​​yang mewakili HDFS. Kelas ini pada gilirannya membungkus kelas DFSClient aktual yang menangani semua interaksi dengan server jarak jauh, yaitu NameNode dan banyak DataNodes.

Saat klien, seperti HBase, membuka file, ia melakukannya dengan, misalnya, memanggil metode open() atau create() dari kelas FileSystem, di sini inkarnasi paling sederhana

  publik DFSInputStream open(String src) throws IOException
public FSDataOutputStream create(Path f) throws IOException

Instance aliran yang dikembalikan adalah yang memerlukan soket dan utas sisi server, yang digunakan untuk membaca dan menulis blok data. Mereka membentuk bagian dari kontrak untuk bertukar data antara klien dan server. Perhatikan bahwa ada protokol berbasis RPC lain yang digunakan di antara berbagai mesin, tetapi untuk tujuan diskusi ini protokol tersebut dapat diabaikan.

Instance streaming yang ditampilkan adalah kelas DFSOutputStream atau DFSInputStream khusus, yang menangani semua interaksi dengan NameNode untuk mencari tahu di mana salinan blok berada, dan komunikasi data per blok per DataNode.

Di sisi server, DataNode membungkus instance DataXceiverServer, yang merupakan kelas aktual yang membaca kunci konfigurasi di atas dan juga menampilkan pengecualian di atas saat batas terlampaui.

Saat DataNode dimulai, ia membuat grup utas dan memulai instance DataXceiverServer yang disebutkan seperti:

  this.threadGroup =new ThreadGroup(“dataXceiverServer”);
this.dataXceiverServer =new Daemon( threadGroup,
DataXceiverServer baru(ss, conf, this));
this.threadGroup.setDaemon(true); // hancurkan otomatis saat kosong

Perhatikan bahwa utas DataXceiverServer sudah menempati satu tempat di grup utas. DataNode juga memiliki kelas internal ini untuk mengambil jumlah utas yang sedang aktif di grup ini:

  /** Jumlah xceiver bersamaan per node. */
int getXceiverCount() {
kembalikan threadGroup ==null ? 0 :threadGroup.activeCount();
}

Membaca dan menulis blok, seperti yang diprakarsai oleh klien, menyebabkan sambungan dibuat, yang digabungkan oleh utas DataXceiverServer menjadi instance DataXceiver. Selama hand off ini, sebuah utas dibuat dan didaftarkan di grup utas di atas. Jadi untuk setiap operasi baca dan tulis yang aktif, utas baru dilacak di sisi server. Jika jumlah utas dalam grup melebihi maksimum yang dikonfigurasi, maka pengecualian tersebut dilemparkan dan dicatat dalam log DataNode:

  if (curXceiverCount> dataXceiverServer.maxXceiverCount) {
throw new IOException(“xceiverCount ” + curXceiverCount
+ ” melebihi batas xcievers bersamaan ”
+ dataXceiverServer.maxXceiverCount);
}

Implikasi bagi Klien

Sekarang, pertanyaannya adalah, bagaimana hubungan membaca dan menulis klien dengan utas sisi server. Sebelum kita masuk ke detailnya, mari gunakan informasi debug yang dicatat oleh kelas DataXceiver saat dibuat dan ditutup

  LOG.debug(“Jumlah koneksi aktif adalah:” + datanode.getXceiverCount());

LOG.debug(datanode.dnRegistration + “:Jumlah koneksi aktif adalah:”     + datanode.getXceiverCount());

dan pantau selama awal HBase apa yang dicatat di DataNode. Demi kesederhanaan, ini dilakukan pada pengaturan terdistribusi semu dengan satu contoh DataNode dan RegionServer. Berikut ini menunjukkan bagian atas halaman status RegionServer.

Bagian penting ada di bagian "Metrik", di mana dikatakan "storefiles=22". Jadi, dengan asumsi bahwa HBase memiliki setidaknya banyak file untuk ditangani, ditambah beberapa file tambahan untuk log write-ahead, kita akan melihat pesan log di atas menyatakan bahwa kita memiliki setidaknya 22 "koneksi aktif". Mari kita mulai HBase dan periksa file log DataNode dan RegionServer:

Baris Perintah:

$ bin/start-hbase.sh

Log DataNode:

05-03-2012 13:01:35,309 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Jumlah koneksi aktif adalah:1
05-03-2012 13:01:35,315 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS- 1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:2
12/03/05 13:01:35 INFO regionserver.MemStoreFlusher:globalMemStoreLimit=396.7m, globalMemStoreLimitLowMark=347.1m, maxHeap=991.7m
05/12/03 13:01:39 INFO http.HttpServer:Port dikembalikan oleh webServer.getConnectors()[0].getLocalPort() sebelum open() adalah -1 . Membuka pendengar pada 60030
05-03-2012 13:01:40.003 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:1
12/03/05 13:01:40 INFO regionserver.HRegionServer:Menerima permintaan untuk membuka region:-ROOT-,,0.70236052
03-2012 13:01:40,882 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode :Jumlah koneksi aktif adalah:3
05-03-2012 13:01:40,884 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448 -10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:4
03-2012-05 13:01:40,888 DEBUG org.apache.hadoop.hdfs.server. datanode.DataNode:Jumlah koneksi yang aktif adalah:3

12/03/05 13:01:40 INFO regionserver.HRegion:Onlined -ROOT-,,0.70236052; next sequenceid=63083
05-03-2012 13:01:40,982 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi yang aktif adalah:3
03-2012 13 :01:40,983 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:4

12/03/05 13:01:41 INFO regionserver.HRegionServer:Menerima permintaan untuk membuka wilayah:.META.,,1.1028785192
2012-03 -05 13:01:41,026 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi yang aktif adalah:3
05-03-2012 13:01:41,027 DEBUG org.apache.hadoop. hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif:4

12/03/05 13:01:41 INFO regionserver.HRegion:Onlined .META.,,1.1028785192; next sequenceid=63082
05-03-2012 13:01:41,109 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:3
03-2012 13 :01:41,114 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:4
03-2012-05 13:01:41.117 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:Jumlah koneksi aktif adalah:5
12/03/05 13:01:41 INFO regionserver.HRegionServer:Menerima permintaan untuk membuka 16 region
12/03/05 13 :01:41 INFO regionserver.HRegionServer:Menerima permintaan untuk membuka region:usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.
12/03/05 13:01:41 INFO regionserver.HRegionServer:Menerima permintaan untuk membuka region:usertable,user1120311784 1330944810191.90d287473fe223f0ddc137020efda25d.

05-03-2012 13:01:41,246 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Jumlah koneksi aktif:6
05-03-2012 13:01:41,248 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif:7

05-03-2012 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772 , infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:10
03-2012-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0. 0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:9

12/03/05 13:01:41 INFO regionserver.HRRegion:Tabel pengguna online, pengguna1120311784,1330944810191.90d287473fe223f0ddc137020efda25d.; next sequenceid=62917
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.; next sequenceid=62916

12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,user1361265841,1330944811370.80663fcf291e3ce00080599964f406ba.; next sequenceid=62919
05-03-2012 13:01:41.474 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:6
03-2012 13 :01:41.491 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:7
05-03-2012 13:01:41.495 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:8
2012-03 -05 13:01:41.508 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:7

12/03/05 13:01:41 INFO regionserver .Hregion:Tabel pengguna online, pengguna1964968041,1330944848231.dd89596e9129e1caa7e07f8a491c9734.; next sequenceid=62920
05-03-2012 13:01:41,618 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:6
03-2012 13 :01:41,621 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi yang aktif adalah:7

05-03-2012 13:01:41,829 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:7
12/03/05 13:01:41 INFO regionserver.HRegion:Tabel pengguna online ,pengguna515290649,1330944849739.d23924dc9e9d5891f332c337977af83d.; next sequenceid=62926
05-03-2012 13:01:41,832 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:6
03-05-2012 13 :01:41,838 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:7
05/12/03 13:01:41 INFO regionserver.HRegion:Onlined usertable,user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f.; next sequenceid=62929

2012-03-05 14:01:39,711 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:4
2012 -03-05 22:48:41,945 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:4
03/12/05 22:48:41 INFO regionserver.HRegion:Tabel pengguna online,user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f.; next sequenceid=62929
05-03-2012 22:48:41,963 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64 -50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:4

Anda dapat melihat bagaimana wilayah dibuka satu demi satu, tetapi Anda juga mungkin memperhatikan bahwa jumlah koneksi aktif tidak pernah naik menjadi 22 – bahkan hampir mencapai 10. Mengapa demikian? Untuk memahami hal ini dengan lebih baik, kita harus melihat bagaimana file dalam HDFS dipetakan ke instance DataXceiver sisi server – dan utas aktual yang diwakilinya.

Penyelaman Hadoop Jauh

DFSInputStream dan DFSOutputStream yang disebutkan di atas benar-benar fasad di sekitar konsep aliran biasa. Mereka membungkus komunikasi klien-server ke dalam antarmuka Java standar ini, sementara secara internal merutekan lalu lintas ke DataNode yang dipilih – yang merupakan salah satu yang menyimpan salinan blok saat ini. Ia memiliki kebebasan untuk membuka dan menutup koneksi ini sesuai kebutuhan. Saat klien membaca file dalam HDFS, kelas pustaka klien beralih secara transparan dari blok ke blok, dan oleh karena itu dari DataNode ke DataNode, sehingga harus membuka dan menutup koneksi sesuai kebutuhan.

DFSInputStream memiliki instance kelas DFSClient.BlockReader, yang membuka koneksi ke DataNode. Instance streaming memanggil blockSeekTo() untuk setiap panggilan ke read() yang menangani pembukaan koneksi, jika belum ada. Setelah blok benar-benar dibaca, koneksi ditutup. Menutup aliran tentu saja memiliki efek yang sama.

DFSOutputStream memiliki kelas pembantu yang serupa, yaitu DataStreamer. Ini melacak koneksi ke server, yang dimulai oleh metode nextBlockOutputStream(). Ini memiliki kelas internal lebih lanjut yang membantu menulis data blok, yang kami hilangkan di sini demi singkatnya.

Baik blok tulis maupun baca memerlukan utas untuk menampung soket dan data perantara di sisi server, yang dibungkus dalam instance DataXceiver. Bergantung pada apa yang dilakukan klien Anda, Anda akan melihat jumlah koneksi berfluktuasi di sekitar jumlah file yang diakses saat ini di HDFS.

Kembali ke teka-teki HBase di atas:alasan Anda tidak melihat hingga 22 (dan lebih) koneksi selama awal adalah karena saat wilayah terbuka, satu-satunya data yang diperlukan adalah blok info HFile. Blok ini dibaca untuk mendapatkan detail penting tentang setiap file, tetapi kemudian ditutup lagi. Ini berarti bahwa sumber daya sisi server dirilis secara berurutan. Empat koneksi yang tersisa lebih sulit untuk ditentukan. Anda dapat menggunakan JStack untuk membuang semua utas di DataNode, yang dalam contoh ini menunjukkan entri ini:

“DataXceiver untuk klien /127.0.0.1:64281 [sending block blk_5532741233443227208_4201]” daemon prio=5 tid=7fb96481d000 nid=0x1178b4000 dapat dijalankan [1178b3000]
java.lang.Thread.State:RUNNABLE

“DataXceiver untuk klien /127.0.0.1:64172 [menerima blok blk_-2005512129579433420_4199 client=DFSClient_hb_rs_10.0.0.29 ,60020,1330984111693_1330984118810]” daemon prio=5 tid=7fb966109000 nid=0x1169cb000 dapat dijalankan [1169ca000]
java.lang.Thread.State:RUNNABLE

Ini adalah satu-satunya entri DataXceiver (dalam contoh ini), jadi hitungan di grup utas agak menyesatkan. Ingatlah bahwa utas daemon DataXceiverServer sudah menyumbang satu entri tambahan, yang digabungkan dengan dua akun di atas untuk tiga koneksi aktif – yang sebenarnya berarti tiga utas aktif. Alasan log menyatakan empat sebagai gantinya, adalah karena ia mencatat hitungan dari utas aktif yang akan segera selesai. Jadi, tak lama setelah hitungan empat dicatat, itu sebenarnya kurang satu, yaitu tiga dan karenanya cocok dengan jumlah kepala kita dari utas aktif.

Perhatikan juga bahwa kelas pembantu internal, seperti PacketResponder menempati utas lain dalam grup saat sedang aktif. Output JStack memang menunjukkan fakta itu, mencantumkan utas seperti itu:

 “PacketResponder 0 for Block blk_-2005512129579433420_4199” daemon prio=5 tid=7fb96384d000 nid=0x116ace000 di Object.wait () [116acd000]
java.lang.Thread.State:TIMED_WAITING (pada monitor objek)
di java.lang.Object.wait(Metode Asli)
di org.apache.hadoop. hdfs.server.datanode.BlockReceiver$PacketResponder \
.lastDataNodeRun(BlockReceiver.java:779)
– terkunci (org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder)
di org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder.run(BlockReceiver.java:870)
di java.lang.Thread.run(Thread.java:680)

Utas ini saat ini dalam status TIMED_WAITING dan tidak dianggap aktif. Itulah sebabnya jumlah yang dikeluarkan oleh pernyataan log DataXceiver tidak termasuk jenis utas ini. Jika mereka menjadi aktif karena klien mengirim data pengiriman, jumlah utas aktif akan naik lagi. Hal lain yang perlu diperhatikan adalah bahwa utas ini tidak memerlukan koneksi atau soket terpisah antara klien dan server. PacketResponder hanyalah utas di sisi server untuk menerima data blok dan mengalirkannya ke DataNode berikutnya di jalur tulis.

Perintah Hadoop fsck juga memiliki opsi untuk melaporkan file apa yang saat ini terbuka untuk ditulis:

$ hadoop fsck /hbase -openforwrite
FSCK dimulai oleh larsgeorge dari /10.0.0.29 untuk jalur / hbase pada Sen 05 Mar 22:59:47 CET 2012
……/hbase/.logs/10.0.0.29,60020,1330984111693/10.0.0.29%3A60020.1330984118842 0 byte, 1 blok, OPENFORWRITE:………………………………..Status:SEHAT
Total ukuran:     2088783626 B
Total direktori:     54
Total file:   45

Ini tidak langsung berhubungan dengan utas sisi server yang ditempati, karena ini dialokasikan oleh ID blok. Tetapi Anda dapat mengambil kesimpulan darinya, bahwa ada satu blok terbuka untuk menulis. Perintah Hadoop memiliki opsi tambahan untuk mencetak file aktual dan memblokir ID yang terdiri dari:

$ hadoop fsck /hbase -files -blocks
FSCK dimulai oleh larsgeorge dari /10.0.0.29 untuk path /hbase pada Sel 06 Mar 10:39:50 CET 2012


/hbase/.META./1028785192/.tmp


/hbase/.META./1028785192/info
/hbase/.META./1028785192/info/4027596949915293355 36517 byte, 1 blok:  OK
0. blk_5532741233443227208_4201 len=36517 repl=1


Status:SEHAT
Ukuran total:     2088788703 B
Total direktori :     54
Total file:     45 (File yang sedang ditulis:1)
Total blok (divalidasi):     64 (ukuran blok rata-rata 32637323 B) (Total blok file terbuka (tidak divalidasi):1)
Blok yang direplikasi minimal:     64 (100,0 %)

Ini memberi Anda dua hal. Pertama, ringkasan menyatakan bahwa ada satu blok file yang terbuka pada saat perintah dijalankan – cocok dengan jumlah yang dilaporkan oleh opsi “-openforwrite” di atas. Kedua, daftar blok di sebelah setiap file memungkinkan Anda mencocokkan nama utas dengan file yang berisi blok yang sedang diakses. Dalam contoh ini blok dengan ID "blk_5532741233443227208_4201" dikirim dari server ke klien, di sini RegionServer. Blok ini milik HBase .META. tabel, seperti yang ditunjukkan oleh output dari perintah Hadoop fsck. Kombinasi JStack dan fsck dapat berfungsi sebagai pengganti mans yang buruk untuk lsof (alat pada baris perintah Linux untuk "mendaftarkan file yang terbuka").

JStack juga melaporkan bahwa ada utas DataXceiver, dengan PacketResponder yang menyertainya, untuk ID blok “blk_-2005512129579433420_4199”, tetapi ID ini hilang dari daftar blok yang dilaporkan oleh fsck. Ini karena blok belum selesai dan karena itu tidak tersedia untuk pembaca. Dengan kata lain, Hadoop fsck hanya melaporkan pemblokiran yang lengkap (atau disinkronkan[7][8], untuk versi Hadoop yang mendukung fitur ini.

Kembali ke HBase

Membuka semua wilayah tidak memerlukan banyak sumber daya di server seperti yang Anda harapkan. Jika Anda memindai seluruh tabel HBase, Anda memaksa HBase untuk membaca semua blok di semua HFiles:

HBase Shell:

hbase(main):003:0> scan 'usertable'

1000000 baris dalam 1460.3120 detik

Log DataNode:

05-03-2012 14:42:20,580 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Jumlah koneksi aktif:6
05-03-2012 14:43:23,293 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif:7
2012 -03-05 14:43:23.299 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-132135223772, infoPort=50075, ipcPort=50020):Jumlah koneksi yang aktif adalah:8

05-03-2012 14:49:24,332 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0. 0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah:11
05-03-2012 14:49:24,332 DEBUG org .apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:10
05-03-2012 14:49:59,987 DEBUG org.apache.hadoop.hdfs.server.datanod e.DataNode:Jumlah koneksi yang aktif adalah:11
05-03-2012 14:51:12.603 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif:12
05-2012-05 14:51:12,605 DEBUG org.apache.hadoop.hdfs .server.datanode.DataNode:Jumlah koneksi aktif:11
05-03-2012 14:51:46,473 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif:12

05-03-2012 14:56:59,420 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:15
03-2012 14:57:31,722 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:16
05-03-2012 14:58:24.909 DEBUG org.apache.hadoop.hdfs. server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-132135223772, infoPort=50075, ipcPort=50020):Jumlah tindakan koneksi ive adalah:17
2012-03-05 14:58:24.910 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:16

05-03-2012 15:04:17.688 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi yang aktif adalah:21
05-03-2012 15:04:17,689 DEBUG org.apache .hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi yang aktif adalah:22
05-03-2012 15:04:54.545 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:21
05-03-2012 15:05:55.901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Jumlah koneksi aktif adalah :22
05-03-2012 15:05:55.901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Jumlah koneksi aktif adalah:21

Jumlah koneksi aktif mencapai 22 yang sulit dipahami sekarang. Perhatikan bahwa jumlah ini sudah termasuk utas server, jadi kami masih sedikit kekurangan dari apa yang dapat kami anggap sebagai maksimum teoretis – berdasarkan jumlah file yang harus ditangani HBase.

Apa artinya semua itu?

Jadi, berapa banyak "xcievers (sic)" yang Anda butuhkan? Mengingat Anda hanya menggunakan HBase, Anda dapat dengan mudah memantau metrik "storefiles" di atas (yang juga Anda dapatkan melalui Ganglia atau JMX) dan menambahkan beberapa persen untuk file log perantara dan write-ahead. Ini harus bekerja untuk sistem yang sedang bergerak. Namun, jika Anda menentukan angka tersebut pada sistem yang tidak digunakan dan dipadatkan sepenuhnya dan menganggapnya sebagai maksimum, Anda mungkin menemukan angka ini terlalu rendah setelah Anda mulai menambahkan lebih banyak file penyimpanan selama pembersihan memstore biasa, yaitu segera setelah Anda mulai menambahkan data ke tabel HBase. Atau jika Anda juga menggunakan MapReduce pada cluster yang sama, agregasi log Flume, dan sebagainya. Anda perlu memperhitungkan file tambahan tersebut, dan, yang lebih penting, membuka blok untuk membaca dan menulis.

Perhatikan lagi bahwa contoh dalam posting ini menggunakan DataNode tunggal, sesuatu yang tidak akan Anda miliki di cluster nyata. Untuk itu, Anda harus membagi jumlah total file penyimpanan (sesuai metrik HBase) dengan jumlah DataNodes yang Anda miliki. Jika Anda memiliki, misalnya, jumlah file penyimpanan 1000, dan cluster Anda memiliki 10 DataNode, maka Anda seharusnya setuju dengan default 256 xceiver thread per DataNode.

Kasus terburuk adalah jumlah semua pembaca dan penulis aktif, yaitu mereka yang sedang mengirim atau menerima data. Tetapi karena ini sulit ditentukan sebelumnya, Anda mungkin ingin mempertimbangkan untuk membangun di tempat yang layak. Juga, karena proses penulisan membutuhkan utas ekstra – meskipun berumur lebih pendek – (untuk PacketResponder), Anda juga harus memperhitungkannya. Jadi, rumus yang masuk akal, tetapi agak sederhana bisa jadi:

Rumus ini memperhitungkan bahwa Anda memerlukan sekitar dua utas untuk penulis aktif dan satu lagi untuk pembaca aktif. Ini kemudian dijumlahkan dan dibagi dengan jumlah DataNode, karena Anda harus menentukan “dfs.datanode.max.xcievers” per DataNode.

Jika Anda mengulang kembali ke tangkapan layar HBase RegionServer di atas, Anda melihat ada 22 file penyimpanan. These are immutable and will only be read, or in other words occupy one thread only. For all memstores that are flushed to disk you need two threads – but only until they are fully written. The files are finalized and closed for good, cleaning up any thread in the process. So these come and go based on your flush frequency. Same goes for compactions, they will read N files and write them into a single new one, then finalize the new file. As for the write-ahead logs, these will occupy a thread once you have started to add data to any table. There is a log file per server, meaning that you can only have twice as many active threads for these files as you have RegionServers.

For a pure HBase setup (HBase plus its own HDFS, with no other user), we can estimate the number of needed DataXceiver’s with the following formula:

Since you will be hard pressed to determine the active number of store files, flushes, and so on, it might be better to estimate the theoretical maximum instead. This maximum value takes into account that you can only have a single flush and compaction active per region at any time. The maximum number of logs you can have active matches the number of RegionServers, leading us to this formula:

Obviously, the number of store files will increase over time, and the number of regions typically as well. Same for the numbers of servers, so keep in mind to adjust this number over time. In practice, you can add a buffer of, for example, 20%, as shown in the formula below – in an attempt to not force you to change the value too often.

On the other hand, if you keep the number of regions fixed per server[9], and rather split them manually, while adding new servers as you grow, you should be able to keep this configuration property stable for each server.

Final Advice &TL;DR

Here is the final formula you want to use:

It computes the maximum number of threads needed, based on your current HBase vitals (no. of store files, regions, and region servers). It also adds a fudge factor of 20% to give you room for growth. Keep an eye on the numbers on a regular basis and adjust the value as needed. You might want to use Nagios with appropriate checks to warn you when any of the vitals goes over a certain percentage of change.

Note:Please make sure you also adjust the number of file handles your process is allowed to use accordingly[10]. This affects the number of sockets you can use, and if that number is too low (default is often 1024), you will get connection issues first.

Finally, the engineering devil on one of your shoulders should already have started to snicker about how horribly non-Erlang-y this is, and how you should use an event driven approach, possibly using Akka with Scala[11] – if you want to stay within the JVM world. Bear in mind though that the clever developers in the community share the same thoughts and have already started to discuss various approaches[12][13].

Links:

  • [1] http://old.nabble.com/Re%3A-xceiverCount-257-exceeds-the-limit-of-concurrent-xcievers-256-p20469958.html
  • [2] http://ccgtech.blogspot.com/2010/02/hadoop-hdfs-deceived-by-xciever.html
  • [3] https://issues.apache.org/jira/browse/HDFS-1861 “Rename dfs.datanode.max.xcievers and bump its default value”
  • [4] https://issues.apache.org/jira/browse/HDFS-1866 “Document dfs.datanode.max.transfer.threads in hdfs-default.xml”
  • [5] http://hbase.apache.org/book.html#dfs.datanode.max.xcievers
  • [6] http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom
  • [7] https://issues.apache.org/jira/browse/HDFS-200 “In HDFS, sync() not yet guarantees data available to the new readers”
  • [8] https://issues.apache.org/jira/browse/HDFS-265 “Revisit append”
  • [9] http://search-hadoop.com/m/CBBoV3z24H1 “HBase, mail # user – region size/count per regionserver”
  • [10] http://hbase.apache.org/book.html#ulimit “ulimit and nproc”
  • [11] http://akka.io/ “Akka”
  • [12] https://issues.apache.org/jira/browse/HDFS-223 “Asynchronous IO Handling in Hadoop and HDFS”
  • [13] https://issues.apache.org/jira/browse/HDFS-918 “Use single Selector and small thread pool to replace many instances of BlockSender for reads”


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Kinerja HBase CDH5 (HBase1) vs CDH6 (HBase2)

  2. Singkatnya, Replikasi Basis Data Operasional Cloudera

  3. Bagaimana-untuk:Sertakan Perpustakaan Pihak Ketiga di Pekerjaan MapReduce Anda

  4. Membuat Standar Terbuka:Tata Kelola Pembelajaran Mesin menggunakan Apache Atlas

  5. Cara menerapkan model ML ke produksi