歡迎光臨
每天分享高質量文章

如何更好運用Go語言 造就數千萬月活的網際網路產品

前言

大家下午好!這次我給大家帶來的分享是 Go 在客路的應用實踐。我將從以下幾個方面作分享:

 

一、Go In KLOOK

二、不同階段的架構回顧

三、面臨的新挑戰

四、 一點探索和思考

 

Go In KLOOK

首先給大家介紹一下客路,目前主要業務是在海外,是一個全球目的地旅遊體驗預訂平臺,當地遍佈全世界 250 個熱門國家,提供 8萬+ 服務的預定,包括折扣景點門票、一日遊、當地交通等等。每月有 2000 多萬全球使用者使用 KLOOK 預訂旅遊活動,客路的國際化也得到了資本的認可,累計獲得 3 億美元融資,成為了目的地旅遊全球融資額最高的公司。下麵是客路 APP,大家可以看一下。客路近期也在大量招募超百位的技術人才,在這裡給自己提前打個廣告,歡迎大家去拉勾看看。

     

客路團隊是一個相對比較國際化的團隊,目前來自於 25 個國家及地區,大家可以看到客路辦公室遍佈全球,客路做的是全球化的生意,什麼是全球化?如果有一天你想去迪士尼去玩,你帶上手機直接去,到了場地開啟客路 APP,直接購買掃碼入場就可以,不需要考慮其它,無論你身處全球的哪個地方,所有使用者體驗是一致的,這是客路一直在做的事情,這就是全球化。

GO 在客路的應用有很多,包括 Go in KLOOK APP,還有內部執行的APP,幾乎整個客路後端都是用 Go 開發,用 Go 在做客路幾乎所有系統。之所以說幾乎,還有一些東西是 Go 不能做的,Go 不能做的東西怎麼辦呢?當然就用 CGo 啦,這個其實是一樣的。

不同階段的架構回顧

對於客路在不同階段所使用的架構,我在這做一些回顧分享給大家,希望大家能有所收穫。客路最初和很多初創公司一樣,是基於 SSH 的單體應用,但客路發展其實非常快,在當時那個時間點就可以看到,以當時的發展趨勢,Java 很快將不能支撐,我們決定必須要重構我們的技術架構,做這個決定真的很難。

最初期的思考

我們也做了很多考量,比如,當時團隊大部分是 Java 的,那換 Go 語言的成本怎麼樣?所以最初用 Go 試做了很多小系統,發現 Go 語言效率很高,且學習成本很低,透過一步步的積累後,我們開始大量的透過 Go 來實現我們新的基於微服務的後臺架構。


      

這上面列了一些我們當時有考慮到的一些事項。如寫業務是否夠快?舊的系統怎麼辦?舊的系統難不難?碰到難題,團隊能不能 Hold 住?  我們當時透過一些案例和驗證,發現這些團隊完全可以 Hold 住的, Go 寫業務也是飛快。

同時還會有一些問題:需求多不多?人員是否緊張?人員跟團隊技術有衝突的時候怎麼辦? 我們當時定了一個原則,如果這方面有衝突,一定是以業務為優先的原則。

關鍵先用起來,當真正用起來後,開發效率有提高,業務寫得快了之後,上面的所有疑問都不再是問題。

最初期的落地

具體落地現在看起來,其實當時有幾個點做得比較好,保證了新架構的有效落地。 首先是思想上統一,要制定一個好的規範。如用什麼樣的原則劃分微服務,這些規範要統一;然後是工程規範,就是說你的程式碼倉庫怎麼擺,具體到每個使用者倉庫裡面,每個模組檔案用什麼統一規範去做,早期這些事項規範的越早,對後面的幫助越大;其次,公司業務變化非常快,當時很難定義一套特別具體的細則來做為業務邊界劃分規則,但大的劃分原則是必須統一的,大家要在統一的頻道、統一的思路上面去做事和溝通。沒有這個,當微服務多了之後,要重新梳理密密麻麻的各種服務,代價非常的大,所以統一思想非常關鍵;最後,要有一個可用的基礎庫,大家註意這個庫的只要可用,夠用就可以了。早期,尤其是團隊人力資源緊張的情況,基礎庫其實不需要特別強大,太過強大全面,意味著會變得複雜度很高,團隊可能會很難駕馭,而且也很有可能團隊等不起,你只要好用、足夠可控就可以了。 

 

     

