標籤:master ha徹底解密
內容:
1、Master HA解析;
2、Master HA的四種方式;
3、Master HA的內部工作機制;
4、Master HA的源碼解密;
本講主要源碼角度分析Master HA,因為在生產環境必然要做的
==========Master HA解析============
Spark是Master-Slave的結構
650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />
現在業界是1個Master Active,2個以上standby
如果有HA的話,切換active的時候,會在上次啟動並執行基礎上繼續運行
Drvier提交程式、申請資源,是跟Master互動
ZOOKEEPER工作採用的是leader的機制,它對外提供服務,其它都是follower
ZOOKEEPER保留了叢集的資訊:Worker、Driver、Application的資訊,會被持久化到Zookeeper,切換的時候只會影響新Job的提交。
因為每個Job運行之前,只要跟叢集申請到資源之後,和Master沒關係了,之後就是Driver和executor的互動,在27講說過。所以只會影響新Job提交,而不會影響現有Job的運行。
=>總結:
1、生產環境一般採用zookeeper做HA,且建議為3台Master,Zookeeper會自動化管理Masters的切換;
2、採用Zookeeper做HA的時候,Zookeeper會儲存整個Spark叢集運行時候的中繼資料:所有的Workers、Drivers、Applications、Executors等;
3、Zookeeper在遇到當前Active層級的Master出現故障的時候,會從standby Master中選取出一台做為Active Master,但是要注意:被選舉後到成為真正的Active Master之間需要從Zookeeper擷取叢集當前運行狀態的中繼資料資訊並進行恢複;
4、在Master切換的過程中,所有的已經在啟動並執行程式皆正常運行!因為Spark Application在運行前就已經通過Cluster Manager獲得了計算資源,所以在運行時Job本身的調度和處理和Master是沒有任何關係的;
5、在Master切換過程中唯一的影響是,是不能提交新的Job:一方面不能提交新的應用程式給叢集,因為只有Active Master才能接收新的程式的提交請求,另外一方面,已經啟動並執行程式中也不能夠因為Action操作觸發新的Job的提交請求;
經驗之談:yarn的模式比standalone模式效能低30%左右
==========Master HA的四種方式============
1、MasterHA四大方式分別是:ZOOKEEPER、FILESYSTEM、CUSTOM(自訂)、NONE(不做HA,下載Spark直接使用);
2、需要說明的是:
1)ZOOKEEPER是自動管理Master;
2)FILESYSTEM的方式在Master出現故障後需要手動重新啟動機器,機器啟動後會立即成為Active層級的Master來對外提供服務(接受應用程式提交的請求,接受新的Job啟動並執行請求);
3)CUSTOM的方式允許使用者自訂MasterHA的實現,這對於進階使用者特別有用;
4)NONE,這是預設情況,當我們下載安裝了Spark叢集後,就是採用這種方式,該方式不會持久化叢集的資料,Master啟動後立即管理叢集;
Master中onStart
val serializer = new JavaSerializer(conf)
val (persistenceEngine_, leaderElectionAgent_) = RECOVERY_MODE match {
case "ZOOKEEPER" =>
logInfo("Persisting recovery state to ZooKeeper")
val zkFactory =
new ZooKeeperRecoveryModeFactory(conf, serializer)
(zkFactory.createPersistenceEngine(), zkFactory.createLeaderElectionAgent(this))//資料持久化引擎和leader選舉
case "FILESYSTEM" =>
val fsFactory =
new FileSystemRecoveryModeFactory(conf, serializer)
(fsFactory.createPersistenceEngine(), fsFactory.createLeaderElectionAgent(this))
case "CUSTOM" =>
val clazz = Utils.classForName(conf.get("spark.deploy.recoveryMode.factory"))
val factory = clazz.getConstructor(classOf[SparkConf], classOf[Serializer])
.newInstance(conf, serializer)
.asInstanceOf[StandaloneRecoveryModeFactory]
(factory.createPersistenceEngine(), factory.createLeaderElectionAgent(this))
case _ =>
(new BlackHolePersistenceEngine(), new MonarchyLeaderAgent(this))
}
persistenceEngine = persistenceEngine_
leaderElectionAgent = leaderElectionAgent_
4、persistEngine中有一個至關重要的方法persist來實現資料持久化,readPersistedData來回複叢集中的中繼資料;
/**
* Returns the persisted data sorted by their respective ids (which implies that they‘re
* sorted by time of creation).
*/
final def readPersistedData(
rpcEnv: RpcEnv): (Seq[ApplicationInfo], Seq[DriverInfo], Seq[WorkerInfo]) = {
rpcEnv.deserialize { () =>
(read[ApplicationInfo]("app_"), read[DriverInfo]("driver_"), read[WorkerInfo]("worker_"))
}
}
5、FILESYSTEM和NONE均是採用MonarchyLeaderAgent的方式來完成leader的選舉,其實際實現是直接將傳入的Master作為leader
def createLeaderElectionAgent(master: LeaderElectable): LeaderElectionAgent = {
new MonarchyLeaderAgent(master)
}
/** Single-node implementation of LeaderElectionAgent -- we‘re initially and always the leader. */
private[spark] class MonarchyLeaderAgent(val masterInstance: LeaderElectable)
extends LeaderElectionAgent {
masterInstance.electedLeader()
}
6、NONE根本不需要持久化,為什麼寫了BlockHolePersistenceEngine,裡面啥都沒實現?代碼結構統一,且易擴充;
private[master] class BlackHolePersistenceEngine extends PersistenceEngine {
override def persist(name: String, obj: Object): Unit = {}
override def unpersist(name: String): Unit = {}
override def read[T: ClassTag](name: String): Seq[T] = Nil
}
==========Master HA的內部工作機制(主要Zookeeper)============
1、Zookeeper自動從Standby Master裡面選取出作為Leader的Master;
2、使用ZookeeprPersistEngine去讀取叢集的狀態資料Workers、Drivers、Applications、Executors 等資訊;
3、判斷中繼資料資訊是否有空的內容;
4、把通過Zookeeper持久化引擎獲得的Workers、Drivers、Applications、Executors 等資訊重新註冊到Master的記憶體中緩衝起來;
5、驗證獲得的資訊和當前正在啟動並執行叢集的狀態的一致性;
6、將Applications和Workers的狀態標識為UNKOWN,然後會向Application中的Driver以及Worker發送現在是Leader的standby模式的Master的地址資訊;
7、當Drivers以及Workers收到新的Master地址資訊後,會響應改資訊;
8、Master接收到來自Drviers和Workers的響應資訊後,會使用一個關鍵的方法completeRecovery,對沒有響應的Applications(Drivers)、Workers(Executors)進行處理,Master的state會變成RecoveryState.ALIVE ,從而可以開始對外服務
private def completeRecovery() {
// Ensure "only-once" recovery semantics using a short synchronization period.
if (state != RecoveryState.RECOVERING) { return }
state = RecoveryState.COMPLETING_RECOVERY
// Kill off any workers and apps that didn‘t respond to us.
workers.filter(_.state == WorkerState.UNKNOWN).foreach(removeWorker)
apps.filter(_.state == ApplicationState.UNKNOWN).foreach(finishApplication)
// Reschedule drivers which were not claimed by any workers
drivers.filter(_.worker.isEmpty).foreach { d =>
logWarning(s"Driver ${d.id} was not found after master recovery")
if (d.desc.supervise) {
logWarning(s"Re-launching ${d.id}")
relaunchDriver(d)
} else {
removeDriver(d.id, DriverState.ERROR, None)
logWarning(s"Did not re-launch ${d.id} because it was not supervised")
}
}
state = RecoveryState.ALIVE
schedule()
logInfo("Recovery complete - resuming operations!")
}
d.desc.supervise此種方式在Drvier失敗後重啟Drvier
9、(關鍵一步)此時Master調用自己的scheduler方法對正在等待的Applications和Drviers進行資源調度!!!
650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" />
本文出自 “一枝花傲寒” 部落格,謝絕轉載!
Master HA徹底解密(DT大資料夢工廠)