偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

產(chǎn)品環(huán)境中 Go 語(yǔ)言的最佳實(shí)踐

開(kāi)發(fā) 項(xiàng)目管理
我們也是通曉多種語(yǔ)言的組織,因?yàn)槲覀兪褂昧撕芏嗾Z(yǔ)言。并且這些服務(wù)(和基礎(chǔ)設(shè)施支持)的許多部分是使用Golang開(kāi)發(fā)的。事實(shí)上,我們都是早期Golang的使用者:目前,我們已在產(chǎn)品中使用Golang有兩年半的時(shí)間。

在SoundCloud,我們?yōu)榭蛻?hù)構(gòu)建了產(chǎn)品的API?;蛘哒f(shuō),我們主要的網(wǎng)站、手機(jī)客戶(hù)端和手機(jī)應(yīng)用是該API的***批客戶(hù)。該API背后是一個(gè)領(lǐng)域性的服務(wù):SoundCloud基本上以面向服務(wù)體系結(jié)構(gòu)的形式運(yùn)作。

我們也是通曉多種語(yǔ)言的組織,因?yàn)槲覀兪褂昧撕芏嗾Z(yǔ)言。并且這些服務(wù)(和基礎(chǔ)設(shè)施支持)的許多部分是使用Golang開(kāi)發(fā)的。事實(shí)上,我們都是早期Golang的使用者:目前,我們已在產(chǎn)品中使用Golang有兩年半的時(shí)間。相關(guān)項(xiàng)目包括:

  • Bazooka,我們內(nèi)部服務(wù)平臺(tái);產(chǎn)品思想非常類(lèi)似于Keroku或Flynn。

  • 我們外圍的傳輸層使用通用的nginx, HAProxy等等,但是它們要和Golang服務(wù)協(xié)作。

  • 我們的音頻存儲(chǔ)在AWS S3上,但是上傳、轉(zhuǎn)碼和生成鏈接等需要Golang服務(wù)協(xié)調(diào)處理。

  • 搜索采用了Elasticsearch, 探測(cè)使用復(fù)雜的機(jī)器學(xué)習(xí)模型,但是它們都與由Golang開(kāi)發(fā)的基礎(chǔ)設(shè)施相集成。

  • Prometheus,一個(gè)早期階段的遙測(cè)系統(tǒng)純粹是有Golang開(kāi)發(fā)。

  • 當(dāng)前,流處理采用Cassandra,但是我們正打算(幾乎)完全使用Golang代替。

  • 我們也正在試驗(yàn)用Golnag開(kāi)發(fā)的HTTP流媒體直播服務(wù)。

  • 許多其他面向產(chǎn)品的小服務(wù)。

這些項(xiàng)目大概有六個(gè)團(tuán)隊(duì)開(kāi)發(fā),包括十多人的SoundCloud勤雜工,他們中的大部分會(huì)全職使用Golang。畢竟在這個(gè)時(shí)候,這些項(xiàng)目和這樣混雜的工程師中,我們已經(jīng)逐漸形成了在產(chǎn)品中使用Golang的***實(shí)踐方法。我們的這些教訓(xùn)將對(duì)其他開(kāi)始大舉投資Golang的組織提供幫助。

開(kāi)發(fā)環(huán)境

在我們的筆記本上,我們已經(jīng)設(shè)定了單一、全局的GOPATH。就個(gè)人而言,我喜歡使用$HOME,但是許多其他人使用$HOME下的一個(gè)子目錄。我們克隆倉(cāng)庫(kù)進(jìn)入GOPATH的相對(duì)路徑,然后就可直接工作。即,

  1. $ mkdir -p $GOPATH/src/github.com/soundcloud  
  2. $ cd $GOPATH/src/github.com/soundcloud  
  3. $ git clone git@github.com:soundcloud/roshi 

我們中的許多人在早期一直和約定俗成的事情做斗爭(zhēng),以保持我們自己特有的代碼組織方法。事實(shí)上,它根本不值得如此麻煩。

對(duì)于編輯器,許多用戶(hù)使用Vim以及各種插件。(我使用的vim-go就不錯(cuò)。)還有許多人,包括我自己也是,結(jié)合GoSublime使用Sublime Text。也有少數(shù)人使用Emacs,但沒(méi)有人用IDE。我不確定這是不是個(gè)***的實(shí)踐,但標(biāo)出來(lái)挺有趣的。

庫(kù)結(jié)構(gòu)

