回覆列表
-
1 # 武漢朝夕教育科技
-
2 # 躬耕篤行
我推薦一個基於spring cloud 外延的一個開源專案,主要是針對企業資訊化方向的,做得比較不錯能開源,支援商用。
開源地址:JVS/jvsgitee.com/software-minister/jvsgitee.com/software-minister/jvs
裡面實現了 SaaS(使用者與租戶的多對多關係)、統一多模式登陸、線上表單配置、線上列表頁配置,線上流程配置,線上圖表配置等等。
作為一個老開發人員,我個人認為在選擇開源專案的時候可以從以下幾個方面考慮考慮!
軟體開發領域有一個流行的原則:DRY,Don’t repeat yourself。翻譯過來更通俗易懂:不要重複造輪子。開源專案的主要目的是共享,其實就是為了讓大家不要重複造輪子,尤其是在網際網路這樣一個快速發展的領域,速度就是生命,引入開源專案可以節省大量的人力和時間,大大加快業務的發展速度,何樂而不為呢?
然而現實往往沒有那麼美好,開源專案雖然節省了大量的人力和時間,但帶來的問題也不少,相信絕大部分技術人員都踩過開源軟體的坑,小的影響可能是宕機半小時,大的問題可能是丟失幾十萬條資料,甚至災難性的事故是全部資料都丟失。
除此以外,雖然 DRY 原則擺在那裡,但實際上開源專案反而是最不遵守 DRY 原則的,重複的輪子好多,你有 MySQL,我有 PostgreSQL;你有 MongoDB,我有 Cassandra;你有 Memcached,我有 Redis;你有 Gson,我有 Jackson;你有 Angular,我有 React……總之放眼望去,其實相似的輪子很多!相似輪子太多,如何選擇就成了讓人頭疼的問題了。
怎麼辦?完全不用開源專案幾乎是不可能的,架構師需要更加聰明地選擇和使用開源專案。形象點說:不要重複發明輪子,但要找到合適的輪子!但別忘了,如果你開的是保時捷,可別找個拖拉機的輪子。
選:如何選擇一個開源專案
1. 聚焦是否滿足業務
架構師在選擇開源專案時,一個頭疼的問題就是相似的開源專案較多,而且後面的總是要宣稱比前面的更加優秀。有的架構師在選擇時有點無所適從,總是會擔心選擇了 A 專案而錯過了 B 專案。這個問題的解決方式是聚焦於是否滿足業務,而不需要過於關注開源專案是否優秀。
Tokyo Tyrant 的教訓在開發一個社交類業務時,我們使用了 TT(Tokyo Tyrant)開源專案,覺得既能夠做快取取代 Memcached,又有持久化儲存功能,還可以取代 MySQL,覺得很強大,於是就在業務裡面大量使用了。但後來的使用過程讓人很鬱悶,主要表現為:
功能上看起來很高大上,但相應的 bug 也不少,而且有的 bug 是致命的。例如所有資料不可讀,後來是自己研究原始碼寫了一個工具才恢復了部分資料。
功能確實強大,但需要花費較長時間熟悉各種細節,不熟悉隨便用很容易踩坑。
後來我們反思和總結,其實當時的業務 Memcached + MySQL 完全能夠滿足,而且大家都熟悉,其實完全不需要引入 TT。
簡單來說:如果你的業務要求 1000 TPS,那麼一個 20000 TPS 和 50000 TPS 的專案是沒有區別的。有的架構師可能會擔心 TPS 不斷上漲怎麼辦?其實不用過於擔心,架構是可以不斷演進的,等到真的需要這麼高的時候再來架構重構,這裡的設計決策遵循架構設計原則中的“合適原則”和”演化原則”。
2. 聚焦是否成熟
很多新的開源專案往往都會聲稱自己比以前的專案更加優秀:效能更高、功能更強、引入更多新概念……看起來都很誘人,但實際上都有意無意地隱藏了一個負面的問題:更加不成熟!不管多優秀的程式設計師寫出來的專案都會有 bug,千萬不要以為作者歷害就沒有 bug,Windows、Linux、MySQL 的開發者都是頂級的開發者,系統一樣有很多 bug。
不成熟的開源專案應用到生產環境,風險極大:輕則宕機,重則宕機後重啟都恢復不了,更嚴重的是資料丟失都找不回來。還是以我上面提到的 TT 為例:我們真的遇到異常斷電後,檔案被損壞,重啟也恢復不了的故障。還好當時每天做了備份,於是只能用 1 天前的資料進行恢復,但當天的資料全部丟失了。後來我們花費了大量的時間和人力去看原始碼,自己寫工具恢復了部分資料,還好這些資料不是金融相關的資料,丟失一部分問題也不大,否則就有大麻煩了。
所以在選擇開源專案時,儘量選擇成熟的開源專案,降低風險。
你可以從這幾個方面考察開源專案是否成熟:
版本號:除非特殊情況,否則不要選 0.X 版本的,至少選 1.X 版本的,版本號越高越好。
使用的公司數量:一般開源專案都會把採用了自己專案的公司列在主頁上,公司越大越好,數量越多越好。
社群活躍度:看看社群是否活躍,發帖數、回覆數、問題處理速度等。
3. 聚焦運維能力
大部分架構師在選擇開源專案時,基本上都是聚焦於技術指標,例如效能、可用性、功能這些評估點,而幾乎不會去關注運維方面的能力。但如果要將專案應用到線上生產環境,則運維能力是必不可少的一環,否則一旦出問題,運維、研發、測試都只能乾瞪眼,求菩薩保佑了!
你可以從這幾個方面去考察運維能力:
開源專案日誌是否齊全:有的開源專案日誌只有寥寥啟動停止幾行,出了問題根本無法排查。
開源專案是否有命令列、管理控制檯等維護工具,能夠看到系統執行時的情況。
開源專案是否有故障檢測和恢復的能力,例如告警、切換等。
如果是開源庫,例如 Netty 這種網路庫,本身是不具備運維能力的,那麼就需要在使用庫的時候將一些關鍵資訊透過日誌記錄下來,例如在 Netty 的 Handler 裡面列印一些關鍵日誌。
用:如何使用開源專案
1. 深入研究,仔細測試
很多人用開源專案,其實是完完全全的“拿來主義”,看了幾個 Demo,把程式跑起來就開始部署到線上應用了。這就好像看了一下開車指南,知道了方向盤是轉向、油門是加速、剎車是減速,然後就開車上路了,其實是非常危險的。
Elasticsearch 的案例我們有團隊使用了 Elasticsearch,基本上是拿來就用,倒排索引是什麼都不太清楚,配置都是用預設值,跑起來就上線了,結果就遇到節點 ping 時間太長,剔除異常節點太慢,導致整站訪問掛掉。
MySQL 的案例很多團隊最初使用 MySQL 時,也沒有怎麼研究過,經常有業務部門抱怨 MySQL 太慢了。但經過定位,發現最關鍵的幾個引數(例如,innodb_buffer_pool_size、sync_binlog、innodb_log_file_size 等)都沒有配置或者配置錯誤,效能當然會慢。
你可以從這幾方面進行研究和測試,更詳細的完整方法可以參考專欄特別放送《如何高效的學習開源專案》:
通讀開源專案的設計文件或者白皮書,瞭解其設計原理。
核對每個配置項的作用和影響,識別出關鍵配置項。
進行多種場景的效能測試。
進行壓力測試,連續跑幾天,觀察 CPU、記憶體、磁碟 I/O 等指標波動。
進行故障測試:kill、斷電、拔網線、重啟 100 次以上、切換等。
2. 小心應用,灰度釋出
假如我們做了上面的“深入研究、仔細測試”,發現沒什麼問題,是否就可以放心大膽地應用到線上了呢?別高興太早,即使你的研究再深入,測試再仔細,還是要小心為妙,因為再怎麼深入地研究,再怎麼仔細地測試,都只能降低風險,但不可能完全覆蓋所有線上場景。
Tokyo Tyrant 的教訓還是以 TT 為例,其實我們在應用之前專門安排一個高手看原始碼、做測試,做了大約 1 個月,但最後上線還是遇到各種問題。線上生產環境的複雜度,真的不是測試能夠覆蓋的,必須小心謹慎。
所以,不管研究多深入、測試多仔細、自信心多爆棚,時刻對線上環境和風險要有敬畏之心,小心駛得萬年船。我們的經驗就是先在非核心的業務上用,然後有經驗後慢慢擴充套件。
3. 做好應急,以防萬一
即使我們前面的工作做得非常完善和充分,也不能認為萬事大吉,尤其是剛開始使用一個開源專案,運氣不好可能遇到一個之前全世界的使用者從來沒遇到的 bug,導致業務都無法恢復,尤其是儲存方面,一旦出現問題無法恢復,可能就是致命的打擊。
MongoDB 丟失資料某個業務使用了 MongoDB,結果宕機後部分資料丟失,無法恢復,也沒有其他備份,人工恢復都沒辦法,只能接一個使用者投訴處理一個,導致 DBA 和運維從此以後都反對我們用 MongoDB,即使是嘗試性的。
雖然因為一次故障就完全反對嘗試是有點反應過度了,但確實故障也給我們提了一個醒:對於重要的業務或者資料,使用開源專案時,最好有另外一個比較成熟的方案做備份,尤其是資料儲存。例如,如果要用 MongoDB 或者 Redis,可以用 MySQL 做備份儲存。這樣做雖然複雜度和成本高一些,但關鍵時刻能夠救命!
改:如何基於開源專案做二次開發
1. 保持純潔,加以包裝
當我們發現開源專案有的地方不滿足我們的需求時,自然會有一種去改改的衝動,但是怎麼改是個大學問。一種方式是投入幾個人從內到外全部改一遍,將其改造成完全符合我們業務需求。但這樣做有幾個比較嚴重的問題:
投入太大,一般來說,Redis 這種級別的開源專案,真要自己改,至少要投入 2 個人,搞 1 個月以上。
失去了跟隨原專案演進的能力:改的太多,即使原有開源專案繼續演進,也無法合併了,因為差異太大。
所以我的建議是不要改動原系統,而是要開發輔助系統:監控、報警、負載均衡、管理等。以 Redis 為例,如果我們想增加叢集功能,則不要去改動 Redis 本身的實現,而是增加一個 proxy 層來實現。Twitter 的 Twemproxy 就是這樣做的,而 Redis 到了 3.0 後本身提供了叢集功能,原有的方案簡單切換到 Redis 3.0 即可(詳細可參考這裡)。
如果實在想改到原有系統,怎麼辦呢?我們的建議是直接給開源專案提需求或者 bug,但弊端就是響應比較緩慢,這個就要看業務緊急程度了,如果實在太急那就只能自己改了;如果不是太急,建議做好備份或者應急手段即可。
2. 發明你要的輪子
這一點估計讓你大跌眼鏡,怎麼講了半天,最後又回到了“重複發明你要的輪子”呢?
其實選與不選開源專案,核心還是一個成本和收益的問題,並不是說選擇開源專案就一定是最優的專案,最主要的問題是:沒有完全適合你的輪子!
軟體領域和硬體領域最大的不同就是軟體領域沒有絕對的工業標準,大家都很盡興,想怎麼玩就怎麼玩。不像硬體領域,你造一個尺寸與眾不同的輪子,其他車都用不上,你的輪子工藝再高,質量再好也是白費;軟體領域可以造很多相似的輪子,基本上能到處用。例如,把快取從 Memcached 換成 Redis,不會有太大的問題。
除此以外,開源專案為了能夠大規模應用,考慮的是通用的處理方案,而不同的業務其實差異較大,通用方案並不一定完美適合具體的某個業務。比如說 Memcached,透過一致性 Hash 提供叢集功能,但是我們的一些業務,快取如果有一臺宕機,整個業務可能就被拖慢了,這就要求我們提供快取備份的功能。但 Memcached 又沒有,而 Redis 當時又沒有叢集功能,於是我們投入 2~4 個人花了大約 2 個月時間基於 LevelDB 的原理,自己做了一套快取框架支援儲存、備份、叢集的功能,後來又在這個框架的基礎上增加了跨機房同步的功能,很大程度上提升了業務的可用性水平。如果完全採用開源專案,等開源專案來實現,是不可能這麼快速的,甚至開源專案完全就不支援我們的需求。
所以,如果條件允許的情況下:重新設計完美符合自己業務特點的輪子也是很好的選擇!