TOC
前言
大家應該或多或少都有經驗要將某個語言實做的API搬到另一種語言重寫。原因總是有千千百百種,但是有時候當專案很大,沒辦法一次搬完的時候又該怎麼辦呢?分享一下我們的例子。
原先的API是使用PHP來撰寫,但因為幾個原因所以我們決定把他搬到Golang。
- 原始PHP版本留在PHP 5.3,是一個效能不好(compare to PHP 7)以及不被維護的版本。要升級得顧慮沒有人維護的framework,所以是個大工程。
- 因為業務的需要,一個API request有很多可以平行化處理的事情,如果一步步來其實速度慢又浪費資源,改用Golang可以帶來大幅度的效能提昇。
- 我們原始業務一直是使用Golang,在QPS > 2w的環境上驗證過,所以成熟度完全不是問題。
因此最後決定新的API就以Golang撰寫,有需要動到舊有的API且時間足夠再搬到Golang。這時候就遇到一個問題啦,同時兩套語言寫成的API要怎麼共存的?當時想到透過切分域名或切分request path也就是routing來達成,分成幾個維度來看~
切分域名
切分域名就如字面上的意思,舊的API用原有的域名,新的API用心的域名。簡單明瞭不囉唆。但同時也有不便之處。
優缺點分析
優點
- 新舊API切分乾淨,新的API不會影響舊版的APP。
- 針對新舊API可以有完全不同的API設定,例如快取規則、HTTPS的SSL版本、及開啟HTTP/2等等
缺點
- 如果僅僅是想要優化API以Golang改寫,將只有新版的APP用戶會拉取,而一般APP的版本到達率…慘
- 萬一同個API以Golang實做了,在未來如果要更改邏輯則必須兩個語言都要同時更改,增加開發及測試的複雜度
切分Routing
透過CDN切分
以Cloudfront為例,透過Cloudfront可以將不同的PATH Route到不同的Origin,甚至我們可以針對不同的PATH設定不同的快取時間、通訊協定、要cache的query parameter或header等等。
透過Proxy(Nginx)切分
我們可以在Proxy例如Nginx來設定不同的PATH要使用PHP或者是forward到Go API。
# /v1/user forward到PHP
location /v1/user {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php last;
}
}
# /v1/user/points 則forward到golang
location /v1/user/points {
proxy_pass https://localhost:19002;
}
在Golang裡切分
這邊以Gin為例,我們把所有的request都導到Go API,如果API在golang裡面有實做則直接由GO處理,否則就proxy到原有的PHP API處理
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
//放你所有的API
//...
//當上面的PATH都沒命中則pass到PHP
r.NoRoute(func(c *gin.Context) {
director := func(req *http.Request) {
req.URL.Scheme = "http"//使用http省下ssl解析時間
req.Header.Add("Host", "php-api.xxx.com")//php.api替換成你的PHP url
req.Host = "php-api.xxx.com" //同上
}
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(c.Writer, c.Request)
})
r.Run() // listen and serve on 0.0.0.0:8080
}
方案分析及結論
考量維度 | 切分域名 | 使用同個域名但routing切開 |
---|---|---|
修改舊有API | 只有新版的APP才會使用到新的API。舊版用戶得等版本到達率整個慘。 | 因為API path不變,因此新舊版同時生效 |
新增API | 直接切開,清爽 | 透過設定routing來切分,比較瑣碎 |
因為我們必須讓使用舊版的用戶也可以馬上生效,最後我們選擇使用同個域名。如果不在乎這個,其實切分域名還是比較方便的。
最後比較一下透過PATH切分不同方法的優缺點:
在CDN切
好處:像Cloudfront可以提供route到不同的origin, 分別設ttl, cache條件等等很方便。
壞處:換CDN或不同國家使用不同的CDN就GG,不是每家CDN都支援。每次有新的API都得確認一次routing很煩前面放個Proxy e.g.Nginx
好處: Nginx熟悉的人很多,也很直覺
壞處: 每次有新的API都得確認一次routing,量一多挺亂的在Golang裡面切
好處: 在程式裡設routing,都不中則proxy到PHP,不須額外設定第三方或其他套件
壞處: 要寫程式@@?
「您的支持是創作的原動力」
您的支持是創作的原動力
使用Wechat(微信))掃描QR Code贊助我吧!
comments powered by Disqus