天天看點

zeppelin源碼分析(0)——zeppelin要解決什麼問題

通過我其他的zeppelin分析文章,大家可以從中了解zeppelin是什麼樣的。本篇試着闡述問題的另外一面,zeppelin為什麼是這樣的?本文從需求出發,探尋zeppelin的架構設計、技術選型、代碼的子產品劃分和依賴關系最初的“出發點”。

zeppelin的核心功能用一句話總結就是:支援多語言混合的REPL(Read-Evaluation-Print-Loop)。這個核心功能的價值展現在:

站在使用者的角度,意味着:

1. 可以在一個Note中混合使用多種語言。使用者可以根據需要完成的任務的類型,選擇最合适的語言來實作,不再受限于單個語言的特性。例如:MarkDown能做出漂亮的文檔,python和R有大量的科學計算、機器學習和可視化包,scala與Spark有天然的血緣關系,Shell處理本地檔案非常友善……,可以想象一下将這些語言的優點都結合起來,會産生多麼強大的生産力。

2. 資料分析和機器學習,從來都不是一個“一蹴而就”的過程。分析過程和機器學習算法一樣,本質是不斷疊代和試錯的過程。資料科學家和算法工程師對資料分析平台最看中的能力是“有豐富的元件”和“可調試”(至少在我接觸到的資料科學家和算法工程師來看是這樣的),前者表達了對平台功能全面的需求,後者表達了如何對采用這些功能“平順”地開展實際業務分析的需求,二者相輔相成。REPL相對于“拖拽式”的資料分析平台,雖然不能像傳統IDE一樣,設定斷點和檢視中間變量,但是相對于“純黑盒”的拖拽式資料分析工具,能在很大程度上實作“調試”功能。

站在管理者的角度,意味着:

1. 使得統一工具環境成為可能。一個資料分析團隊中,各成員由于擅長的語言不同,可能需要同時維護多種環境,如R、Python遠端桌面開發環境,R和Python都是通過第三方擴充包進行擴充的,成員熟練使用的包,也有所不同,給運維造成了較大壓力。實作一個集中式的分析工具,在服務端集中于一處,統一配置R、Python、Spark、Hadoop、Hive等開發環境,顯著降低運維成本。

2. 使得進行統一安全控制成為可能。B/S系統,友善進行集中式使用者權限控制,并且由于該平台”看到”的是各種語言的源碼,可以對惡意代碼進行監測和過濾,避免有意或者無意地對系統造成的損害。此外,可以限制所有過程都線上操作,不存在跨機器傳遞資料的問題,可限制導出資料,保障資料安全。

現在,讓我們抛開對zeppelin的已有認知,假設讓我們重新設計一個平台,實作上述核心功能,會面臨哪些問題,這些問題都有哪些解決方案,各種方案又孰優孰劣,在此過程中,探尋zeppelin的設計動因和它要解決的問題。

首先看一下該平台要應對的典型場景:

zeppelin源碼分析(0)——zeppelin要解決什麼問題

平台要解決的是:在服務端資源一定的情況下,如何盡可能正确和高效地執行多個使用者混合了多種語言的Notes問題。

由于我們要實作IPython Notebook式的B/S架構的共享式的分析工具,是以至少需要一台Web伺服器。一般zeppelin典型的使用方式是與spark一起使用,而spark on Yarn又是常見的spark部署方式,是以,上圖就是生産環境下,zeppelin部署時的最小配置。确定了部署方式,軟體設計問題會接踵而至,每種問題的解決都影響的該平台技術的選型和架構的設計:

  1. 各種語言的代碼在哪裡執行?

    代碼的執行是會消耗伺服器資源的,資源是共享的,有限的,合理的配置設定代碼的執行環境,對平台的擴充能力至關重要。 在有web伺服器的前提下,顯然不會每個使用者直接連接配接spark叢集,送出任務(否則,就退化成了每個使用者在本地啟動一個spark-shell了,這也就是失去了集中共享式資料分析平台建設的意義),web伺服器自然成了spark叢集唯一的用戶端,所有使用者的任務都間接通過web伺服器向spark叢集送出。但是,并不是所有語言寫的代碼都需要送出的spark叢集上執行,各種不同的語言的代碼“理想”的執行位置如下:

語言 單機/叢集 代碼在哪裡執行
R 單機 web伺服器
R(SparkR) 叢集 Spark叢集
Python 單機 web伺服器
Python(PySpark) 叢集 Spark叢集
MarkDown 單機 web伺服器
SQL(SparkSQL) 叢集 Spark叢集
SQL(其他SQL) 單機 web伺服器
Shell 單機 web伺服器

通過上表可以看出:

1. Spark叢集有自己獨立的資料總管Yarn。任務的排程和資源的配置設定都有該資料總管接管,這裡不讨論。

