Spark廣播變量的java 使用踩坑記 賦值,更新與重啓

本文爲純原創,轉載請註明出處,謝謝

spark廣播變量適用於多節點並行操作同一變量的情況,如果spark每次都將該變量分發到不同executor節點那麼浪費資源又佔用帶寬,所以可以將變量在driver端創建一份然後通過廣播變量廣播到各個executor,相當於多個executor共享一個變量,這樣即方便又節約資源。類似下圖(圖片來源於網絡,侵刪)

不使用廣播變量

使用廣播變量

使用廣播變量是我最近項目上做性能調優的一個手段,但是也踩了比較多的坑,現記錄如下,以作參考

1、廣播的變量必須進行序列化,如果是自定義的類,需要實現Serializable接口(至於爲什麼要序列化,歡迎自行閱讀spark官網,此處不做解釋)

此處說的實現序列化接口,不單單是廣播的類需要實現,如果該類中包含其他類,那麼其他類也同樣需要實現序列化接口

例如:

Map<String,Buffer> broadcastBuffer=new HashMap<String,Buffer> 作爲值放入廣播變量JavaSparkContext.broadcast(broadcastBuffer) 此處不光要求HashMap需要實現Serializable,自定義實體類Buffer同樣需要implements Serializable,否則在調用的時候就會出現反序列化異常

2、如果傳遞的類本身不支持序列化,那麼需要用一個包裝類包裝一下,並且包裝類要實現Serializable接口。

例如:

需求爲,sparkStreaming對一些日誌信息進行過濾,過濾過後需要送回kafka,如果在foreachrdd內不斷創建新的kafkaproducer,勢必會造成連接過多,可能把kafka搞死了,那就可以將一個kafkaProducer放入到廣播變量內廣播出去,避免造成連接過多,但是KafkaProducer本身沒有實現Serializable接口,我們不能去改kafka源碼吧?所以可以用一個包裝類,把KafkaProducer包裝起來,讓這個類來implements Serializable繼而放入廣播變量。

代碼如下:

/**
    包裝類
*/
public class KafkaProducerClient implements Serializable{

	/**
	 * 必須序列化,不序列化無法在executor端使用
	 * 
	 */ 
	private  KafkaProducer<String, String> kafkaProducer = null; 
	private  Properties kafkaProduceProperties;

	/**
	 * 創建生產者實例
	 * 
	 * @param  kafkaproperties配置信息 
	 * 
	 */
	public KafkaProducerClient(Properties properties) {
		kafkaProduceProperties = properties;
	}
	
	public Properties getProperties(){
		return kafkaProduceProperties;
	}
	// 由於Producer沒有實現Serialiable接口,只能採用懶加載的方式
    public synchronized KafkaProducer<String, String> getProducer() {
        if (!Lang.isEmpty(kafkaProducer)) {
        	 
            return kafkaProducer;
        }
        kafkaProducer = new KafkaProducer<String, String>(kafkaProduceProperties);
        return kafkaProducer;
    }
 
}
/**
    Driver端賦值代碼塊
*/
public Broadcast<KafkaProducerClient> kafka;
KafkaProducerClient kpc=new KafkaProducerClient(properties); 
JavaSparkContext.broadcast(kafka);

3、如何更新重啓

應用廣播變量的時候,難免遇見廣播的內容需要更新(比如緩存的實時更新),但是廣播變量不支持實時更新,所以只能手動停掉,然後重新賦值,java代碼塊如下

//停止
broadcast.unpersist();
//重新賦值並廣播	
 broadcast=JavaSparkContext().broadcast(廣播內容);  

4、使用

使用很簡單broadcast.value() 就可以了,需要加類型轉換,不過這點編譯器都會進行提醒

以上。

 

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