从本节开始,将逐步阅读nsq各模块的代码。

读一份代码,我的思路一般是:

1、了解用法,知道了怎么使用,对理解代码有宏观上有很大帮助。

2、了解各大模块的功能特点,同时再想想,如果让自己来实现这些模块,会是怎么样的思路。

3、开始上手试读,为不打击阅读的积极性,可以选择一个简单的模块,或者某一个功能点开始读。对nsq而言,打开源码的目录看一下,发现nsqlookupd和nsqadmin的代码相对较少,而nsqd的代码量较多。再比较nsqlookupd和nsqadmin,发现nsqadmin下还有一个templates目录,这大概是在第一篇文章里用来显示截图里的网页的模板文件。再考虑到nsqlookupd的中枢作用,我决定从nsqlookupd的代码开始读起。

4、读代码的第一遍,偏向于读懂,了解功能的实现即可。所有代码全部读过一遍后,看一下文件名,就能知道这个文件里的代码实现了什么功能。碰到读不懂的地方,可以通过加注释输出变量、打断点跟踪等方式辅助学习。

5、之后读第二遍,理解宏观的架构体系,心里始终要想的问题是: 为什么要这么做?如果是我,我会怎么做?这两种做法有什么利弊?多揣摩,细研读,并把体会到的精华思想吸引牢记,转为已有。

6、再之后,可以读第三遍,这基本就是拨云见日的境界了,对代码了如之掌,考虑是否有更好的实现,然后可以对代码动手改造。如果在代码还没读懂前改代码,那属于在给白雪公主喂屎,恶心的要死了。

下面我们开始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/nsqio/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源码nsqlookupd.go的更多相关文章

  1. DRF(1) - REST、DRF(View源码解读、APIView源码解读)

    一.REST 1.什么是编程? 数据结构和算法的结合. 2.什么是REST? 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下: /books/ /get_all_books/ 访问所 ...

  2. REST、DRF(View源码解读、APIView源码解读)

    一 . REST            前言 1 . 编程 : 数据结构和算法的结合 .小程序如简单的计算器,我们输入初始数据,经过计算,得到最终的数据,这个过程中,初始数据和结果数据都是数据,而计算 ...

  3. Restful 1 -- REST、DRF(View源码解读、APIView源码解读)及框架实现

    一.REST 1.什么是编程? 数据结构和算法的结合 2.什么是REST? - url用来唯一定位资源,http请求方式来区分用户行为 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下 ...

  4. 5.2 spring5源码--spring AOP源码分析三---切面源码分析

    一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs ...

  5. mybatis源码解读(三)——数据源的配置

    在mybatis-configuration.xml 文件中,我们进行了如下的配置: <!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境常用: ...

  6. jQuery源码解读三选择器

    直接上jQuery源码截取代码 // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ i ...

  7. Python Web Flask源码解读(三)——模板渲染过程

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  8. ConcurrentHashMap源码解读三

    今天首先讲解helpTransfer方法 final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) ...

  9. spring源码解读之 JdbcTemplate源码

    原文:https://blog.csdn.net/songjinbin/article/details/19857567 在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数 ...

随机推荐

  1. Qt5中this application has requested the runtime to terminate it in an unusual way 无法运行问题的解决

    在windows平台使用Qt5.8mingw版写出的程序,在Qt中运行正常,而以release的形式编译并且补充完必要的dll文件后,在其他电脑上运行出现了以下问题: 经过查阅许多资料和亲身实验,终于 ...

  2. javascript 调试 & console.table()

    通过console.table()打印数组.对象 一般我们都是通过console.log()打印数组或对象,但console.table()打印数组.对象更直观: console.table(empi ...

  3. ios项目开发汇总

    UI界面 iOS和Android 界面设计尺寸规范  http://www.alibuybuy.com/posts/85486.html iPhone app界面设计尺寸规范  http://www. ...

  4. 前端技术之_CSS详解第五天

    前端技术之_CSS详解第五天 一.行高和字号 1.1 行高 CSS中,所有的行,都有行高.盒模型的padding,绝对不是直接作用在文字上的,而是作用在“行”上的. <!DOCTYPE html ...

  5. The note of Developing Innovative Ideas for New Companies Course

    This course is free on the Coursera Site,But it only has English version Threee pieces of the course ...

  6. 移动 Web 的用户界面设计

    http://www.ibm.com/developerworks/cn/mobile/wa-interface/index.html 简介 在创新者试图探索新的可能性的同时,新兴技术也在经历快速变化 ...

  7. redis资源未释放引发的问题

    一.redis资源未释放的起因: N年前,在修改一个古老程序时,不小心把redis释放的这块给干掉了, if (jedis != null) { if (!isInProcess) { jedis.d ...

  8. java之Spring(IOC)注解装配Bean详解

    在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看Annotation的魅力所在吧. 先来看看之前的bean ...

  9. java类的种类

    1.this this指向当前对象. public class HelloWorld{ String name = "桔子桑"; public void call(){ Syste ...

  10. CSS样式渐变代码,兼容IE8

    background: -webkit-linear-gradient(top,#ffffff,#f5f5f5); background: -moz-linear-gradient(top,#ffff ...