我們的***實(shí)踐是確保任何事情簡(jiǎn)單。許多服務(wù)源碼半打包在main包中。

  1. github.com/soundcloud/simple/  
  2.     README.md  
  3.     Makefile  
  4.     main.go  
  5.     main_test.go  
  6.     support.go  
  7.     support_test.go 

比如我們的搜索調(diào)度器,兩年后仍然是這樣。在確定需要前不要?jiǎng)?chuàng)建新結(jié)構(gòu)。

也許在某些時(shí)候你需要?jiǎng)?chuàng)建一個(gè)新的支持包。在你的main庫(kù)中使用子目錄,并使用完整的限定名導(dǎo)入。如果該包只有一個(gè)文件或一個(gè)結(jié)構(gòu),那么它肯定不需要分拆出來(lái)。

有時(shí)一個(gè)倉(cāng)庫(kù)中需要包含多個(gè)二進(jìn)制文件;比如這個(gè)任務(wù)需要一個(gè)服務(wù),一個(gè)工作進(jìn)程,或一個(gè)監(jiān)控。在這種情況下,將每個(gè)二進(jìn)制文件放在特定main包的單獨(dú)的子目錄中,并使用其他的子目錄(或包)來(lái)實(shí)現(xiàn)共享的功能。

  1. github.com/soundcloud/complex/  
  2.     README.md  
  3.     Makefile  
  4.     complex-server/  
  5.         main.go  
  6.         main_test.go  
  7.         handlers.go  
  8.         handlers_test.go  
  9.     complex-worker/  
  10.         main.go  
  11.         main_test.go  
  12.         process.go  
  13.         process_test.go  
  14.     shared/  
  15.         foo.go  
  16.         foo_test.go  
  17.         bar.go  
  18.         bar_test.go 

請(qǐng)注意,不要引入asrc目錄。由于vendor子目錄異常(下面介紹更多內(nèi)容)不要在倉(cāng)庫(kù)中包含src目錄,或?qū)⑵涮砑拥紾OPATH。

格式及樣式

通常來(lái)說(shuō),首先配置你的編輯器保存代碼交給go fmt(或goimports),使用默認(rèn)參數(shù)。這意味使用tab縮進(jìn),用空格對(duì)齊。格式不正確的代碼將不能提交。

過(guò)去的風(fēng)格指南非常廣泛,但谷歌最近發(fā)布了他們的 代碼審查意見(jiàn) 文檔,這幾乎就是我們應(yīng)遵守的公約。因此,我們使用它。

實(shí)際上我們把它推進(jìn)了一點(diǎn):

  • 避免命名返回參數(shù),除非他們能明確和顯著地提高透明度。

  • 避免用 make 和 new,除非他們是必要的(new(int),或 make(Chan int)),或者我們能提前知道要分配的東西的尺寸( make(map[int]string,n),或 make([]int,0,256))。

  • 使用 struct{} 作為標(biāo)記值,而不是布爾或接口{}。例如,集合是 map[string]struct{};信道是 chan struct{}。它明確標(biāo)明了信息的明確缺乏。

