go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go

转自:http://www.baiyuxiong.com/?p=891


从本节开始,将逐步阅读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  &amp ;NSQLookupd {
options : options ,
tcpAddr : tcpAddr ,
httpAddr : httpAddr ,
DB : NewRegistrationDB ( ) ,
}
}

//
//Main函数,启动时首先执行本函数
//补注:阅读options.go时,发现nsqlookupd启动时,首先运行的并不是这个Main方法。而是apps\nsqlookupd\nsqlookupd.go里的main方法,这个下篇文章会提到。
//
func  (*NSQLookupd ) Main ( )  {
//定义了Context的实例,Context在nsqlookupd\context.go文件中定义,其中只包含了一个nsqlookupd的指针,注意花括号里是字符L的小写,不是数字一.
context  :=  &amp ;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  :=  &amp ;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  :=  &amp ;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  (*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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值