這裡要再強調一下,在早期有一份比較好的程式碼規範是非常必要的,這也是程式碼評審推行的必要條件之一,程式碼評審其實是一個相互學習的過程,透過相互檢查、溝通交流,大家的技術水平和業務能力才有可能提高的更快。同時,一個好的程式碼規範,能無形之中幫研發避開很多已踩過的坑,對提高程式碼質量,能起到非常重要的作用. 總的來說因為有這些東西作為基礎,我們客路早期微服務實施的算比較順利。

小服務大作用-監控

 

現在回過頭看這個階段,除了上面說的這些以外,發現當時寫的一個小監控服務,在對於新架構的實施也起到了意外的關鍵作用。這個監控服務當時就花了一點點時間,用了幾百行 Go 程式碼來實現,它起得作用看起來似乎沒有多大,就一個告警和簡單的日誌收集,有一個日誌查詢頁面,但是它實際起到的作用非常大。

作為一個創業公司,獲取一個新使用者是比較難的。使用者的口碑非常關鍵,產品要是出了問題,會導致用戶投訴。 公司 CEG (客服)部門會過來找開發,這時負責的研發如果沒有一些快速定位問題的工具或方法,可能會很緊張,因為不知道到底是服務問題?還是系統出問題?還是網路出問題?或者是資料庫出問題了? 好不容易有點頭緒,還不知道具體這次請求有經過哪些服務,是哪個環節出了問題?

而有了監控服務後,首先我們能透過告警提前發現異常,併在出現異常後,能透過日誌查詢,快速定位問題。 當時起的作用是立竿見影的。並且在當時情況下,這套東西 Go 這邊有,Java 那邊沒有,這個對比非常之明顯。

  

監控和告警應當是你的架構基石中,不可缺少的一環,它能帶來很大的收益,千萬不要忽視。

第二階段

 

當微服務從幾個增加到十幾個的時候,一些問題微服務治理相關的問題開始出現。比如 APP 發個版本,會發現要開十幾個視窗,執行一堆指令碼,來回切換,這是很痛苦的事情。服務配置管理也變得比較困難,還存在很多其它類似問題。所有問題粗看起來好像很容易解決,比如招個運維?但真要去解決時發現其實並不容易,因為有些會涉及到基礎技術框架層的東西,光運維是不能完全解決的,另外當時團隊沒有也沒專職運維,好的運維其實也蠻難招的。

   

還有另外一些問題,比如說服務線上檢查以及服務介面的內外隔離之類,也很麻煩。以服務介面隔離為例,雖然我們在微服務方面做了很多分離約定,但後來發現,前端還是可以繞過後端對外服務,直接呼叫後端內部服務介面。 另外,有些後端服務對於本身所屬的 API 介面分類和權責也不清晰。 比如,在實際開發過程中,他可能在服務裡面,既支援了對外的介面,又支援對內的介面,還有支援內部運營系統的介面,這個在一個服務裡面是三種不同的業務場景,它們使用場景都不一樣,這個其實也是很可怕。到這個階段微服務管理開始有點亂,感覺有點吃力了。不過還好,在後期出現了一個轉折,這個轉折點出現在哪裡呢?

轉折點-微服務治理平臺

 

