java 单例模式打包jar_在 Spark 中实现单例模式的技巧
單例模式是一種常用的設計模式,但是在集群模式下的 Spark 中使用單例模式會引發一些錯誤。我們用下面代碼作例子,解讀在 Spark 中使用單例模式遇到的問題。
object?Example{
var?instance:Example?=?new?Example("default_name");
def?getInstance():Example?=?{
return?instance
}
def?init(name:String){
instance?=?new?Example(name)
}
}
class?Example?private(name1:String)?extends??Serializable{
var?name?=?name1
}
object?Main{
def?main(args:Array[String])?=?{
Example.init("To?create?happiness?with?money")
val?sc?=??new?SparkContext(new?SparkConf().setAppName("test"))
val?rdd?=?sc.parallelize(1?to?10,?3)
rdd.map(x=>{
x?+?"_"+?Example.getInstance().name
}).collect.foreach(println)
}
}
我們預期結果是數字和騰訊游戲座右銘,然后實際的結果確實數字和默認名字,如下所示
就像 Example.init("To create happiness with money") 沒有執行一樣。在 Stackoverflow 上,有不少人也碰到這個錯誤,比如 問題1 、 問題2 和 問題3 。
這是由什么原因導致的呢?Spark 執行算子之前,會將算子需要東西準備好并打包(這就是閉包的概念),分發到不同的 executor,但這里不包括類。類存在 jar 包中,隨著 jar 包分發到不同的 executors 中。當不同的 executors 執行算子需要類時,直接從分發的 jar 包取得。這時候在 driver 上對類的靜態變量進行改變,并不能影響 executors 中的類。拿上面的程序做例子,jar 包存的 Example.instance = new Example("default_name"),分發到不同的 executors。這時候不同 executors 中 Example.getInstance().name 等于 "default_name"。
這個部分涉及到 Spark 底層原理,很難堂堂正正地解決,只能采取取巧的辦法。不能再 executors 使用類,那么我們可以用對象嘛。我們可以把 Example 的實例對象塞進算子的閉包,隨著閉包分發到不同的 executors。修改之后的代碼如下所示。
object?Main{
def?main(args:Array[String])?=?{
Example.init(""To?create?happiness?with?money"")
val?sc?=??new?SparkContext(new?SparkConf().setAppName("test"))
example?=?Example
val?rdd?=?sc.parallelize(1?to?10,?3)
rdd.map(x=>{
x?+?"_"+?Example.getInstance().name
}).collect.foreach(println)
}
}
上面代碼在集群模式下的 Spark 運行結果是數字和騰訊游戲座右銘。
歡迎關注我的公眾號,每周日的更新就會有提醒哦~
總結
以上是生活随笔為你收集整理的java 单例模式打包jar_在 Spark 中实现单例模式的技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个贷委贷回收什么意思
- 下一篇: solr java 全量,Solr实时创