go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go
从本节开始,将逐步阅读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的更多相关文章
- DRF(1) - REST、DRF(View源码解读、APIView源码解读)
一.REST 1.什么是编程? 数据结构和算法的结合. 2.什么是REST? 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下: /books/ /get_all_books/ 访问所 ...
- REST、DRF(View源码解读、APIView源码解读)
一 . REST 前言 1 . 编程 : 数据结构和算法的结合 .小程序如简单的计算器,我们输入初始数据,经过计算,得到最终的数据,这个过程中,初始数据和结果数据都是数据,而计算 ...
- Restful 1 -- REST、DRF(View源码解读、APIView源码解读)及框架实现
一.REST 1.什么是编程? 数据结构和算法的结合 2.什么是REST? - url用来唯一定位资源,http请求方式来区分用户行为 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下 ...
- 5.2 spring5源码--spring AOP源码分析三---切面源码分析
一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs ...
- mybatis源码解读(三)——数据源的配置
在mybatis-configuration.xml 文件中,我们进行了如下的配置: <!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境常用: ...
- jQuery源码解读三选择器
直接上jQuery源码截取代码 // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ i ...
- Python Web Flask源码解读(三)——模板渲染过程
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- ConcurrentHashMap源码解读三
今天首先讲解helpTransfer方法 final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) ...
- spring源码解读之 JdbcTemplate源码
原文:https://blog.csdn.net/songjinbin/article/details/19857567 在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数 ...
随机推荐
- [ Java学习基础 ] Java的对象容器 -- 集合
当你有很多书时,你会考虑买一个书柜,将你的书分门别类摆放进入.使用了书柜不仅仅使房间变得整洁,也便于以后使用书时方便查找.在计算机中管理对象亦是如此,当获得多个对象后,也需要一个容器将它们管理起来,这 ...
- Windows平台安装及配置Hadoop(不借助cygwin)
由于项目需要,我在VMware上装了几个虚拟机Windows server 2012 R2,并要搭建Hadoop集群.刚刚入门hadoop,一头雾水,然后开始搜各种教程,首先是选用cygwin进行安装 ...
- C 标准库基础 IO 操作总结
其实输入与输出对于不管什么系统的设计都是异常重要的,比如设计 C 接口函数,首先要设计好输入参数.输出参数和返回值,接下来才能开始设计具体的实现过程.C 语言标准库提供的接口功能很有限,不像 Pyth ...
- search a 2D matrix(在二维数组中搜索一个元素)
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...
- 查找链表中是否有环linked-list-cycle
Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...
- 2MySQL Server 系统架构
2.2MySQL Server 系统架构 总的来说,MySQL 可以看成是二层架构,第一层我们通常叫做SQL Layer,在MySQL 数据库系统处理底层数据之前的所有工作都是在这一层完成的,包括权限 ...
- JAVA学习总结-面向对象
前言:java面向对象中的知识可以说是整个java基础最核心的部分,不知不觉已经学完快2个月了,是时候复习一波了,刚开始学习的时候被绕的很懵逼,这次总结完毕之后有了很多新的感悟,这就是所谓的每有会意, ...
- Vector 特性
1.Vector是一个连续内存占用的容器 2.每次Insert,都会将插入的对象先析构,然后复制一个副本添加到容器内 3.容器的大小先是1,然后是2,然后是4,也可以使用reserve来重新制定队列的 ...
- 微信小程序中自定义函数的学习使用
新手,最近在给学校搞个党费计算器.需要自己定义函数来实现某个功能. 1.无参函数: 函数都是写在js文件里面的. Page({ data:{ income1:'0', }, cal:function( ...
- linux上nginx新建站点
遇到一个要将后台部分模块剥离出来,重新放到一个新的后台上的问题: 这样一来,就要在服务器上新建站点,but,服务器是linux系统的,不是很熟,经过多方努力,搞定了 在这记录一下,用到的linux命令 ...