go項目的一些心得

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
spacex

最近小夥伴們剛完成廣告系統,第二個直接服務於業務的項目。踩了一些坑,更收穫了不少知識。總結出來與大家分享,沒什麼高大尚技術,都是周邊的小技巧,加深對 go 語言的理解,適合新手,老鳥勿噴。

包管理

很多人都認為 go 的包管理不夠友好,深有感覺。特別是在 github 上給別人提 patch, 我先 fork 到自已目錄下面,如果原作者有引用自已路徑下面的庫,這就麻煩了。

另外一個是版本管理,每個人的 gopath 下面同樣的庫可能有不同版本,官方提供了一個 Godep 來控製版本,我看很多開源項目也在用。但是如果想管理除 go 以外的依賴呢?

我們使用相對路徑的方式,將引用到的庫集中放到 submodule 中,如:


包管理

我司將所有語言第三方庫都放到 tinder 裡面,包括多個組之間共用的 thrfit IDL 檔案。Go 第三方庫都放到 golang/lib 目錄下面,共用的內部庫放到 golang/src/common 下面,每次 install 編譯器時將 gopath 指定到當前項目下的相對目錄。

更新20160629:現在依賴使用govender,第三方的IDL使用submodule

逾時控制與請求跟蹤

由於業務對時延要求高,給我們定 50ms 逾時時間。大家肯定會想到用 Channel 和 timer 來做控制,但是我們還想跟蹤請求在內部的一系列操作,否則 Debug 日誌一大堆,無法定位。

此時想到了 golang.org/x/net/context 庫,官方文檔很詳細,用於跨 API 呼叫很方便,vitess 中大量使用這個庫。

// A Context carries a deadline, a cancelation signal, and other values across

// API boundaries.

// Context's methods may be called by multiple goroutines simultaneously.

type Context interface {

// Deadline returns the time when work done on behalf of this context

// should be canceled.  Deadline returns ok==false when no deadline is

// set.  Successive calls to Deadline return the same results.

Deadline() (deadline time.Time, ok bool)

// Done returns a channel that's closed when work done on behalf of this

// context should be canceled.  Done may return nil if this context can

// never be canceled.  Successive calls to Done return the same value.

// See http://blog.golang.org/pipelines for more examples of how to use

// a Done channel for cancelation.

Done() <-chan struct{}

// Value returns the value associated with this context for key, or nil

// if no value is associated with key.  Successive calls to Value with

// the same key returns the same result.

// Use context values only for request-scoped data that transits

// processes and API boundaries, not for passing optional parameters to

// functions.

// Packages that define a Context key should provide type-safe accessors

// // userKey is the key for user.User values in Contexts.  It is

// // unexported; clients use user.NewContext and user.FromContext

// // instead of using this key directly.

Value(key interface{}) interface{}

}

一個請求過來,每一次流轉都要攜帶 context.Context, 並且首先檢測是否逾時,如果逾時或是被取消,那麼直接返回。另外 context.Context 會攜帶每次請求 ID,這是由業務傳過來的欄位,如果為空白,內部會產生一個 uuid 來標識。


最終執行的代碼邏輯

逾時參數由業務傳過來,根據 timeout 產生 context.Context,最終函數要麼由 ctx.Done 逾時返回,要麼從 rr channel 中擷取業務結果返回。 真實業務請求會開啟一個匿名 goroutine, 傳入的 context.Context 攜帶了 logid, 內部打日誌都會先列印 logid.


cancel signal

在每個耗時請求(redis/mysql)的入口,都會先檢測是否逾時。

goroutine和panic

這塊學藝不精,不像 actor 有父子關係,函數派生出來的 goroutine 如果panice 會掛掉整個程式,比如如下代碼:


錯誤樣本

最開始程式如,原以為會捕獲到 do_something 產生的 panic, 還是太年輕啊。要將 recover 放置在 go func 入口。

緩衝髒資料

我們會在 redis 緩衝使用者資訊,到期時間 6 小時,如果沒有再 fallback 到資料庫,另外還有一個程式內建 lru cache. 

程式升級後,發現測試邏輯不對,uid 始終為0,fix 這個問題後,緩衝這時就出現了髒資料。這時有兩個辦法,選擇了第2個。

1. 使用 redis-port 批量清除無效緩衝

2. 再次更新程式,內部修訂錯誤資料

php thrift 逾時問題

這個問題蠻頭痛,網上也有人遇到過 thrift中的逾時(timeout)坑。底層有三個逾時時間 connect, send 和 recv,最初都設定的 100ms,線上每天大量逾時報錯,後來我們將 recv timeout 調到 1000ms 線上就安靜了。

另外兩個 connect, send 仍然是 100ms,我們更傾向於底層驅動的逾時時間稍長一些,由業務層來控制逾時 ( context 庫)。

對象池

對象池是不同於串連池,兩個概念的東西。串連池特指 redis/mysql 的長串連,常駐記憶體。而對象池是內部執行個體,使用對象池可以減少程式 GC 壓力。目前常用的有兩種  sync.Pool 和 channel 類比的對象池。官方有對 sync.Pool 的詳細說明,對象會在兩個 GC 之間被回收釋放,而 channel 則會常駐。


對象池

代碼很簡單也易懂,Get 時 channel 有資料就返回,沒有直接 New。至於 channel 緩衝大小,要根據業務壓力來定。

內部服務註冊

在全域 map 註冊服務,這也算是 go 程式標配了,最出名的就是官方 database 庫註冊 mysql driver 的代碼


服務註冊

實現在 driver.Driver 介面的服務,直接註冊進來即可,使用時直接根據 name 找到 driver。

ServerOnRun

服務內部模組有大量初始化的需求,對於全域變數等直接扔到 init() 函數裡即可,但是對於依賴外部服務 (mysql/redis/servervice),在程式啟動時串連控制代碼都不存在,就不能扔到 init() 裡。

一種做法就是在各個模組裡寫 init_xx()等方法,然後在 main() 啟動初始化外部配置後,去調用,不過這樣在 main 裡維護就很麻煩。

所以要在全域定義 ServerOnRun, 每個無法由 init() 完成的初始化都在這裡進行註冊,最後由 main 遍曆 ServerOnRun 來執行即可。

thrift欄位變更問題

業務升級改動,時常會加欄位,並且為了相容現有代碼,必須設為 optional。另外有時還遇到要將欄位類型由 int 換成 string 的問題,比較麻煩,前期還是要設計好

json序列化

程式內部有大量的json序列化需求,官方的稍慢,採用比較流行的 ffjons 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.