nsq源码阅读 nsqlookupd源码一 nsqlookupd.go

来源:互联网 发布:时时彩的的网络女孩 编辑:程序博客网 时间:2024/06/05 14:56
查看nsq的几个模块,发现nsqlookupd模块的代码量最少,所以从它开始。从nsqlookupd/nsqlookupd.go文件开始:

package nsqlookupdimport ("fmt""log""net""os""sync""github.com/nsqio/nsq/internal/http_api""github.com/nsqio/nsq/internal/protocol""github.com/nsqio/nsq/internal/util""github.com/nsqio/nsq/internal/version")type NSQLookupd struct {//读写互斥锁 https://golang.org/pkg/sync/#RWMutex//http://blog.csdn.net/aslackers/article/details/62044726/** * 基本遵循两大原则: * 1、可以随便度,多个goroutine同时读 * 2、写的时候,啥也不能干。不能读也不能写 */sync.RWMutex//在文件nsqlookupd/options.go中定义,记录NSQLookupd的配置信息opts         *OptionstcpListener  net.ListenerhttpListener net.Listener//在文件internal/util/wait_group_wrapper.go中定义,与sync.WaitGroup相关,用于线程同步waitGroup util.WaitGroupWrapper//在文件nsqlookupd/registration_db.go中定义,与数据存储有关DB *RegistrationDB}//根据配置的nsqlookupd options信息,创建一个NSQLookupd实例func New(opts *Options) *NSQLookupd {if opts.Logger == nil {opts.Logger = log.New(os.Stderr, opts.LogPrefix, log.Ldate|log.Ltime|log.Lmicroseconds)}n := &NSQLookupd{opts: opts,DB:   NewRegistrationDB(),}n.logf(version.String("nsqlookupd"))return n}func (l *NSQLookupd) logf(f string, args ...interface{}) {l.opts.Logger.Output(2, fmt.Sprintf(f, args...))}//Main函数,启动nsqlockupd进程时,//首先运行nsqlookupd/options.go里的NewOptions()这个方法,设置默认配置//然后运行上面的New()方法,根据配置信息创建一个NSQLookupd实例//再运行这里的Main()方法,启动nsqlockupd进程//详情见apps/nsqlookupd/nsqlookupd.go里的Start()方法func (l *NSQLookupd) Main() {//Context实例,在文件nsqlookupd/context.go中定义,NSQLookupd类型的指针ctx := &Context{l}//监听TCP,监听地址取options中的默认参数,0.0.0.0:4160tcpListener, err := net.Listen("tcp", l.opts.TCPAddress)if err != nil {l.logf("FATAL: listen (%s) failed - %s", l.opts.TCPAddress, err)os.Exit(1)}//RWMutex写锁l.Lock()//将Listener保存到NSQLookupd对象元素里,供后面的方法调用,如:RealTCPAddr()l.tcpListener = tcpListenerl.Unlock()//tcpServer实例,在文件nsqlookupd/tcp.go中定义,处理TCP接收到的数据tcpServer := &tcpServer{ctx: ctx}//使用sync.WaitGroup,关于sync.WaitGroup介绍,http://blog.csdn.net/aslackers/article/details/62046306//通过下面的Exit()方法,可知,当关闭nsqlookupd进程时,主线程(goroutine)会等待所有TCP监听关闭,才关闭自己l.waitGroup.Wrap(func() {//在文件internal/protocol/tcp_server.go中定义,//接收监听并处理TCP数据//第二个参数tcpServer实现了internal/protocol/tcp_server.go文件中定义的TCPHandler接口//tcpServer接收到TCP数据时,会调用其Handle()方法(nsqlookupd/tcp.go)处理。protocol.TCPServer(tcpListener, tcpServer, l.opts.Logger)})//监听并处理HTTP,逻辑和上面TCP差不多 0.0.0.0:4161httpListener, err := net.Listen("tcp", l.opts.HTTPAddress)if err != nil {l.logf("FATAL: listen (%s) failed - %s", l.opts.HTTPAddress, err)os.Exit(1)}l.Lock()l.httpListener = httpListenerl.Unlock()//httpServer实例,在文件nsqlookupd/http.go中定义,处理HTTP接收到的数据//并定义了一系列HTTP接口(路由)httpServer := newHTTPServer(ctx)l.waitGroup.Wrap(func() {http_api.Serve(httpListener, httpServer, "HTTP", l.opts.Logger)})}//获取监听的TCP地址func (l *NSQLookupd) RealTCPAddr() *net.TCPAddr {l.RLock()defer l.RUnlock()return l.tcpListener.Addr().(*net.TCPAddr)}//获取HTTP地址func (l *NSQLookupd) RealHTTPAddr() *net.TCPAddr {l.RLock()defer l.RUnlock()return l.httpListener.Addr().(*net.TCPAddr)}//退出nsqloopupd进程,关闭两个Listener,等待TCP和HTTP线程都关闭了,才关闭自身func (l *NSQLookupd) Exit() {if l.tcpListener != nil {l.tcpListener.Close()}if l.httpListener != nil {l.httpListener.Close()}l.waitGroup.Wait()}

程序执行步骤:

1、执行nsqlookupd/options.go中的NewOptions()方法,创建Options实例,生成NSQLookupd配置信息

2、执行上面的New()方法,将第1步中创建的Options配置信息作为参数,创建NSQLookupd实例

3、执行NSQLookupd实例的Main()方法,创建nsqloopupd进程,TCP监听0.0.0.0:4160,HTTP监听0.0.0.0:4161

nsqloopupd进程退出时,调用NSQLookupd实例的Exit()方法,关闭TCP和HTTP监听,主线程(goroutine)等待子线程(goroutine)退出,程序退出




0 0