go語言 nsq源碼解讀三 nsqlookupd源碼nsqlookupd.go

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

從本節開始,將逐步閱讀nsq各模組的代碼。

讀一份代碼,我的思路一般是:

1、瞭解用法,知道了怎麼使用,對理解代碼有宏觀上有很大協助。如第一篇文章:go語言nsq源碼解讀-基本介紹。

2、瞭解各大模組的功能特點,同時再想想,如果讓自己來實現這些模組,會是怎麼樣的思路。如第二篇文章:go語言nsq源碼解讀二 nsqlookupd、nsqd與nsqadmin

3、開始上手試讀,為不打擊閱讀的積極性,可以選擇一個簡單的模組,或者某一個功能點開始讀。對nsq而言,開啟源碼的目錄看一下,發現nsqlookupd和nsqadmin的代碼相對較少,而nsqd的代碼量較多。再比較nsqlookupd和nsqadmin,發現nsqadmin下還有一個templates目錄,這大概是在第一篇文章裡用來顯示裡的網頁的模板檔案。再考慮到nsqlookupd的中樞作用,我決定從nsqlookupd的代碼開始讀起。

4、讀代碼的第一遍,偏向於讀懂,瞭解功能的實現即可。所有代碼全部讀過一往遍後,看一下檔案名稱,就能知道這個檔案裡的代碼實現了什麼功能。碰到讀不懂的地方,可以通過加註釋輸出變數、打斷點跟蹤等方式輔助學習。

5、之後讀第二遍,理解宏觀的架構體系,心裡始終要想的問題是: 為什麼要這麼做?如果是我,我會怎麼做?這兩種做法有什麼利弊?多揣摩,細研讀,並把體會到的精華思想吸引牢記,轉為已有。

6、再之後,可以讀第三遍,這基本就是撥雲見日的境界了,對代碼了如之掌,考慮是否有更好的實現,然後可以對代碼動手改造。如果在代碼還沒讀懂前改代碼,那屬於在給白雪公主喂屎,噁心的要死了。

好了,廢話就說到這裡了,給大學推薦一本學習go語言的書籍:Go Web 編程,中文編寫,內容階層清晰,知識全面,適合入門閱讀。

下面我們開始nsqlookupd的源碼解讀。

nsqlookupd的代碼位於源碼根目錄的nsqlookupd下。目錄下共十一個檔案,去掉README.md檔案和兩個以_test.go結尾(這是單元測試檔案)的檔案,共有八個檔案。另外nsqlookupd還會用到util目錄下的一些功能代碼,這個也會閱讀到。對代碼的解釋我都會放在注釋裡,等第一遍代碼閱讀完,我會把所有代碼打包傳上來。

OK,首先從nsqlookupd\nsqlookupd.go檔案開始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package nsqlookupd

import (
"log"
"net"

"github.com/bitly/nsq/util"
)

type NSQLookupd struct {
//在檔案nsqlookupd\options.go中定義,記錄NSQLookupd的配置資訊
options *nsqlookupdOptions

//nsqlookupd監聽TCP資料的地址
tcpAddr *net.TCPAddr

//nsqlookupd監聽HTTP資料的地址
httpAddr *net.TCPAddr

//使用上面的tcpAddr建立的Listener
tcpListener net.Listener

//使用上面的httpAddr建立的Listener
httpListener net.Listener

//在util\wait_group_wrapper.go檔案中定義,與sync.WaitGroup相關,用於線程同步。
waitGroup util.WaitGroupWrapper

//在nsqlookupd\registration_db.go檔案中定義,看字面意思DB(database)就可知道這涉及到資料的存取
DB *RegistrationDB
}
//
//根據配置的nsqlookupdOptions建立一個NSQLookupd的執行個體
//
func NewNSQLookupd(options *nsqlookupdOptions) *NSQLookupd {

//使用配置參數的TCPAddress建立TCP地址,用於和nsqd通訊。
tcpAddr, err := net.ResolveTCPAddr("tcp", options.TCPAddress)
if err != nil {
log.Fatal(err)
}

//使用配置參數的HTTPAddress參數,建立http連結,可以供nsqadmin訪問,以讀取統計資料
httpAddr, err := net.ResolveTCPAddr("tcp", options.HTTPAddress)
if err != nil {
log.Fatal(err)
}

return &NSQLookupd{
options: options,
tcpAddr: tcpAddr,
httpAddr: httpAddr,
DB: NewRegistrationDB(),
}
}