轉折點是研發了一個微服務治理平臺,當時從有想法到讓它跑起來實際上花的時間並不多,它的核心思想是說把所有服務註冊、部署、線上狀態管理和相關的配置等等聚集在一個地方管理,不需要關心背後的各種關係也不需要切換,一個系統一個頁面管理所有事情,當然,這些功能的背後是需要對架構進行一系列的改造才能做,團隊也一直在持續對它進行最佳化和改造。

     

 

 

微服務探索與發現

 

隨著我們持續的完善發展,引入了非常多的開源元件,大家可以看到各類元件很多,有些大家應當都非常熟悉,如 Consul、fabio 等等。它們都非常好用,但引入後是需要人來維護,而這其實會消耗掉很多的資源,我們很多人力和時間,如果消耗在維護上面,消耗在部署上面,這其實是一種浪費。

     

 

 

後期問題

 

另外,後期發現開源元件的搭建和運維上,投入的團隊資源比重越來越大,在消耗人力和機器資源的同時,部署和運維也變得太過複雜。同時,一些開源元件的 bug 與頻繁更新的跟進也令人頭疼。在遭遇過一系列的產線 Bug 後,我們開始思考這些分析,決定大部份元件移到雲服務上,我們做了幾個方面的改變:

第一,最基礎的設施,比如說 Redis、Nginx、NFS 之類,不再自己搭建。這些完全可以使用雲服務。

第二,對依賴元件做減法,只留下最精華的開源或自研元件,其它都儘量換為雲服務元件。為什麼還要留來下一些開源元件呢?首先不是所有的雲服務都那麼好,也有很糟的雲服務元件,有很多非常不錯的開源元件做得比雲服務好。另外,也有很多元件也沒有雲服務可替代。

第三,透過自研元件的方式來解決架構的可控問題。自研元件這件事對我們來說,它的功能不需要那麼多,但是它要滿足未來一段時間的需求。它是自研可控的,出現問題時,我們有對應的解決方案。有些元件的實現,你會發現它非常強大,但是它非常複雜,想完全掌控這個東西,其實是要花費相當大的精力。可控性在有些設計上非常關鍵,整個架構需要足夠可控,尤其架構元件多起來的後,自研必須納入考量的選擇。

精簡後

 

這是精簡後的架構,可以看到只保留了 NSQ、slack、NATS 等幾個有限的元件,複雜度與維護工作量減輕了非常多,這就是轉換思路後對我們帶來的影響。

     

案例-日誌查詢系統

 

我這裡還準備了一個這種思路下的實踐例子”日誌查詢”系統。 查詢日誌一個非常高頻的需求。剛開始我們有好幾個不同場景不同平臺的日誌查詢系統,其實查詢心智負擔很重,研發不應當需要那麼多的日誌查詢平臺,最好只提供一個統一的查詢平臺就好。

微服務下,接收和處理一個請求基本都會經過很多的服務實體,對請求的日誌,如果可以把請求經過所有微服務所有日誌全部串起來,對於定位修複問題,會是很大的效率提升。   另外,我們上新服務或新需求時,研發常常需要實時定位日誌,但因為安全的考量,不是所有的開發都直接登入伺服器去實時監控服務實時日誌,而我們現在的日誌系統直接支援在網頁上實時對產線服務實體日誌線上監控,效果與 “tail -f” 相同,這是個非常受歡迎的功能。

      

早期的日誌查詢都是基於 ELK 是很難做這些定製化功能的,當然早期它也非常好用。但後面公司日誌漲的實在太快,一直在加伺服器,  我們又沒有人有足夠精力在上面做最佳化,雖然我相信如果最佳化的好,也是能撐住的。最後方案是用雲服務加自研實現了一個穩定,效能比很高的方案。

 

日誌查詢平臺具體是怎麼實現的呢?首先,各類日誌會上傳儲存到 Amazon S3,研發可在查詢系統,透過背後的 Athena 進行日誌查詢。 效能有保障且幾乎沒什麼維護成本。其實,前面有一個講師講了一個非常好的日誌解決方案,我很羨慕唯品會有這麼多能力和資源可以在這個事情上一個事情做到極致,但是對於創業團隊來說,很難有這種資源或者精力投入到這個事情上面,對比唯品會的方案,使用雲服務其實是一個對創業團隊來說是一個受益非常高且更實際的方式。

     

