写在前面:
NSQ版本 : v1.2.0
在源码层面,完整阅读了一个GO-Lang实际的项目-NSQ,目标是让自己从学习、熟悉Go语法,进阶到深入理解GO,理解实现工程中GO的使用和组织。现把这大半个月阅读的文章和学习笔记做一些整理。
一. NSQ官网(nsq.io)
这个没啥好说的,官方文档是最权威的.逐页看就是,后来发现一个中文的:
其他介绍参考文档
https://www.jianshu.com/p/c47e0350bb2e
https://www.cnblogs.com/li-peng/category/1537661.html
https://segmentfault.com/a/1190000012362544
http://blog.rayxxzhang.com/index.html
http://luodw.cc/2017/04/14/nsqd/
https://www.cnblogs.com/li-peng/p/11435083.html
二. NSQ依赖
NSQ已经改成go modules来管理包.
module github.com/nsqio/nsq
require (
github.com/BurntSushi/toml v0.3.1
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932
github.com/bitly/timer_metrics v0.0.0-20170606164300-b1c65ca7ae62
github.com/blang/semver v3.5.1+incompatible
github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
github.com/judwhite/go-svc v1.0.0
github.com/julienschmidt/httprouter v1.2.0
github.com/mreiferson/go-options v0.0.0-20190302015348-0c63f026bcd6
github.com/nsqio/go-diskqueue v0.0.0-20180306152900-74cfbc9de839
github.com/nsqio/go-nsq v1.0.7
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2 // indirect
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6 // indirect
)
可以看出基本大部分都是自己的依赖(其中nsqio和bilty部分),都是一些小的工具包.
唯一需要注意的是httprouter,nsq用它来装饰处理http请求.
package | 简要说明 |
---|---|
go-difflib | python迁移的对比包 |
go-diskqueue | 官方提供的文件记录包-用于在channel满的时候,作为backendQueue保存到文件中 |
go-hostpool | 把主机信息池化 |
go-nsq | NSQ官方提供的客户端实现 |
go-options | 读取命令行配置工具 |
go-spew | 格式化打印 |
go-svc | 用于包装为系统服务(会识别环境) |
http-router | 轻量级http请求路由 |
perks | 产生图标的工具包 |
semver | 解析版本字符串的工具(如1.0.3-beta) |
snappy | 压缩算法包 |
x/sys | GO官方扩展包 |
timer_metrics | 计时测量 |
toml | nsq使用toml文件格式作为配置持久化 |
三. Go-nsq (V1.0.7)
- 首先要理解go-nsq作为官方提供的客户端,怎么使用,先堆一堆参考文档:
https://nicksors.cc/2018/08/15/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E4%B9%8B%E3%80%8A02-NSQ%E5%AE%9E%E8%B7%B5%E7%AF%87%E3%80%8B.html
https://cloud.tencent.com/developer/article/1070860
https://segmentfault.com/a/1190000009194607
https://lihaoquan.me/2016/6/20/using-nsq.html
https://juejin.im/post/5d3e3a44f265da1bae39439a
https://www.cnblogs.com/li-peng/p/11435083.html
- 其次是看源码,代码不多.我理解核心还是搞懂Conn,Delegate,Consumer,Producer之间的关系.默认的Consumer和Producer都实现了ConnDelegate接口,用来把连接conn上的事件传导给具体的
Consumer和Producer去完成.
Delegate使得它们之间的关系解耦,避免了Conn和Consumer双向引用.
- 测试代码:
- Config_test.go | Go语言可以很方便用数组形式构造测试案例
- Producer_test.go | 测试生产者
- Consumer_test.go | 测试消费者
四. nsq-internal
nsq-internal是几个实现共用的一些工具包
package | 简要说明 |
---|---|
app | 包含FloatArray和StringArray,用在解析命令参数 |
auth | Authorization结构,用在权限控制(本次阅读忽略) |
clusterinfo | 用来外呼http请求,获取信息 |
dirlock | 锁定目录(windows无效) |
httpapi | 带截止时间的http请求封装(主要和go-nsq中的不同) |
lg | 日志工具 |
pqueue | 以Item为元素的优先级队列,其中Item.value是个空接口,用在diskBackend中.奇怪的是InflightQueue是用Message实现的一套. |
protocol | 用来表明自己能处理的tcp协议报文.(nsqd和nsqlookupd都有自己的实现) |
quanltile | 统计用的火焰图数据 |
statsd | 登记统计信息的服务器调用简单包装 |
stringy | nsq用的几个字符串函数工具包 |
test | nsq对测试的工具包,其中FakeNetConn可以伪装为一个连接 |
util | WaitGroupWrapper把普通的函数(无参数,无返回值)同步调用包装成异步调用 |
version | 表明版本号(目前1.2.1) |
writers | BoundaryBufferedWriter和SpreadWriter两种实现 |
五. nsq-apps
由nsq提供的可执行程序的源码,除了nsqd、nsqlookup、nsqadmin这几个服务端封装外,基本都是用go-nsq(客户端)实现特定功能的命令行工具。
package | 简要说明 |
---|---|
nsq_stat | 使用http_api实现对特定的topic,channel的监控(打印控制台) |
nsq_tail | 订阅消费特定Topic消息,实现对特定的channel监控(打印控制台) |
nsq_to_file | 订阅消费特Channel消息,记录到文件 |
nsq_to_http | 把Nsq消息通过http发出 |
nsq_to_nsq | 桥接Nsq消息-转发 |
to_nsq | 读取文件中message,发送到nsqd中 |
六. nsq-nsqd
NSQD是整个消息中间件的核心,所幸很多人都分析了,这里不需要再累述,看代码的同时,结合牛人的文章即可:
NSQ源码分析之概述(不错)
http://luodw.cc/2016/12/08/nsq01/
http://luodw.cc/2016/12/13/nsqlookupd/
http://luodw.cc/2017/04/14/nsqd/
nsq源码分析
https://www.cnblogs.com/hlxs/p/11445103.html
nsq源码学习
https://segmentfault.com/a/1190000012362544
NSQ源码剖析之nsqd(不错)
http://shanks.leanote.com/post/NSQ%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90%E4%B9%8BNSQD
nsq源码阅读(nsqd)(不错)
http://sksun.com.cn/2018/06/13/nsq%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-nsqd/
http://sksun.com.cn/2018/06/12/nsq%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-nsqlookupd/
-
结构:
NSQ结构是多层次的,NSQD有个topicMap,记录所有的Topic;topic有个channelMap,记录所有的Channel,Channel有个clients,记录所有的消费者.这些结构都有一个ctx指针,指向NSQD自身. -
启动:
先启动TcpServer,HttpServer,处理报文
再启动queueScanLoop(动态调整queueScanWorker的数目,处理in-flight和deffered queue的消息),lookupLoop(和nsqlookupd服务器连接),statsdLoop(和stasd服务器连接) -
消息处理:
略,上面文章讲太多了.. -
代码阅读中一些疑问:
-
Topic创建时机?
在Publish时,如果不存在,会自动创建. -
Channel创建时机?
在Sub是,如果不存在,会自动创建. -
deferredMessages与inFlightMessages
Channel内部维护2个队列,infight表示正在和client交互(等到client返回FIN才删除,保证消息至少被接收一次),deferred表示可以提前给nsqd发送message,等到时间到才合法. -
BackendQueue与ephemeral
如果声明为ephemera,则如果消息超过infight队列长度,就会被丢弃.而BackendQueue可以用go-diskqueue包提供的方法保存到文件中. -
消息有序性?
NSQ不保证,可能无序(requeue机制,多节点机制) -
丢消息?
如果异常退出,infightMsg可能会丢 -
RDY意义:
RDY是订阅方告知NSQD服务器自身处理能力的方法,这样避免服务器快速给客户端发消息,客户端处理不过来的情况(Rx中背压)
七. nsq-nsqlookupd
与nsqd类似,nsqlookupd通过TCP和Http两种方式向外提供服务.
- RegistrationDB
登记nsq信息的内存DB,使用registrationMap,ProducerMap两层MAP,并且实现了add,remove,find,这些操作,便于上层进行调用. - lookup_protocol_v1
提供tcp服务,只有Ping,Identify,Register,Unregister四个方法,也就是说,只有nsqd才会使用tcp和nsqlookupd连接通讯.(Category有topic和channel,client三种) - http
提供http服务,消费者使用nsqlookupd提供的方法感知,而producer是需要直连nsqd的.
提供了"/topic/create","/topic/delete"这种,不是给nsqd用的,是给go-nsq客户端或者nqadmin手工删除topic用的.
八. nsq-nsqadmin
admin相对比较简单(go部分),通过notify构造AdminAction向外主动POST,或者通过http向外提供服务.而且,它本身并不存储任何数据,需要时,都是使用httpServer中的client向nslookupd或者nsqd查询(类似于gateway).这里用了internal/clusterinfo,先调用nslookupd,不行就直接请求nsqd(需要遍历所有的nsqd,为了效率,还是搭建nslookupd吧).
前端页面部分用了backdone+jquery+gulp.未看...
九. 其他
- bench目录: 用python写的批量测试用例
- 有赞nsq (https://github.com/youzan/nsq)
发现有赞Fork了一个分支,并做了改进,有机会再细看一下...
网友评论