軟件開發領域有一個流行的原則:DRY,Don’t repeat yourself。翻譯過來更通俗易懂:不要重複造輪子。開源項目的主要目的是共享,其實就是爲了讓你們不要重複造輪子,尤爲是在互聯網這樣一個快速發展的領域,速度就是生命,引入開源項目能夠節省大量的人力和時間,大大加快業務的發展速度,何樂而不爲呢?html
然而現實每每沒有那麼美好,開源項目雖然節省了大量的人力和時間,但帶來的問題也很多,相信絕大部分技術人員都踩過開源軟件的坑,小的影響多是宕機半小時,大的問題多是丟失幾十萬條數據,甚至災難性的事故是所有數據都丟失。mysql
除此之外,雖然 DRY 原則擺在那裏,但實際上開源項目反而是最不遵照 DRY 原則的,重複的輪子好多,你有 MySQL,我有 PostgreSQL;你有 MongoDB,我有 Cassandra;你有 Memcached,我有 Redis;你有 Gson,我有 Jackson;你有 Angular,我有 React……總之放眼望去,其實類似的輪子不少!類似輪子太多,如何選擇就成了讓人頭疼的問題了。程序員
怎麼辦?徹底不用開源項目幾乎是不可能的,架構師須要更加聰明地選擇和使用開源項目。形象點說:不要重複發明輪子,但要找到合適的輪子!但別忘了,若是你開的是保時捷,可別找個拖拉機的輪子。sql
1. 聚焦是否知足業務緩存
架構師在選擇開源項目時,一個頭疼的問題就是類似的開源項目較多,並且後面的老是要宣稱比前面的更加優秀。有的架構師在選擇時有點無所適從,老是會擔憂選擇了 A 項目而錯過了 B 項目。這個問題的解決方式是聚焦因而否知足業務,而不須要過於關注開源項目是否優秀。網絡
Tokyo Tyrant 的教訓
在開發一個社交類業務時,咱們使用了 TT(Tokyo Tyrant)開源項目,以爲既可以作緩存取代 Memcached,又有持久化存儲功能,還能夠取代 MySQL,以爲很強大,因而就在業務裏面大量使用了。但後來的使用過程讓人很鬱悶,主要表現爲:架構
不能徹底取代 MySQL,所以有兩份存儲,設計時每次都要討論和決策究竟什麼數據放 MySQL,什麼數據放 TT。負載均衡
功能上看起來很高大上,但相應的 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 的原理,本身作了一套緩存框架支持存儲、備份、集羣的功能,後來又在這個框架的基礎上增長了跨機房同步的功能,很大程度上提高了業務的可用性水平。若是徹底採用開源項目,等開源項目來實現,是不可能這麼快速的,甚至開源項目徹底就不支持咱們的需求。
因此,若是你有錢有人有時間,投入人力去重複發明完美符合本身業務特色的輪子也是很好的選擇!畢竟,不少財大氣粗的公司(BAT 等)都是這樣作的,不然咱們也就沒有那麼多好用的開源項目了。