2. 還有大量的語言代碼,是在Web伺服器本地執行的。一台Web伺服器的資源是有限的,會成為限制該平台橫向擴充的瓶頸。這就有必要在web伺服器端,對使用者執行代碼的頻率進行限制,如進行排隊。或者将代碼的執行環境從web伺服器端抽取出來,額外建立一個叢集(這個叢集與Spark叢集不同),該叢集的目的很單一,就是執行web伺服器發過來的各種語言的代碼。它可以是“無中心”節點的方式,各自向Web伺服器報告,或者是類似Yarn叢集的方式,隻不過擷取到的container專門用來執行一段代碼。

  1. multi-tenancy支援問題

    多使用者系統,每個使用者建立的note,每個note執行的結果,都應該是屬于該使用者的。其他使用者未經授權不能通路。

    repl解釋器應該至少實作各個使用者之間隔離,因為repl解釋器是執行過程中會儲存context,即:之前定義的變量或者routine等,能夠直接檢視和使用,但是一般情況下,repl解釋器不應該被共享,否則,就會出現兩個使用者互相影響的情況。那麼問題來了,同一個使用者不同的note,含有相同語言的代碼,可以共享同一個repl解釋器嗎?這個問題抽象出來,就是repl解釋器粒度問題,是per-user還是per-note的問題,2者各有優劣:

  1. per-user模式,節省資源,同一個使用者不同note之間的相同語言的代碼都可以發送到同一個解釋器,節省伺服器資源。由于解釋器同時保留多個代碼段執行的上下文,這種模式可以實作跨note交換資料。同時,由于多個note共用一個repl解釋器,解釋器比較繁忙,使用者的響應時間變長。
  2. per-note模式,耗費伺服器資源,但是代碼執行速度塊,使用者體驗好。

平台應該将選擇權交給使用者,提供靈活的配置功能。

  1. Note中paragraph執行的順序問題

    并發還是順序執行?其實答案不是個0/1問題,而是要視代碼是否具有上下文相關性而定。

    zeppelin源碼分析(0)——zeppelin要解決什麼問題

上圖是Note内部構成邏輯圖,一個Note由一系列paragraph(代碼段)組成,代碼段有序的。每個代碼段隻能使用一種語言,但是不同paragrah的語言可以各不相同。理想情況下,所有的代碼都并行執行,以期望獲得最高的執行效率,但是實際上由于大部分語言的前後代碼之間存在上下文相關性,一般情況下是不能并行的。各語言代碼段之間能否并行如下表所示:

語言 是否能并行 解釋&示例
R 存在執行順序相關性,如:前面定義的變量後面才能使用
Python 同上
Spark 同上
Shell 同上,如:隻有目錄存在了,才能往裡面放檔案
SQL 存在執行順序相關性,DDL、DML語句會互相影響,如必須先create table才能insert資料
MarkDown 上下文無關,一段MarkDown可以獨立與其他MarkDown代碼獨立渲染

可以看出,除了MarkDown之外,其他代碼都是不能并發執行的。當然,不存在上下文相關性的時候,是可以并行的。例如SQL語句,在table和資料都已經存在的前提下,2條select語句是可以并發執行的。

需要提供每個repl解釋器級别的并發設定,在分析師人工檢查代碼後,能夠确定并發執行的代碼,能夠顯式啟用該設定,以提高速度。

  1. 相同的repl解釋器不同的runtime依賴的問題

    一個典型的場景是支援同一個産品的不同版本。隻要該産品的public API不改變,通過配置修改該repl解釋器的運作時依賴,就可以實作代碼不變,支援多個版本的能力。

    另一個典型的場景是JDBC repl解釋器,使用的都是SQL語句,但是背景配置不同的連接配接就通路不同的庫,可以是RDBMS也可以是NoSQL,每次解釋器啟動的時候,都要根據需要加載不同的runtime依賴,以完成Driver的加載、connection的擷取以及SQL語句的執行。這要求repl解釋器具有運作時動态查找、下載下傳并加載依賴的能力。目前maven基于GAV(Group、Artifact、Version)坐标和公共repo的方式唯一定位依賴,并自動下載下傳的方式,已經成為事實上的标準,故平台需要具有動态加載maven格式依賴包的能力。該問題也引出了下面的問題。

  2. repl解釋器程序管理問題

    由于同一個JVM(這裡不讨論為什麼采用JVM-Based語言的問題)class加載是根據classpath定義的順序決定的,一旦找到就終止查找。這決定了要支援不同的runtime依賴和同一個産品的不同的版本,需要啟動單獨的JVM,以實作依賴的隔離。但是這樣,問題又來了,repl解釋器需要受到平台的控制。我們常用的在作業系統中啟動一個R或者Python的repl程序,該程序的生命周期是隻受作業系統控制的。而本平台要實作的repl解釋器程序需要”受控“,即:其啟動、停止、解釋執行代碼、輸出回報等過程都要在平台的控制下程序,以實作自動化repl程序控制,同時避免資源洩露。

    再者,不同語言的repl程序,如何與JVM-Based的平台的程序進行跨語言通信,也是需要考慮的問題。常見的IPC(Inter-Process-Communication)機制,Shared-Memory、Pipe、Socket,這三種中,考慮到未來支援repl解釋器叢集化部署,基于Socket的實作方式是适應性最好的。平台需要确定一種IPC通信協定,規定repl解釋器內建和平台之間的資料交換的格式和時序。

    此外,盡可能複用多種語言的repl程序的生命周期控制邏輯,實作通用的控制,避免增加repl解釋器擴充開發的工作量。

