蝦皮購物是一家服務臺灣、印尼、越南等7個東南亞市場的電商平臺,涵蓋了從C2C拍賣、B2C購物到B2B2C商城等多種業務。從2015年開始上線到如今成為區域性的最大電商平臺,蝦皮的系統架構在這段期間承受住了使用者和訂單火箭般地飛速成長,也伴隨著很多痛並快樂的煩惱。而這些煩惱中,有相當一部分就與蝦皮使用的各種各樣的開源軟體相關。
在負載均衡器領域,F5、A10和AWS的ELB就是非常出名的商業產品。F5和A10都是基於硬體提供的負載均衡,AWS的ELB則是基於軟體。對於F5和A10這種硬體產品來說,一般採購它們的產品的時候是有一定規格和處理能力上限的,且1Gbps和10Gbps有不同的價格,而蝦皮的流量增長又特別快,假設我們這個月買了一臺1Gbps的F5或A10,過不了多久就會因為當前的F5或A10撐不住而要買另一臺更高規格的來進行升級。而且更麻煩的是,像這些硬體負載均衡器的升級只能是替換成更高階的裝置,且升級的過程會造成相當長的一段時間無法訪問網站。而像某些雲服務提供商的負載均衡方案,我們使用它的時候就完全無法撐住蝦皮的海量請求,當雲服務發生問題時我們完全束手無策。這些雲服務對我們來說是一個黑盒子,裡面程式碼到底是如何執行的,我們完全不瞭解,當遇到問題需要解決的時候,我們需要提ticket,來回溝通的週期特別長,至少都要好幾個星期,而我們對服務的可用性要求有特別高,任何時候有問題,都需要第一時間立刻恢復服務,使用商業產品對我們來說,就不得不面對這樣那樣的矛盾。
所以我們最終是基於LVS和Nginx這樣的開源軟體開發了我們自己的負載均衡系統,相比商業產品,開源軟體的程式碼開放,社群使用者參與活躍,我們參與到其中去,一方面可以基於開源軟體開發出更符合蝦皮業務場景的系統並快速定位和修復問題,另一方面也能在向上遊報BUG,修復BUG的過程中和開源社群一起成長,從而更好地支撐業務的發展,保障蝦皮的使用者體驗。
從今天來看,我們再看看蝦皮到底是使用了Redis還是使用了Memcached。答案是我們都用。蝦皮是由很多不同的分散式系統和服務組成,有不同的場景和業務要求,有些場景用Redis非常合適,直接使用一個Redis自帶的命令就可以解決;有些場景用Memcached就更合適,比方說上面提到的那個例子;有些場景則可以直接上Redis Cluster的方式來繞過Redis單Instance時只能用一個CPU的限制。
在蝦皮的各種不同系統中,從前端到後臺,從資料庫到作業系統,我們使用了大量不同的開源軟體。很多時候並不是非此即彼,用了A就不用B,用了B就不用A。每種開源軟體都有其適合的場景,也有其相對應的優缺點。只要能解決問題,都值得使用嘗試和使用。像Redis和Memcached一樣,他們都是非常優秀的Cache,又有各自適合的場景,對我們來說,都值得使用和學習。
對我們來說,如果使用一個開源軟體,而我們卻不瞭解它內部是如何工作,出問題毫無解決頭緒,無法基於已有的開原始碼做二次修改的話,還不如直接使用相應的商業解決方案,至少商業解決方案有專業支援。比方說Ceph這個分散式檔案儲存系統,蝦皮在使用的過程中,就經常因為各種各樣的原因踩到Ceph的坑,但是Ceph這個分散式的檔案儲存對我們而言又非常重要,每次Ceph出問題都會導致我們的系統當機很長時間,客服人員電話會被海量的使用者投訴打爆,造成非常嚴重的後續影響。這逼著我們不斷地閱讀和熟悉Ceph的各個元件和程式碼,逐漸地糾正之前使用Ceph的錯誤方式,patch相關的地方以便故障時能快速恢復。
而隨著蝦皮使用者量和業務量的不斷增長,很多之前可能是正常工作的開源軟體到了某個瓶頸之後就無法再正常工作。這也讓我們對了解開源軟體的程式碼和內部實現有了更高要求,需要我們能即時定位到效能瓶頸。比方說我們使用Nginx,在過去三年中一直執行的非常穩定,突然前幾天就出現把所有CPU Core跑滿的問題。所幸在過去幾年中,我們基於Nginx的原始碼做了大量工作,對Nginx的程式碼比較熟悉,這次就很快定位到了是一處shared memory lock競爭導致的效能衰退。
蝦皮對這些開源軟體的修改,我們一般會根據實際情況把這些patch提交回上游merge。像Linux Kernel、Docker、Tensorflow等等開源專案中都有蝦皮工程師提交的patch。當然也存在這樣的情況,改動的地方上游覺得不夠好,或者有其他解決方案拒絕或者推遲了我們的patch,或者merge和review的速度非常慢。這個時候可以fork出一個版本,當然也保持開源,這樣其他人如果遇到了和我們一樣的問題的時候,參考我們的改動,也會對他們帶來一定啟發。參與開源社群有很多中方式,不一定提交patch並merge才算,報BUG是一種方式,改進使用說明資料是一種方式,fork出另外的分支也是一種方式,最終都能在開源社群相互交流,共同進步。
同樣的,在考量解決方案的時候,我們會先看看是否已有開源的方案能解決我們的需求,如果有的話,已有的開源方案是否足夠成功,設計足夠好,執行是否足夠穩定,如果不成熟的話,我們是否可以在這個基礎上,在上面再開發改進。如果整個開源軟體設計優秀,很容易擴充套件和改進,和我們期望的解決方案比較匹配,那麼我們就會採用,一方面節約了資源的投入,同時又能少走一些彎路,而且開源社群不止蝦皮,很多組織都在參與,在整個生態系統中,每個參與的團體做的改進其他團體都能受益。
但也存在開源社群中我們無法找到相對應的實現或者滿足我們要求的實現的情況,這個時候我們會自行研發解決方案。大家知道像蝦皮支援的業務型別非常多,對核心系統和元件有各種各樣的業務要求以及效能上的考量,在廣泛使用開源軟體的同時,蝦皮也有大量自行研發的元件,共同支撐了業務的飛速成長。
蝦皮成立三年來業務飛速成長,離不開各種優秀的開源專案,也在不斷地回饋開源社群,如果你熱愛開源,熱愛Coding,就快快加入我們一起共同成長吧。心動不如馬上行動,火速開啟 https://careers.shopee.com/ 投遞簡歷吧!
開源軟體還是商業產品?
很多開源軟體都有對應的商業產品,蝦皮從誕生的第一天起,就經常面臨是使用開源軟體方案還是商業產品方案的選擇。舉個例子來說,像大家開啟蝦皮的時候,所有的請求流量會發到蝦皮的負載均衡器,負載均衡器會做按照預先定義的規則做各種各樣的處理,包括服務發現、動態路由、健康檢查、熔斷、故障轉移等等。大家可以想下,因為所有流量都會經過這樣的一個負載均衡的系統,所以我們對它的效能、可用性、可拓展性的要求就非常高。在負載均衡器領域,F5、A10和AWS的ELB就是非常出名的商業產品。F5和A10都是基於硬體提供的負載均衡,AWS的ELB則是基於軟體。對於F5和A10這種硬體產品來說,一般採購它們的產品的時候是有一定規格和處理能力上限的,且1Gbps和10Gbps有不同的價格,而蝦皮的流量增長又特別快,假設我們這個月買了一臺1Gbps的F5或A10,過不了多久就會因為當前的F5或A10撐不住而要買另一臺更高規格的來進行升級。而且更麻煩的是,像這些硬體負載均衡器的升級只能是替換成更高階的裝置,且升級的過程會造成相當長的一段時間無法訪問網站。而像某些雲服務提供商的負載均衡方案,我們使用它的時候就完全無法撐住蝦皮的海量請求,當雲服務發生問題時我們完全束手無策。這些雲服務對我們來說是一個黑盒子,裡面程式碼到底是如何執行的,我們完全不瞭解,當遇到問題需要解決的時候,我們需要提ticket,來回溝通的週期特別長,至少都要好幾個星期,而我們對服務的可用性要求有特別高,任何時候有問題,都需要第一時間立刻恢復服務,使用商業產品對我們來說,就不得不面對這樣那樣的矛盾。
所以我們最終是基於LVS和Nginx這樣的開源軟體開發了我們自己的負載均衡系統,相比商業產品,開源軟體的程式碼開放,社群使用者參與活躍,我們參與到其中去,一方面可以基於開源軟體開發出更符合蝦皮業務場景的系統並快速定位和修復問題,另一方面也能在向上遊報BUG,修復BUG的過程中和開源社群一起成長,從而更好地支撐業務的發展,保障蝦皮的使用者體驗。
使用開源軟體 A 還是使用開源軟體 B?
對開源軟體來說,即使是同一類別,可能也會有很多不同的選擇。比方說Cache,常見的就有Memcached和Redis。在蝦皮早期的時候,我們就經常遇到Redis CPU跑滿的問題。我們使用profiling工具一查,發現當用戶請求湧進來的時候,我們的服務短時間建立了大量地連線到Redis,而Redis是單執行緒,只能使用一個CPU Core,導致Redis都在處理連線的建立和斷開,正常的Cache讀寫都無法處理,最終導致服務處理請求時大量超時報錯。那時我們為了避免Redis的CPU跑滿的問題,就換用成是多執行緒模型的Memcached。換了Memcached後效果立竿見影,CPU使用都均攤到了每個CPU Core,非常均衡。當然換成Memcached也帶來了一些不方便的地方,因為Memcached不像Redis一樣支援豐富的不同的資料結構和讀寫命令,中間對系統的改造確實是一個相當痛苦的過程。從今天來看,我們再看看蝦皮到底是使用了Redis還是使用了Memcached。答案是我們都用。蝦皮是由很多不同的分散式系統和服務組成,有不同的場景和業務要求,有些場景用Redis非常合適,直接使用一個Redis自帶的命令就可以解決;有些場景用Memcached就更合適,比方說上面提到的那個例子;有些場景則可以直接上Redis Cluster的方式來繞過Redis單Instance時只能用一個CPU的限制。
在蝦皮的各種不同系統中,從前端到後臺,從資料庫到作業系統,我們使用了大量不同的開源軟體。很多時候並不是非此即彼,用了A就不用B,用了B就不用A。每種開源軟體都有其適合的場景,也有其相對應的優缺點。只要能解決問題,都值得使用嘗試和使用。像Redis和Memcached一樣,他們都是非常優秀的Cache,又有各自適合的場景,對我們來說,都值得使用和學習。
如何正確使用開源軟體和參與開源社群?
在蝦皮,我們使用開源軟體都是當成白盒子來使用。使用開源軟體,意味著也要承擔開源軟體中存在的BUG帶來的風險。在最開始的選型時,我們會去提前瞭解每個開源軟體的內部實現和評估潛在的問題,從而避免使用了不合適的開源軟體,最終折返重頭開始的情況。在使用過程中,遇到問題時和社群保持溝通,修復BUG並回饋patch給社群。對我們來說,如果使用一個開源軟體,而我們卻不瞭解它內部是如何工作,出問題毫無解決頭緒,無法基於已有的開原始碼做二次修改的話,還不如直接使用相應的商業解決方案,至少商業解決方案有專業支援。比方說Ceph這個分散式檔案儲存系統,蝦皮在使用的過程中,就經常因為各種各樣的原因踩到Ceph的坑,但是Ceph這個分散式的檔案儲存對我們而言又非常重要,每次Ceph出問題都會導致我們的系統當機很長時間,客服人員電話會被海量的使用者投訴打爆,造成非常嚴重的後續影響。這逼著我們不斷地閱讀和熟悉Ceph的各個元件和程式碼,逐漸地糾正之前使用Ceph的錯誤方式,patch相關的地方以便故障時能快速恢復。
而隨著蝦皮使用者量和業務量的不斷增長,很多之前可能是正常工作的開源軟體到了某個瓶頸之後就無法再正常工作。這也讓我們對了解開源軟體的程式碼和內部實現有了更高要求,需要我們能即時定位到效能瓶頸。比方說我們使用Nginx,在過去三年中一直執行的非常穩定,突然前幾天就出現把所有CPU Core跑滿的問題。所幸在過去幾年中,我們基於Nginx的原始碼做了大量工作,對Nginx的程式碼比較熟悉,這次就很快定位到了是一處shared memory lock競爭導致的效能衰退。
蝦皮對這些開源軟體的修改,我們一般會根據實際情況把這些patch提交回上游merge。像Linux Kernel、Docker、Tensorflow等等開源專案中都有蝦皮工程師提交的patch。當然也存在這樣的情況,改動的地方上游覺得不夠好,或者有其他解決方案拒絕或者推遲了我們的patch,或者merge和review的速度非常慢。這個時候可以fork出一個版本,當然也保持開源,這樣其他人如果遇到了和我們一樣的問題的時候,參考我們的改動,也會對他們帶來一定啟發。參與開源社群有很多中方式,不一定提交patch並merge才算,報BUG是一種方式,改進使用說明資料是一種方式,fork出另外的分支也是一種方式,最終都能在開源社群相互交流,共同進步。
蝦皮自研軟體和開源的關係?
在蝦皮,我們廣泛使用了各種各樣的開源專案,但我們也有非常多的核心元件是自行研發。對蝦皮來說,自研和開源並不是對立的,並不是蝦皮自己喜歡重新發明輪子。我們知道,就算是輪子,也分很多種,比方說自行車的輪子和跑車的輪子要求就不一樣,而飛機的輪子又和跑車的輪子要求不同。有些時候,開源社群可能只能找到自行車的輪子,那假設蝦皮要開始造飛機了,在開源社群裡面找不到飛機輪子的實現,那麼沒辦法,我們只能自行研發。同樣的,在考量解決方案的時候,我們會先看看是否已有開源的方案能解決我們的需求,如果有的話,已有的開源方案是否足夠成功,設計足夠好,執行是否足夠穩定,如果不成熟的話,我們是否可以在這個基礎上,在上面再開發改進。如果整個開源軟體設計優秀,很容易擴充套件和改進,和我們期望的解決方案比較匹配,那麼我們就會採用,一方面節約了資源的投入,同時又能少走一些彎路,而且開源社群不止蝦皮,很多組織都在參與,在整個生態系統中,每個參與的團體做的改進其他團體都能受益。
但也存在開源社群中我們無法找到相對應的實現或者滿足我們要求的實現的情況,這個時候我們會自行研發解決方案。大家知道像蝦皮支援的業務型別非常多,對核心系統和元件有各種各樣的業務要求以及效能上的考量,在廣泛使用開源軟體的同時,蝦皮也有大量自行研發的元件,共同支撐了業務的飛速成長。
蝦皮成立三年來業務飛速成長,離不開各種優秀的開源專案,也在不斷地回饋開源社群,如果你熱愛開源,熱愛Coding,就快快加入我們一起共同成長吧。心動不如馬上行動,火速開啟 https://careers.shopee.com/ 投遞簡歷吧!
留言