面臨的新挑戰

 

經歷過幾次架構思路上的轉變及一系更迭代後,當時我們覺得至少應付未來一兩年是沒有什麼問題的。其實市場的發展超乎意料,最大挑戰是公司融資了,公司完成 2 億美元的 D 輪融資。這個事情帶來的影響:

第一、使用者增長的更快,使用者量的上漲,帶來的請求量也跟著漲得非常快。

第二、有了更大的市場壓力。有更大市場壓力怎麼辦?市場團隊會拼命提需求,開新的業務線,不停在現有產品上加各種各樣的最佳化,最後結果可能就是所有研發都在拼命去做需求,技術架構升級這塊已經沒有人有精力了。但從監控和資料上看,系統的迭代是不能停的。我們很艱難的從團隊抽出人手開始了新一輪的最佳化。

       

最主要的最佳化精力放在兩個方面: 效能 和 安全。

說到效能問題,雙十一剛剛過去,相信國內的電商為雙十一準備了很久。對於很多電商來說,雙十一隻需要準備好國內市場就可以了,但是客路不一樣,我們做雙十一的時候,發現韓國、日本、臺灣、香港使用者也在過雙十一,但最後發現當日最大流量競然是來自於菲律賓,市場真是給人意外。 另外,客路做的是全球市場,考慮不僅是國內市場還考慮國外市場,比如說國內的雙十一,618 大促要準備,國外的黑色星期五也要準備,國外及一些地區的區域性節日也要準備,這些會對系統效能提出更高的要求。

    

 

從 HTTP 轉 RPC,是我們為解決效能問題做的一個比較大的決策,上面是當時提出一些需求。  說白了就是,即要有大的效能提升,又要儘量無感知的能讓現有的專案切換過去,減少對正常業務需求的影響。

   

以當時團隊的人員情況看,應當是很困難的任務。 但實際情況是,RPC 在很短時間內,超出預期的在團隊落地。 這一方面是團隊對 RPC 的熱情很高,另一方面確實是團隊的成長速度出乎意料。可能是一路走來,趟過的坑,讓團隊的積累會相對足一點,如果直接用特別成熟的框架跳過很多中間過程,團隊成員可能也同步缺失了某些收穫經驗的機會。當然,這個各有利弊。

具體的RPC實現

 

目前的 RPC 基於 gRPC,融入客路微服務治理:服務註冊、服務發現、負載均衡。對於 gRPC,當時我們做過一些對比,它其實是最均衡的一個 RPC,只需要針對它在現有系統上很少量定製化就 OK。然後,為了減少遷移成本,還做些有意思的事,比如,我們做了一個外掛,可以直接把 struct 轉為 PB 協議。對於已有的 HTTP 服務,透過在 main.go 加二行程式碼,即可將整個服務轉為即支援 HTTP 也支援 RPC 的服務。

安全-GO語言層

 

另外是安全問題,做電商的都離不開安全這個話題,基本都會認識到安全的重要性,當然安全涉及到非常多方面,要做很多工作。 

 

比如在語言層面,需要有程式碼安全規範,讓研發知道,怎麼寫程式碼最安全。     

   

最近在考量一些原始碼的分析工具如 Gosec 來進行加固。而 Go 語言本身雖然是相對比較安全的語言,但留意一下,你會發現,暴露出來的問題還是很恐怖的,大家可以關註下麵 PPT 上的 CVE 漏洞。

 

安全-基礎架構層

 