上述需求,是zeppelin的核心需求,zeppelin都給出了相應的解決方案:

需求 zeppelin的解決方案
代碼在哪裡執行 單機版的R和Python,在Web伺服器上執行,SparkR和PySpark在spark叢集上執行。在zeppelinServer端進行進行排程和排隊,對代碼解釋任務進行限流。遠端啟動repl程序到另外的節點上,zeppelinServer端可直接基于Socket連接配接到該repl解釋器程序上,一定程度上解決在web伺服器成為橫向擴充瓶頸的問題。
multi-tenancy支援 Shiro-Based Authentication,Per-User/Per-Note兩種mode的repl解釋器程序共享方式,生命周期受控的多repl解釋器程序。
Note中paragraph執行的順序 在repl解釋器級别,可配置是否運允許并行執行。某些特殊的repl解釋器還支援配置并發數,如JDBC。
“相同的repl解釋器不同的runtime依賴的問題”&“repl解釋器程序管理問題” 多JVM隔離runtime依賴。Thrift-Based跨語言IPC機制。抽象出repl解釋器生命周期管理接口,各repl解釋器受zeppelinServer端控制。

圍繞着上述核心功能,zeppelin還需要提供如下“外圍功能”:

  • 友善擴充的解釋器接口設計

    顯然,一個大資料分析工具,隻有建立起良好的生态圈,才能保證長久的生命力。zeppelin顯然不想隻支援有限的幾種語言的repl解釋器。提供定義良好接口,支援二次開發,是必備項。

  • 一種将背景解釋器程序的輸出格式化到前端UI的能力

    前面提到了python和R有大量可視化包,将這些後端輸出,發送到前端,前後端一緻,就跟使用者在自己本機打開R和python repl程序一樣,也是一必備項。當然,還提供格式化普通文本為表格的能力。

  • 配置化能力

    将編譯時常量變為運作時常量,抽取出來,配置檔案化,可以顯著提高的系統的可移植性。Hadoop生态系統大部分産品,都有xxx-default.xml和xxx-site.xml這樣靈活的配置系統,zeppelin也具備這種能力。

  • 前端實時回報能力

    大資料分析,最痛苦的事情莫過于“代碼跑了很長時間,最後程式挂了”。在大資料處理過程中,實時地回報執行結果,顯示進度和日志,允許使用者中止正在執行的任務,是易用性的很重要的方面。

  • 持久化能力

    系統所有的配置項目,所有的note代碼和執行結果、權限等,系統重新開機之後,都需要恢複,是以需要持久化。

  • 版本控制

    算法無論以什麼語言表達,都是代碼,是代碼就避免不了版本演化問題。zeppelin對note的持久化 方式,決定了進行版本控制的難易程度,純文字方式,則便于版本控制實作;二進制方式,則版本控制中進階特性,如版本比對,merge以及沖突解決,會很困難。

  • Note共享平台

    zeppelin自身是個工具,使用該工具做出來的面向各個行業的Note,才會産生外在價值。zeppelin官方推出的zeppelinhub代碼分享平台,将廣大zeppelin使用者分享的note進行分門别類的整理,試圖建構一個從工具到行業應用,不斷回報、改進、推廣的良性的生态圈。

一些zeppelin不具備的能力(并不是完全沒有,有些實作起來比較蹩腳)。

  1. 叢集化部署

    interperter Process已經成為制約zeppelin橫向擴充的瓶頸問題。如何優雅地在多個節點上動态分布interpreter程序,并且保持zeppelin與這些程序之間的通信,是一個亟待解決的問題。目前有一些蹩腳的實作的方式,勉強實作了zeppelin的叢集化部署,但卻不”優雅“。

  2. 安全性問題

    這裡是除了使用者權限以外的安全問題:包括系統安全和資料安全。可以寫代碼,對分析師來講是最靈活的方式,但是對系統開發者來講,要執行使用者輸入的各種代碼,保證系統的穩定,卻是“噩夢”一般。幾行簡單的代碼,就可以讓作業系統資源耗盡。本來可以很“優雅”地表達的代碼,卻被寫地很低效、bug頻出,占用大量的後端資源,使得repl程序遲遲沒有響應。資料是資産,已經成為行業共識,作為一個共享式的大資料分析工具,所有的資料操作必須是線上的,資料資産不能導出。此外,資料的加密和脫敏問題,也屬于此範疇的問題。

繼續閱讀