關於Hadoop中reducer端combiner的一些思考

什麼是Combiner Functions

“Many MapReduce jobs are limited by the bandwidth available on the cluster, so it pays to minimize the data transferred between map and reduce tasks. Hadoop allows the user to specify a combiner function to be run on the map output—the combiner function’s output forms the input to the reduce function. Since the combiner function is an optimization, Hadoop does not provide a guarantee of how many times it will call it for a particular map output record, if at all. In other words, calling the combiner function zero, one, or many times should produce the same output from the reducer.” -- 《Hadoop: The Definitive Guide》

簡單的說,combiner是一個在mapper之後運行的function,非常類似reducer的功能,所以在《Hadoop In Action》又叫作“local reduce”。它的好處是減少網絡的數據傳輸,從而提高性能。但因爲是一個優化功能,所以Hadoop並不保證會運行它。

其實這個的有一個更深入的設計問題,這裏有一個假設就是大家傾向於fat mapper和slim reducer。就是一般情況下,大家會儘可能的在mapper裏實現複雜的邏輯和運算,在reducer只是做簡單的匯聚。這就是爲什麼有mapper端的combiner而沒有reducer端的combiner。

reducer端的combiner

是不是試想這樣的情景,一個項目需要多個mapper和reducer才能完成,而且必須在reducer端實現業務邏輯。舉一個例子,輸入日誌包含如下字段:用戶ID,國家,timestamp。需要統計不同國家的用戶的訪問時間(定義爲最後一個訪問的時間戳去第一次訪問的時間戳)。日誌爲~10G/小時,但是分析以一天爲單位。

在這裏,同一個用戶會出現在一天的任何小時,所以必須將同一個用戶匯聚到一起來計算訪問時間。顯然無法在mapper端實現這樣的功能。相同的用戶以“用戶ID”作爲partition key排序後匯聚到reducer端。採用如下的標準模板(Perl語言爲例):

while ( my $line = <STDIN> ) {
	chomp($line);
	( $user_id, $country, $timestamp ) = split( /\t/, $line );

	# set base key
	$key = $base_key;

	if ($cur_key) {
		if ( $key ne $cur_key ) {
			&onEndKey();
			&onBeginKey();
		}
		&onSameKey();
	}
	else {
		&onBeginKey();
		&onSameKey();
	}
}

if ($cur_key) {
	&onEndKey();
}

這裏需要另一個mapper/reducer來匯聚不同國家的時間。如果在第一個reducer端能夠有一個combiner,那麼將極大的減少網絡傳輸,甚至避免out of memory問題(會單獨寫一個文章)。因爲現有的Hadoop並沒有這個功能,只能自己來了。最簡單的實現就是提供一個全局的hash來匯聚。因爲從本質上來說,combiner或者reducer其實就是一個hash。

具體的實現就略去了,這裏只是提供一個設計思路,歡迎大家一起討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章