在基礎框架層,我們用自研的 secutils 安全工具函式庫,來替換很多可能存在安全風險操作,比如檔案上傳,下載之類操作。在 SQL 層面,基於 SQL.Driver 層,我們做了一些封裝,會做統一的 SQL 採集,然後在後臺透過工具做相關的安全分析。在框架層也自研了一層薄薄的WAF封裝,提供給對外服務使用,之所以要做一層 WAF,是為了能在必時時,定製一些自己的安全規則,因為很多業務場景,只有我們自己最清楚。

場景思考

 

透過上面一系列的效能與安全最佳化後,我們在總結時發現,到了這個階段以後,透過這些單純的技術框架最佳化,在支撐業務的快速發展方面,作用明顯不如之前?從以往的經驗看,在進行很多最佳化後,團隊會產生很明顯的受益,但這次,好像有點失靈了。 

 

因此,我們列了很多典型的場景,有技術的,也有業務的,來做分析,看最有益的方案是什麼?

場景一

 

多語言處理

早期多語言處理相關的函式 ,是統一放在程式碼公共庫裡面的。因為客路做全球化市場,所以會面臨很多語言的問題,早期只支援簡體中文、繁體中文。英文。但隨著市場越來越大,對更多語言支援需求也越來越多,越來越細,甚至最近開始要求支援英文方言。 而微服務有個特點,服務多。每次加個語言很痛苦,別的不說,光全編譯一遍都非常花時間。 在這個場景下,如果把多語言相關的函式獨立出來成一個單獨服務,好處非常大。這讓我們認識到,業務發展到一定程度,早期特別好用的功能,說不定反而變為了瓶頸,所以不是基礎公共庫功能越多,越複雜就好,反而應當適當的給它瘦身,減負,收益更大。


 

場景二

第二個場景是同一個業務線在微服務場景下,同時存在 A、B、C 三種不同甚至更多種業務服務,按業務重要性分一定會有核心與非核心,但核心服務並不一定是請求佔量大的,而服務所需資源(比如說資料庫或快取等)總體上看是有限的。在一些特殊情況下你會發現出現資源爭用,非核心服務請求有可能搶佔了更多資源。這個問題在單純基礎程式碼框架層很難解決,要徹底解決,會需要獨立出一層資源排程層,這樣才能做到可控。並且還有其它的好處,當你的資源如資料庫要做升級或資料遷移時,有這個中間層在,處理手段會靈活動。  

業務也是一樣,初期一些封裝一些通用的業務函式也蠻好用,隨著業務發展變化,各種更細化,更定製的需求堆積後,框架層的一些基礎業務函式邏輯可能會變得非常複雜,而且因為它可能會被 N 多的服務所取用,任何的改動,包袱很重風險比較高的操作。這時,把這些抽象成服務,以介面的方式提供,反而是值得的,會更靈活,更有優勢。

資源的可控,業務層的合理抽象,基本能保證,不管需求怎麼增加,怎麼變,系統的改變會最可能的小,服務的拓展性會更強,更靈活。

一點探索和思考

有三點探索和思考:

 

第一,主動變化,在不同階段,找到最適合的那個架構。這個架構不需要非常強大,但是是最適合你的。基礎庫到一個階段的時候,你會發現很多東西是一個體系,不要盲目特別追求特高要求的東西,你要考慮整個團隊的消費能力,這個的東西可能非常好,但是需要十幾二十人在維護,你的整個團隊可能不一定 hold 得住。

第二,要善於“組合”,也要善於“拆分”。針對你的問題要知道怎麼利用已有的資源組合利用起來,變成可以落地的解決方案。 選型時不要太過拘泥,開源元件、自研、雲服務 哪個在當時合適就用哪個,關鍵是要解決問題,很多最佳化可以放到後期去迭代。另外,當系統發展到一定階段後,一定會在某些地方碰上瓶頸,找到瓶頸,該用新元件的替換的就替換,該拆分獨立成新服務的,就應當拆分。

第三,服務穩定最重要。所有的最佳化不能影響服務的穩定性。

我的分享就到這,謝謝大家!

贊(0)

分享創造快樂