打斷長(zhǎng)行的參數(shù)也很好。那更象是Java的風(fēng)格:

  1. // 不要這樣。  
  2. func process(dst io.Writer, readTimeout,  
  3.     writeTimeout time.Duration, allowInvalid bool,  
  4.         max int, src <-chan util.Job) {  
  5.     // ...  

這樣會(huì)更好:

  1. func process(  
  2.     dst io.Writer,  
  3.     readTimeout, writeTimeout time.Duration,  
  4.     allowInvalid bool,  
  5.     max int,  
  6.     src <-chan util.Job,  
  7. ) {  
  8.     // ...  

當(dāng)構(gòu)造對(duì)象時(shí)也同樣分為多行:

  1. f := foo.New(foo.Config{
  
  2.     Site: "zombo.com",
  
  3.     Out:  os.Stdout,
  
  4.     Dest: conference.KeyPair{
  
  5.         Key:   "gophercon",  
  6.         Value: 2014,  
  7.     },  
  8. }) 

另外,當(dāng)分配新的對(duì)象時(shí),在初始化部分傳遞成員值(如上面)比下面這樣過(guò)后設(shè)置要好。

  1. // 不要這樣。  
  2. f := &Foo{} // or, even worse: new(Foo)  
  3. f.Site = "zombo.com" 
  4. f.Out = os.Stdout  
  5. f.Dest.Key = "gophercon" 
  6. f.Dest.Value = 2014 

配置

我們嘗試了通過(guò)多種方式向Go程序傳遞配置:解析配置文件,用 os.Getenv 直接從環(huán)境中提取配置,各種增值flag解析包。***,最合乎經(jīng)濟(jì)原則的就是普通的package flag,它的嚴(yán)格類(lèi)型和簡(jiǎn)單語(yǔ)義對(duì)我們所需的一切都絕對(duì)夠用而且夠好。

我們主要部署12-Factor 的應(yīng)用,12-Factor 應(yīng)用程序通過(guò)環(huán)境傳遞配置。但即使這樣,我們也使用一個(gè)啟動(dòng)腳本來(lái)把環(huán)境變量轉(zhuǎn)換為flags。Flags作為程序及其運(yùn)行環(huán)境之間的一個(gè)明確和全文檔化的表面區(qū)域。他們對(duì)于了解和操作程序來(lái)說(shuō)是非常寶貴的。

一個(gè)關(guān)于flags的不錯(cuò)的習(xí)慣是把他們定義到你的main函數(shù)中。這樣就能防止你在代碼中隨意的將他們作為全局變量使用,這使你嚴(yán)格的遵守依賴(lài)注入從而方便測(cè)試。

  1. func main() {  
  2.     var (  
  3.         payload = flag.String("payload""abc""payload data")  
  4.         delay   = flag.Duration("delay", 1*time.Second, "write delay")  
  5.     )  
  6.     flag.Parse()  
  7.     // ...  

日志和遙測(cè)

我們嘗試過(guò)幾個(gè)日志框架,他們提供像日志級(jí)別,調(diào)試,路由輸出,自定義格式化等等功能。最終我們選定package log。因?yàn)槲覀冎挥涗浛刹僮餍畔ⅰ?這意味著需要人工處理的 serious, panic級(jí)別的錯(cuò)誤,或者結(jié)構(gòu)化數(shù)據(jù)會(huì)被其他機(jī)器消耗。 舉個(gè)例子,搜索轉(zhuǎn)發(fā)器發(fā)送每一個(gè)它使用上下文信息處理的請(qǐng)求,因此我們的分析工作流可以看到新西蘭的人們經(jīng)常搜索 Lorde, 或者隨便什么。

我們考慮到遙測(cè),在一個(gè)運(yùn)行過(guò)程中釋放出的任何其他量:請(qǐng)求響應(yīng)時(shí)間,QPS,運(yùn)行錯(cuò)誤,隊(duì)列深度等等。并且遙測(cè)基本上包括兩種模式:push和pull。

  • push意味著釋放指標(biāo)到一個(gè)已知的系統(tǒng)。例如Graphite, Statsd, and AirBrake

  • pull意味著在一些已知的位置暴露指標(biāo),并允許已知的系統(tǒng)去擦除它們。例如,expvar和Prometheus(或許還有其他的)

當(dāng)然兩種方式都有自己的存在性。當(dāng)你開(kāi)始使用時(shí),push是直觀和簡(jiǎn)單的。但是推送指標(biāo)的增長(zhǎng)卻有悖常理:你得到的越大,成本越高。我們過(guò)去發(fā)現(xiàn)在特定規(guī)模大小的基礎(chǔ)設(shè)施上,pull是該尺度下的唯一模型。那也有許多值能反映一個(gè)運(yùn)行的系統(tǒng)。所以,***的實(shí)踐是:expvar或者類(lèi)似風(fēng)格的。

測(cè)試和驗(yàn)證

在一年的過(guò)程中我們嘗試了許多的測(cè)試庫(kù)和框架,但是很快放棄了他們中的大部分,今天我們所有的測(cè)試通過(guò)數(shù)據(jù)驅(qū)動(dòng)(表驅(qū)動(dòng))測(cè)試,用普通的包測(cè)試。我們沒(méi)有強(qiáng)烈或者明確的抱怨測(cè)試/檢查包,除此之外,他們根本沒(méi)有提供巨大的價(jià)值。有一件事情是有幫助的:reflect.DeepEqual讓你更簡(jiǎn)單的對(duì)任意值進(jìn)行比較(例如expected對(duì)got)。

包測(cè)試是面向單元測(cè)試的,對(duì)于集成測(cè)試,就會(huì)有點(diǎn)麻煩。運(yùn)行的外部服務(wù)依賴(lài)于你的集成環(huán)境,但是我們找到了一個(gè)好的方式集成他們。寫(xiě)一個(gè)integration_test.go,給它一個(gè)integration的構(gòu)建標(biāo)簽。定義(全局)標(biāo)志,比如服務(wù)地址和連接字符串,用他們?cè)谀愕臏y(cè)試中。

  1. // +build integration  
  2.    
  3. var fooAddr = flag.String(...)  
  4.    
  5. func TestToo(t *testing.T) {  
  6.     f, err := foo.Connect(*fooAddr)  
  7.     // ...  

go test 和 go build 一樣建立標(biāo)簽,所以你可以調(diào)用 go test -tags=integration 。它也綜合了 flag.Parse 包的 main,所以任何被聲明和可見(jiàn)的 flags 將被處理和提供給你的測(cè)試。

通過(guò)驗(yàn)證,我的意思是靜態(tài)代碼驗(yàn)證。幸運(yùn)的是,Go 有一些很好的工具。我發(fā)現(xiàn)當(dāng)考慮使用哪種工具時(shí)考慮編寫(xiě)代碼的階段很有用。

當(dāng)做這種事時(shí) 使用這個(gè)
保存 go fmt(或 goimports)
構(gòu)建 go vet,golint, 或者 go test
部署 go test -tags=integration

 

插曲
 

到目前為止,還沒(méi)東西過(guò)于瘋狂。當(dāng)做調(diào)查編撰這個(gè)列表的時(shí)候,讓我注意的只是如何。。。。。。結(jié)論如何的無(wú)趣。讓人沉悶。我想強(qiáng)調(diào)這些非常輕量,純標(biāo)準(zhǔn)庫(kù)的約定能真正推廣到大群體的開(kāi)發(fā)人員和多元化的項(xiàng)目生態(tài)系統(tǒng)。你絕對(duì)不會(huì)僅僅因?yàn)槟愕拇a庫(kù)已經(jīng)超過(guò)一定的規(guī)模,或者只是因?yàn)樗?em>可能 增長(zhǎng)超過(guò)一定行數(shù), 而需要你自己的查錯(cuò)框架,或者測(cè)試庫(kù)。你真的是不會(huì)需要它的。標(biāo)準(zhǔn)的語(yǔ)法和用法在代碼大規(guī)模時(shí)仍然功能優(yōu)雅。 

