nsqlookupd的角色类似于注册中心,管理着nsqd -> Topic -> Channel的拓扑信息,提供Client查询Topic和Channel的信息。nsqlookupd主要提供两种接口:TCP接口,用于nsqd广播信息;另外就是HTTP接口,让Client可以服务发现或者admin可以进行管理操作。
启动方式和nsqd类似,
func (p *program) Start() error {
// 配置读取
...
p.nsqlookupd = nsqlookupd
go func() {
err := p.nsqlookupd.Main()
if err != nil {
p.Stop()
os.Exit(1)
}
}()
return nil
}
启动NSQLookupd实例,
func (l *NSQLookupd) Main() error {
...
tcpServer := &tcpServer{ctx: ctx}
l.waitGroup.Wrap(func() {
exitFunc(protocol.TCPServer(l.tcpListener, tcpServer, l.logf))
})
httpServer := newHTTPServer(ctx)
l.waitGroup.Wrap(func() {
exitFunc(http_api.Serve(l.httpListener, httpServer, "HTTP", l.logf))
})
err := <-exitCh
return err
}
启动一个TCP Server和一个HTTP Server,NSQDLoop协议实现代码如下,
func (p *LookupProtocolV1) Exec(client *ClientV1, reader *bufio.Reader, params []string) ([]byte, error) {
switch params[0] {
case "PING":
return p.PING(client, params)
case "IDENTIFY":
return p.IDENTIFY(client, reader, params[1:])
case "REGISTER":
return p.REGISTER(client, reader, params[1:])
case "UNREGISTER":
return p.UNREGISTER(client, reader, params[1:])
}
return nil, protocol.NewFatalClientErr(nil, "E_INVALID", fmt.Sprintf("invalid command %s", params[0]))
}
这部分的实现没有太多很绕的逻辑,读者如果自己感兴趣,可以自己尝试去阅读下相关代码。如果存在问题,欢迎留言交流。