背景
近五年,大數據、資料科學、機器學習與人工智慧熱潮將 Python 這個語言推向高峰,但不論是上述的那哪一項領域,都脫離不了大量的運算需求。另一方面,從 2000 年以降的十餘年間,分散式運算技術已經足夠成熟到成為當今解決大量運算問題的主流,如最具代表性的 Hadoop、當紅炸子雞 Spark,與串流處理代表 Storm…還有各種新的競爭對手如kafka stream、flink、Tez、Apex…,然而,這些主流分散式運算系統幾乎無一例外建構於 JVM 與 JVM 語言之上…
python社群目前有沒有相對應的分散式運算系統呢?首先,我們不是在討論GIL多線程與多進程的問題。再來,上面的答案是零。
其實不單單是python,放眼目前所有語言,目前沒有任何語言在此領域是JAVA的對手。將條件放寬一點,專注於平行運算相關的有blaze ecosystem、ipyparallel、dispy、SCOOP、mpi4py…這些專案如果作為一般單次性運算工具或是純粹科學運算可以滿足需求,然而在作為一個可能拿來上線,在上面運行大量應用程式的系統,可能用Celery來處理還比較讓人安心一些(沒有任何對這些專案不敬的意思,用途不同)。
這是一個令人沮喪的現實,但其實也沒有必要,就像沒有人會試圖拿JAVA取代C在系統語言的地位,python也不需要重造輪子,相反的,研究如何在既有成熟方案上建構python應用程式,或許是較為務實的作法,而潮流確實也如此。
超越開發的應用程式
如何讓 Python 語言能更有效利用既有分散式運算系統,湧現許多解決方案,像是storm藉由thrift實現多語言協議,而最著名的就是Spark率先做出官方 Python API,接著Heron、Flink、Apache Beam也都逐漸推出Python API;然而即使是最熱愛Spark的開發者也不得不承認,即使Pyspark已經足夠成熟,當要走入上線環境(Production Environment),還有許多額外前置作業要手動處理,事實上,這些所謂的手動處理經常困擾著我們。
所以,困難在哪裡?思考部署一個python應用程式在一個有100台主機的分散式運算叢集上,你需要先解決以下問題:
- 虛擬環境(virtualenv)隔離與第三方套件(3rd party packages)引用
- 測試(testing)
- 共用上下文(shared context)
虛擬環境隔離第三方套件引用
最令python社群自豪的,莫過於背後龐大、高品質且涵蓋各領域的第三方套件,這些套件是如此成熟,以至於幾乎被當作領域內的標準庫使用,如資料科學的numpy、pandas、mathplotlib…,你需要額外手動引入這些套件,對於單台主機這或許不算什麼,然而在擁有100台主機分散式運算系統內,事情就不再那麼簡單了。
知名Hadoop廠商Cloudera對此有一個近乎暴力的解決方法,提供一鍵為叢集節點安裝Anaconda —最受歡迎的python科學運算集成版本(筆者沒有對內部機制作深入研究);然而,如果我們同時需要兩個版本的python怎麼辦?python 2.7可說是最受歡迎的python版本,即使PSF早已宣佈2020年python2不再維護,但是事實上,在五到十年內依舊會存在為數眾多運行在python2的應用程式(centos7使用python2.7.5,維護更新直到2024年)。
更深入來看,對於開發應用程式而言,開發者早已將隔離專案環境習以為常,python習慣使用virtualenv+pip打造開發環境,在Java的世界裡,他們使用JRE與Maven,這些奠基於JVM的分散式運算系統對此此有一套專門處理流程,但是如果你是使用python開發,很抱歉,你可能得自己造輪子。
測試
你知道什麼比測試應用程式更可怕嗎?測試分散式應用程式。
前幾年,有一個名為Jepsen的分散式測試框架,把各大著名的分散式系統全都踢館了一輪,抓出一堆bug,一戰成名。事實上,測試分散式系統的確不容易,許多問題甚至根本沒跳出異常,整個運算系統跑了三個月,突然就被Linux OOM給砍了,到底這帳該算在應用程式,還是Spark,還是HDFS、還是Zookeeper、還是Linux系統、還是那條秀斗的網路線上?在分散式系統底下,連要找個問題都比較困難。
這時候,如果你是用python寫應用程式,恭喜你,連要寫個測試都比較麻煩,更別提要測出問題。
共用上下文
共用上下文又可以被稱為全局狀態,如何在分散式運算系統間,存取一致的狀態是一項難題,不同分散式系統也都有各自實現方法,幸運的是,如果你使用的系統有提供官方PYTHON API,通常它都已經極小化共用上下文複雜性,至少當不小心被OOM掉時,還可以比較不要臉地跟上司說是系統太爛。
如果不幸的沒有官方API,在效能要求不高情況下,一個外部的儲存體經常是最快速的解決方案,像是redis就很適合作為這種臨時快速查詢的所在;但是當叢集持續擴大時,外部儲存體經常還是會成為瓶頸所在。
python困境的黎明?
嚴格來說,這些問題都不是無法解決的,只是還需要更多時間成熟,形成最佳實踐或集成到系統內部,就如同python近幾年來非同步(asyncio)標準庫的發展一樣。像是Pyspark、Streamparse都在持續進行開發,我們有理由相信分散式系統會逐漸類似過往的基礎系統一樣,逐漸解開語言的束縛。
延伸閱讀
深度探索分布式系统测试 https://zhuanlan.zhihu.com/p/24467744
Best Practices Writing Production-Grade PySpark Jobs https://developerzen.com/best-practices-writing-production-grade-pyspark-jobs-cb688ac4d20f