依賴(lài)管理

依賴(lài)管理! 呃! ᕕ( ᐛ )ᕗ

依賴(lài)管理的狀態(tài)在 Go 生態(tài)系統(tǒng)中是一個(gè)熱門(mén)的爭(zhēng)論點(diǎn),我們還沒(méi)有想到***的解決方案。但是,我們選用了一個(gè)似乎不錯(cuò)的妥協(xié)方案。

你的項(xiàng)目有多么重要? 你的依賴(lài)管理方案是…
嗯… go get -d,然后祈禱!
很好. VENDORING

(值得提出的是,我們有令人震驚數(shù)量的長(zhǎng)期產(chǎn)品服務(wù),依然依賴(lài)于***個(gè)選項(xiàng).然而,因?yàn)槲覀円话銢](méi)有使用太多第三方代碼,以及主要問(wèn)題通常在編譯階段就被檢測(cè)到,我們僥幸規(guī)避了這個(gè)問(wèn)題.)

Vendoring意味著拷貝依賴(lài)到項(xiàng)目代碼庫(kù),然后在編譯的時(shí)候使用它們.依賴(lài)于你下載的內(nèi)容,這里有兩個(gè)vendoring的***實(shí)踐.

下載  Vendor目錄名 過(guò)程
二進(jìn)制 _vendor 加GOPATH前綴編譯
庫(kù) vendor 重寫(xiě)import語(yǔ)句

如果下載二進(jìn)制,就在代碼庫(kù)的根目錄創(chuàng)建一個(gè)_vendor子目錄.(帶上下劃線,這樣,go工具就會(huì)在處理時(shí)忽略它,例如go test ./...)對(duì)待它就像對(duì)待GOPATH一樣; 例如,拷貝這個(gè)依賴(lài)github.com/user/dep 到 _vendor/src/github.com/user/dep. 然后,編寫(xiě)一個(gè)所謂的神圣的編譯過(guò)程,它將_vendor加入到可能存在的GOPATH之中. (記住: GOPATH 實(shí)際是一個(gè)路徑的列表,當(dāng)go工具處理import時(shí),會(huì)按順序搜索這個(gè)列表.)例如,你可能擁有一個(gè)頂層的Makefile文件,如下所示:

  1. GO ?= go  
  2. GOPATH := $(CURDIR)/_vendor:$(GOPATH)  
  3.    
  4. all: build  
  5.    
  6. build:  
  7.     $(GO) build 