//
//Main函數,啟動時首先執行本函數
//補註:閱讀options.go時,發現nsqlookupd啟動時,首先啟動並執行並不是這個Main方法。而是apps\nsqlookupd\nsqlookupd.go裡的main方法,這個下篇文章會提到。
//
func (l *NSQLookupd) Main() {
//定義了Context的執行個體,Context在nsqlookupd\context.go檔案中定義,其中只包含了一個nsqlookupd的指標,注意花括弧裡是字元L的小寫,不是數字一.
context := &Context{l}

//監聽TCP
tcpListener, err := net.Listen("tcp", l.tcpAddr.String())
if err != nil {
log.Fatalf("FATAL: listen (%s) failed - %s", l.tcpAddr, err.Error())
}

//把Listener存在NSQLookupd的struct裡
l.tcpListener = tcpListener

//建立tcpServer的執行個體,tcpServer在nsqlookupd\tcp.go檔案中定義,用於處理TCP串連中接收到的資料。通過前面閱讀知道,context裡只是一個NSQLookupd類型的指標。
tcpServer := &tcpServer{context: context}

//調用util.TCPServer方法(在util\tcp_server.go中定義)開始接收監聽並註冊handler。 //傳入的兩個參數第一個是tcpListener
//第二個tcpServer實現了util\tcp_server.go中定義的TCPHandler介面。
//tcpServer接到TCP資料時,會調用其Handle方法(見nsqlookupd\tcp.go)來處理。
//此處為何要用到waitGroup,目前還比較迷糊
l.waitGroup.Wrap(func() { util.TCPServer(tcpListener, tcpServer) })

//監聽HTTP
httpListener, err := net.Listen("tcp", l.httpAddr.String())
if err != nil {
log.Fatalf("FATAL: listen (%s) failed - %s", l.httpAddr, err.Error())
}

//把Listener存在NSQLookupd的struct裡
l.httpListener = httpListener

//建立httpServer的執行個體,httpServer在nsqlookupd\http.go檔案中定義
httpServer := &httpServer{context: context}

//調用util.HTTPServer方法(在util\http_server.go中定義)開始在指定的httpListener上接收http串連。
//傳入的兩個參數第一個是httpListener
//第二個httpServer定義了http handler,用於處理HTTP請求。
//同樣,對waitGroup的用法還不是很理解。
l.waitGroup.Wrap(func() { util.HTTPServer(httpListener, httpServer) })

//經過以上閱讀,基本上會有兩個發現:
//1、tcpServer和httpServer的代碼很相似。
//2、util\tcp_server.go在註冊handler之前,先定義了一個介面,而tuil\http_server.go卻沒有。
//如果再仔細研究這兩個檔案,還會發現,tcp_server裡,通過go handler.Handle(clientConn)這段代碼,把串連clientConn做為變數,傳給了handler
//而在http_server,是把handler傳給了HTTPServer
//這主要是因為net/http包和net包用法不一樣,net/http做了進一步有封裝。
}

//
//退出 關閉兩個Listener
//
func (l *NSQLookupd) Exit() {
if l.tcpListener != nil {
l.tcpListener.Close()
}

if l.httpListener != nil {
l.httpListener.Close()
}
l.waitGroup.Wait()
}

上面的代碼裡共涉及到幾個外部檔案:
nsqlookupd\options.go
nsqlookupd\context.go
nsqlookupd\tcp.go
util\tcp_server.go
nsqlookupd\http.go
util\http_server.go
util\wait_group_wrapper.go
nsqlookupd\registration_db.go

這些檔案,將在後續文章中繼續閱讀,其中下一篇為:

go語言nsq源碼解讀四 nsqlookupd源碼options.go、context.go和wait_group_wrapper.go

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.