Dubbo 爲什麼用 Go 重寫?

先說兩句

我常常在散步時思考很多技術上的「爲什麼問題」,有時一個問題會想很久,直到問題的每一個點都能說服自己時,纔算完結。於是想把這些思考記錄下來,形成文章,可以當做一個新的系列。這些文章中你可能看不到代碼,但能窺探到一些容易被忽視的問題,以及問題更深層次的「爲什麼」。

今天帶來第1篇,Dubbo 爲什麼要用 Go 重寫?

誕生於阿里巴巴,2011 年開源的 Dubbo 已經走過了 10 個年頭。在 2019 年,它被用 Go 重寫並開源,如今兩年過去,已經從當初的V1.0.0版本發展到了V3.0.0,截止目前 star 數 3.8K。

有一次同事問我,爲什麼 Dubbo 這麼 "老" 的項目還要用 Go 重寫,有什麼現實意義嗎?

今天就來談談我的一些看法。

連接過去和未來

我覺得要回答好這個問題,得從 Dubbo-go 的初衷談起,github 主頁上它是這樣介紹自己的:

官方給出的中文翻譯是

Apache Dubbo Go 語言實現,架起 Java 和 Golang 之間的橋樑,與 gRPC/Dubbo 生態互聯互通,帶領 Java 生態享受雲原生時代的技術紅利。

我再通俗地翻譯一下:一個公司或部門內有人用 Java 版 Dubbo,有人用 Go,這兩者需要通信,於是就有了 Dubbo-Go,用來解決通信問題。

所以第一個問題來了,爲什麼一個公司用了 Java,又用了 Go?

編程語言的抉擇

對於編程語言的選擇,在商業公司裏,我覺得最最主要考慮的點就是效率,至於其他的點都是次要。因爲商業公司的主要目的就是盈利,不管什麼語言,只要能用最低的成本拿到相等的收益就是好語言。

效率又包含了好幾個方面:

縱觀國內很多商業公司的選擇都是如此考慮,比如阿里。

阿里早期是 PHP,選擇 PHP 的考量點主要是開發效率,但隨着業務的發展,PHP 的性能無法支撐,必須得換一個運行效率高的語言。

運行效率高自然想到 C/C++,但這兩個語言的開發效率低,得在開發效率和運行效率中找到一個平衡點,於是阿里選擇了 Java。

阿里官方在知乎上回答爲什麼選擇 Java 時,主要有以下幾點考慮:性能簡單易學生態豐富社區活躍

把性能放第一位,簡單易學、生態豐富、社區活躍其實也都是說的開發效率,正是有了這些優點,開發效率才高。

當阿里巴巴選擇 Java 後,自研了大量的 Java 中間件,培養了大量的 Java 人才,所以其他公司在技術選型時,也參考了阿里巴巴,導致越來越多的公司選擇了 Java。

而選擇 Go 也是如此,一些年輕的公司早期可能是 PHP、Python 等腳本語言,等發展壯大後,不得不面臨和阿里一樣的問題:性能問題。

在 2012 年 Go 發佈了,大家又多了一個選擇,Go 既有很高的性能,又非常地簡單易上手,像字節跳動這類新公司就以 Go 爲主。

所以綜合來看,選擇 Java 或者 Go 都是合理的,存在即合理。

爲什麼有公司選擇了 Java,又想用 Go 呢?

小結

綜上看來,選擇 Java 或選擇 Go 都合理,一個公司內兩者都選擇,也有合理之處,雖然佔比不多,但還是有 Java 和 Go 通信的需求。

Dubbo 在 RPC 框架中的勝出

公司早期通常是單體服務,在規模達到一定程度,單體應用無法支撐業務發展時,會選擇微服務架構,這時就需要一個好用的 RPC 框架。

能適配 Java 語言的 RPC 框架中,Dubbo 是國內最早開源,於 2011 年開源。

而和他類似的競品如 Spring Cloud 在 2014 年開源,微博的 Motan 在 2017 年開源,跨語言的 gRPC 在 2015 年開源,Thrift 2007 年開源。

只有 Thrift 比它早,但 Thrift 只是個 RPC 框架,Dubbo 可是包含了開箱即用的服務治理能力,如服務註冊與發現、負載均衡、容錯、動態配置等等。

可以說早期 Java 的 RPC 框架沒得選。

就算到了 RPC 框架百花齊放的時代,這麼多公司的使用加上阿里的背書,Dubbo 也有它的一席之地。

小結

當一個公司選擇了 Java 編程語言和 Dubbo 框架(這種選擇還是挺多的),後來又想嘗試 Go,或者一些新業務、新部門想嘗試 Go 時,他們就面臨了一個難題,Go 如何跟 Java 的 Dubbo 通信。

由於 Dubbo 協議是私有協議,用 Go 重新實現一遍的代價還是挺大。於是 Dubbo-Go 應運而生,從這個角度看,Dubbo-Go 在連接 Java 和 Go 的通信這條路上還是具有相當大的價值的。

終結與線程池的鬥爭

如果使用了 Dubbo 框架,很多時候需要一個 Dubbo 網關,關於 Dubbo 網關可以參考我這篇文章:《微服務網關演進之路》

在這篇文章中,詳細介紹了一款 Dubbo 網關的背景、難點、選型、設計、演進以及踩坑經歷,其中我花了大篇幅介紹了「與線程池所做的鬥爭」,在 Java 中,線程是很寶貴的,但 Dubbo 網關如果是同步調用,必須一個請求佔用一個線程,這就導致併發上不去,而且線程池打滿後,會影響其他請求。

所以解決方案要麼是隔離線程池,要麼改成異步調用。隔離線程池只解決了請求不相互影響,但併發還是上不去,改成異步調用可以完美解決,但是編碼實在是太複雜。

而 Go 的協程可以剛好解決這個問題,Go 的協程很輕量,調度效率也更高,所以我們可以用簡單的代碼寫出非常高效率的網關。

舉個例子可以直觀感受一下,Nginx 的性能大家有目共睹,但如果用 Java 來實現,不知道得堆多少機器才能達到 Nginx 的性能,但百度在反向代理上使用了 Go 寫的 BFE 來代替 Nginx,可見其性能有多誇張。

關於協程的介紹和原理,可以參考我這篇文章:《寫了一年 golang,來聊聊進程、線程與協程》

小結

所以在 Dubbo 網關上,Dubbo-Go 也提供了一種新的解法,已經有用於線上的 Dubbo-Go 網關,開源項目可參考Dubbo-go-pixiu

爲 Dubbo Mesh 鋪路

Service Mesh 也漸漸成爲了下一代微服務架構,Go 在 Mesh 上也絕對是一個閃亮的明星語言,無論是 K8S、Docker 等雲原生基礎設施都採用 Go 編寫,還是 Go 的開發速度以及協程的高併發能力,都使它成爲了 Mesh 的首選語言。

基於此,Dubbo 的 Mesh 化,Dubbo-Go 也爲其鋪平了道路,但目前 Dubbo Mesh 還處於小面積階段,完整落地的方案並沒有開源,從這點上來說,如果某公司想走 Dubbo Mesh 化之路,Dubbo-Go 可能也是他們要着重考慮的點之一。

總結

說了這麼多,該正面回答 Dubbo 爲什麼要用 Go 重寫,這個問題的答案還是官方給出的那句話:架起 Java 和 Golang 之間的橋樑。至於爲什麼要「架起這座橋樑」,參考下圖:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/7pS9KfJsj3u9Ufg4gZ1VhA