如果你正在下載某個(gè)類(lèi)庫(kù)在你的根存儲(chǔ)庫(kù)上創(chuàng)建一個(gè)vendor子目錄。處理這件事就像在包目錄上加一個(gè)前綴。舉例來(lái)說(shuō),拷貝來(lái)自于github.com/user/dep的項(xiàng)目放到vendor/user/dep。在這之后,重寫(xiě)你所有的引入(import),及其相互關(guān)系。此時(shí)是很痛苦的,當(dāng)剩下的內(nèi)容需要go get兼容的時(shí)候,看起來(lái)最有效的方式是確保事實(shí)上可重新構(gòu)建(actually-reproducible build)。值得注意的是,我們?cè)趯?shí)踐中很少去下載類(lèi)庫(kù),因此這個(gè)辦法雖然麻煩卻很有效。

如何在實(shí)際中拷貝一個(gè)依賴(lài)關(guān)系到你自己的存儲(chǔ)庫(kù)是另外一個(gè)熱門(mén)的話題。最簡(jiǎn)單的方法是從一個(gè)克隆(clone)中手動(dòng)復(fù)制文件,如果你不關(guān)心上游部門(mén)的推送,這可能是***的答案。有些人使用git子模塊,但我們發(fā)現(xiàn)它們非常違反直覺(jué)并難以管理(對(duì)許多 來(lái)說(shuō)也是這樣,這是有記錄的)。我們對(duì)于git子目錄(的管理)已經(jīng)很成功,他工作起來(lái)就像是子模塊。還有大量的工具是用來(lái)自動(dòng)處理這項(xiàng)工作的?,F(xiàn)在,它看起來(lái)就像godep發(fā)展非常積極,而且還很值得研究。

構(gòu)建與部署

構(gòu)建與部署有其技巧性,因此它與你的操作環(huán)境耦合緊密。我要描述下我們的場(chǎng)景,因?yàn)槲艺J(rèn)為它是個(gè)好模型,但它可能無(wú)法直接應(yīng)用到你的組織機(jī)構(gòu)中。

就構(gòu)建而言,我們通常直接使用 go build 來(lái)開(kāi)發(fā),以及一個(gè) Makefile 用于剪裁官方構(gòu)建。這主要是因?yàn)槲覀兪煜ざ喾N語(yǔ)言,并且我們的工具使用需要做到最小功能合集(最小公倍數(shù))。并且,我們的構(gòu)建系統(tǒng)始于一個(gè)空環(huán)境,也需要自備編譯器( Makefile 文件很難看?。?。

對(duì)部署而言,對(duì)我們***的吸引是無(wú)狀態(tài)之于有狀態(tài)。

模式 樣例 模型 部署名稱(chēng) 部署形式
無(wú)狀態(tài) Request router 12-Factor Scaling Containers
有狀態(tài) Redis None, really Provisioning Containers?

我們主要部署無(wú)狀態(tài)的服務(wù),方式類(lèi)似于 Heroku。

  1. $ git push bazooka master  
  2. $ bazooka scale -r <new> -n 4 ...  
  3. $ # validate  
  4. $ bazooka scale -r <old> -n 0 ... 

英文原文:Go: Best Practices for Production Environments

譯文鏈接:http://www.oschina.net/translate/go-in-production

責(zé)任編輯:林師授 來(lái)源: 開(kāi)源中國(guó)社區(qū) 編譯
相關(guān)推薦

2018-08-28 07:30:50

云安全云服務(wù)多云

2022-10-30 23:13:30

contextGo語(yǔ)言

2022-04-18 09:41:14

Go架構(gòu)設(shè)計(jì)

2017-04-26 15:00:00

機(jī)器學(xué)習(xí)TensorFlow模型部署

2021-01-27 11:53:08

工具Go 開(kāi)發(fā)

2015-04-28 09:12:10

云計(jì)算軟件無(wú)序

2017-09-07 15:53:51

Go支付Java

2022-10-25 12:11:13

2014-03-05 17:17:09

LuapythonR

2023-09-21 22:02:22

Go語(yǔ)言高級(jí)特性

2014-12-23 14:36:32

PHP

2012-07-18 15:30:58

iOS交互原型

2009-11-26 10:31:55

配置IPS最佳實(shí)踐

2024-04-28 14:46:55

gozero微服務(wù)技巧

2019-11-01 10:27:48

GoJava語(yǔ)言

2011-12-01 15:54:56

機(jī)房環(huán)境數(shù)據(jù)中心

2010-11-23 13:56:46

伊頓云計(jì)算

2023-09-13 08:00:00

JavaScript循環(huán)語(yǔ)句

2015-09-15 16:01:40

混合IT私有云IT架構(gòu)

2011-08-18 11:05:21

jQuery
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)