摘要: 前言 隨着容器技術的興起,愈來愈多不一樣類型的應用開始使用容器的方式進行交付。Golang做爲服務器端很是熱門的一門語言同時也是容器技術的主要編寫語言備受關注。那麼將一個Golang應用進行容器化的時候,須要注意哪些事情,在出現問題時該如何進行調優和診斷呢? 先談談Golang自己的設計 Golang是谷歌發佈的第二款開源編程語言。html
隨着容器技術的興起,愈來愈多不一樣類型的應用開始使用容器的方式進行交付。Golang做爲服務器端很是熱門的一門語言同時也是容器技術的主要編寫語言備受關注。那麼將一個Golang應用進行容器化的時候,須要注意哪些事情,在出現問題時該如何進行調優和診斷呢?nginx
Golang是谷歌發佈的第二款開源編程語言。Golang專門針對多處理器系統應用程序的編程進行了優化,使用Golang編譯的程序能夠媲美C或C++代碼的速度,並且更加安全、支持並行進程。Golang在容器相關的場景和領域以及高併發的服務器程序場景下扮演着很是重要的角色。git
Golang具備以下三個特色:github
在學習一門語言前,一般我會主要關注以下三個方面:第一這門語言的特性是什麼;第二這門語言解決的場景和問題是什麼;第三這門語言的內部設計是否有須要注意的地方。上面的介紹已經爲咱們解答了第一個和第二個問題,那麼接下來咱們主要來討論第三個問題。那麼Golang的這些優秀的特性內部的設計方式是什麼樣子的,使用起來是否有什麼須要特別注意的呢?爲了詳細解答這個問題,咱們將問題拆分紅了二個部分分別爲你們解答。golang
高併發是Golang被你們接納和承認的最重要一環。對於大型的互聯網項目而言,高併發能夠說是應用性能的立足之本,再棒的功能與特性也不如穩定運行來得讓人安心。從前你們在關注C10K問題,而如今愈來愈多的人開始思考如何解決C10M問題。從C10K問題到C10M問題,解決問題的方式已經不是簡簡單單的調整內核參數那麼簡單的。更多的是要從架構甚至應用自身的角度來解決,一個高效的併發模型,能夠從應用程序的交付壓榨系統的性能。目前比較成熟的併發模型,主要是經過進程、線程與協程三種不一樣方式來進行實現的。數據庫
進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每一個進程都有本身的獨立內存空間,不一樣進程經過進程間通訊來通訊。因爲進程比較重量,佔據獨立的內存,因此上下文進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。編程
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源。線程間通訊主要經過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。數組
協程是一種用戶態的輕量級線程,協程的調度徹底由用戶控制。協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操做棧則基本沒有內核切換的開銷,能夠不加鎖的訪問全局變量,因此上下文的切換很是快。安全
Golang的併發模型是基於協程的,而協程在Linux底層的調度是依賴進程的調度的,而這之間的轉換都經過Golang自身的調度器進行了管理,無需開發者關心。可是這個時候有經驗的開發者就會提出問題了,golang自己是編譯型的語言沒有相似JVM同樣的虛擬機能夠在運行時指定參數,那麼Goroutine這種方式是否有參數須要設置來保證性能。服務器
此處給你們講述一個關於Goroutine棧擴容的問題,咱們內部有一個全雙工的高併發寫離線數據的服務,在底層數據出現消費慢的時候快速出現OOM,問題產生的緣由就是因爲Goroutine棧擴容,最後能夠經過經過拆分Goroutine的邏輯到上半段和work group的方式實現,因爲篇幅的緣由不過多的贅述,能夠參考以下這篇博客更深刻了解棧擴容的問題。
內存管理對於C++與Java的開發者而言是最熟悉不過的了。C++的開發者必須經過代碼手動的申請與釋放內存,所以必須熟悉內存佈局和使用;Java的開發者雖然有JVM幫助進行內存的管理與回收,但JVM不一樣的內存參數配置會致使程序由於回收內存帶來不一樣的性能表現。而Golang做爲一門高級編程語言,一樣無需開發者直接操做內存,可是Golang中的GC設計是存在一些缺欠的。主要的問題在GC時的卡頓上,具體的問題能夠參考以下文章,不過這點也無需你們特別關心,建議直接使用Golang1.9之後的版本進行編譯便可。深刻了解Golang的GC能夠參考以下文章
首先須要進行的是常規的容器化優化,具體的內容能夠參考以下文章進行體積的精簡和優化。
不一樣語言對於DNS的Lookup處理會有所不一樣,在Java或者Node.JS等常見的語言和框架中對DNS Lookup都提供語言級別的內置的Cache,而在Golang中卻不存在相似的能力,這會致使對於高併發的場景中,Golang程序有可能會出現大量的DNS查詢,而在kubernetes中,DNS是經過內部的coredns或者kube-dns的方式提供的,所以有可能會由於大流量的Golang DNS致使集羣異常,爲了解決這個問題,建議開發者在Golang的Dockerfile中集成nscd進行DNS的Cache,具體的操做步驟能夠參考以下文檔
在本文的上面的部分,爲你們講解了Golang GC的一些缺欠以及如何避免GC問題的方式,在容器化的時候是否還須要作其餘的優化呢?面對內存的異常,咱們要如何定位是一個GC的問題呢?這裏要給你們介紹的是Golang自來的pprof,pprof是Golang語言中內置的性能調優工具,能夠協同Flame-Graph,排查CPU性能、內存性能、GC回收等問題,建議在容器的場景中,在代碼中集成pprof,並經過環境變量的方式進行開關設置,容器的Dockerfile中保留端口的保留,當出現問題的時候能夠設置環境變量的方式進行開啓,快速進行線上問題的診斷。pprof的使用,能夠參考以下文章
Golang相對而言算是很是」省心「的一門語言了,在老版本的Golang中還須要經過runtime設置GOMAXPROCS,可是在最新版本的Golang中已經基本無需關心runtime的任何參數設置了,這些參數就像nginx的auto同樣,會隨着探測的配置自動變化,而在容器中,咱們依然須要GOMAXPROCS,由於GOMAXPROCS的識別方式是經過獲取系統資源的方式肯定的,而在容器中是經過只讀掛載宿主機的文件實現的,所以獲取的資源仍是宿主機的數值。所以,Golang的應用容器化,更多的仍是要作好標準鏡像優化的步驟,以及在代碼級別作好避免觸發GC和Goroutine的問題。
阿里雲雙十一1折拼團活動:已滿6人,都是最低折扣了
【滿6人】1核2G雲服務器99.5元一年298.5元三年 2核4G雲服務器545元一年 1227元三年
【滿6人】1核1G MySQL數據庫 119.5元一年
【滿6人】3000條國內短信包 60元每6月