NSQ部署与测试
项目背景
logserver服务需要收集汇总其他服务的日志记录或者其他信息,需要一个工具来进行信息传递,在对比过几款同类型方案之后,选择了NSQ。
NSQ简介
Nsq是一个消息队列,它采用去中心化的拓扑结构的分布式实时消息平台。NSQ框架具有高可用性、无单点故障、和低延迟、可靠性的消息传递等特性。它基于Go语言开发,能够为高吞吐量的网络服务器带来性能的优化,稳定性和鲁棒性。
NSQ是一个简单的队列,基本核心就是简单性,这意味着它很容易进行故障推理和很容易发现bug。消费者可以自行处理故障事件而不会影响系统剩下的其余部分。 NSQ具有以下几个主要特点:
- 具有分布式且无单点故障(SPOF)的拓扑结构
- 支持水平扩展,在无中断情况下能够无缝地添加集群节点
- 低延迟的消息推送,参见官方性能文档
- 具有组合式的负载均衡和多播形式的消息路由
- 既擅长处理面向流(高吞吐量)的工作负载,也擅长处理面向Job的(低吞吐量)工作负载
- 消息数据既可以存储于内存中,也可以存储在磁盘中
- 实现了生产者、消费者自动发现和消费者自动连接生产者,参见nsqlookupd
- 支持安全传输层协议(TLS),从而确保了消息传递的安全性
- 具有与数据格式无关的消息结构,支持JSON、Protocol Buffers、MsgPacek等消息格式
- 非常易于部署(几乎没有依赖)和配置(所有参数都可以通过命令行进行配置)
- 使用了简单的TCP协议且具有多种语言的客户端功能库
- 具有用于信息统计、管理员操作和实现生产者等的HTTP接口
- 为实时检测集成了统计数据收集器StatsD
- 具有强大的集群管理界面,参见nsqadmin
部署
log-srv build
作为nsq的注册发现中心,
1.安装编译文件
nsq-build/bin目录下的文件放入/usr/local/bin下
部署nsqlookupd
用于nsqd服务注册与发现
1.配置nsqlookupd.cfg文件
2.配置supervisord.conf
3.初始化supervisor
supervisord -c supervisord.conf
4.启动
supervisorctl start nsqlookupd
- tcp-address : 用于让其他nsqd注册
- http_address : 用于通过接口发现其他nsqd
部署nsqadmin UI监控
用来汇集集群的实时统计,并执行不同的管理任务
1.配置nsqadmin.cfg文件
2.配置supervisord.conf
3.初始化supervisor
supervisord -c supervisord.conf
4.启动
supervisorctl start nsqadmin
主要修改参数
- lookupd-http-address: nsqlookupd地址
-
http-address: 服务地址和端口,对外访问需开启外网端口
- 提供一个对topic和channel统一管理的操作界面以及各种实时监控数据的展示,界面设计的很简洁,操作也很简单
- 展示所有message的数量
- 能够在后台创建和删除topic和channel
- nsqadmin的所有功能都必须依赖于nsqlookupd,nsqadmin只是向nsqlookupd传递用户操作并展示来自nsqlookupd的数据
部署nsq_to_file
自动创建一个channl并把消息写入文件
1.启动
//注意修改启动命令的4个参数
nohup \
nsq_to_file \
--topic=bossLog \
--output-dir=/home/admin/log-srv/nsq_to_file_data \
--lookupd-http-address=127.0.0.1:4161 \
--datetime-format=%Y-%m-%d_%H \
>logs/nsq_to_file.log 2>&1&
- topic : topic
- output-dir : 输出消息到磁盘的目录,文件名称bossLog.ubuntu.2019-06-26_13.log,命名格式{topic}.{hostname}.{日期_小时}.log
- lookupd-http-address : 注意是http端口
- datetime-format : 日志文件命名格式,%Y-%m-%d_%H 为每小时一个日志文件
测试概要
分别从基本功能、性能、配置参数、稳定性、可靠性方面进行测试
测试组件
- nsqd:一个负责接收、排队、转发消息到客户端的守护进程
- nsqlookupd:管理拓扑信息并提供最终一致性的发现服务的守护进程
- receive: go接收消息的接口,一个接收端链接为一个worker
- send: go发送消息的接口,测试时发送消息方式为异步发送
测试用例
参考文件NSQ测试用例.xlsx
结果分析
基本功能
发送与接收消息的主要流程:
与server部署在一起的nsqd负责接收本地的push消息,存储在本地内存或者磁盘中;等待接收方接收消息,如果接收方worker知道发送方的端口和topic,并设置一个channel名称,那么则会建立连接开始传输消息。
所以基本功能测试围绕几个关键点:nsqd、topic、channel、worker,控制变量方式进行测试。
主要结论如下:
- 多nsqd:多个nsqd之间互不影响彼此独立
- 多topic:topic名字全局唯一,可以多个nsqd使用同一个topic
- 多channel:channel与topic是多对一关系,多个channel等于对消息的复制并多路发送。注意清理无用的channel。
- 多worker:会造成并发处理的局部乱序,是一种提高吞吐量、负载均衡的方式
不同情况下基本功能
- nsqd与topic
正常使用方式是一个nsqd与topic是一对多关系,此时相当于一个nsqd负责处理两种消息,彼此独立
但是也可以nsqd与topic是多对多关系,实际环境中不推荐这么做,徒增复杂性,除非是server集群,考虑用多个nsqd负载均衡
如果两个nsqd有相同topic,等于这两个nsqd处理同一个类型的消息
- topic与channel
channel与topic是多对一关系,一个channel可以理解为一个消息一份复制,一个去向;比如一份由接收方写入本地文件,一份接收后经过处理再存入数据库
性能
自测
发送方:使用不带缓存的异步发送方式 接收方:使用链接接收消息
机器:101.132.149.11 和 139.224.119.126
一台机器发送消息,另一台接收消息,消息1w在内存中,其他大部分都在磁盘中
- 1nsqd多worker
发送qps:5w 接收qps:2.5w 写文件qps:1.5w 发送cpu:180 接收cpu:150 接收写文件cpu: 30
- 2nsqd多worker
发送qps:6w+6w 发送方cpu:nsqd100+100 接收qps:5w 接收cpu:150
导致自测慢的原因:
- 多nsqd可以轻松提升qps,说明还没有达到nsq的极限,考虑用buffer方式可以进一步提升
- 消息1w在内存中,其他大部分都在磁盘中
- 接收消息慢,由于是远程接收,单个worker最慢速度qps1.5k,多个(15个)worker可达到与发送差不多的速度6w
- 官方接收测试使用读取buffer方式,消息都在buffer中混在一起,只统计计数,刨除了处理消息的时间
- 自测用的是nsq-go接口,建立TCP连接方式,可以对单条消息进行操作
压测
机器:101.132.149.11 和 139.224.119.126
内存消耗取决于允许存入内存的大小,可以设置为所有消息都存盘,即降低了内存压力,提高了cpu压力;内存充裕可以将更多消息存入内存,但是要注意清理无用的channel防止内存占用。
以下操作为内存消息仅1w条,基本不占用内存,等于所有消息都从磁盘写入并消费
一台机器发送消息,另一台接收消息 发送qps:5w 接收qps:2.5w 写文件qps:1.5w 发送cpu:180 接收cpu:150 接收写文件cpu: 30
测试时间将近4小时,共2.5亿消息,算上两个channel共5亿 接收方日志文件18G 发送方产生临时文件47w个
注:接收方worker数量较少,发送方速度高于接收方,消息有积压。积压的消息会存在本地磁盘,但是由于测试机器磁盘空间当时只剩下1G左右,磁盘肯定放不下这么多消息,但是nsq没有停止运行,在磁盘空间没有释放的情况下依然继续收发消息,并且大体数目正确,当然其中肯定有很多消息存储在本地磁盘失败。处理机制大概是利用0k大小的临时文件.dat.tmp,1分钟重试等待内存或磁盘有空间再次传输。当结束发送程序时一段时间,还可以看到不断有消息存入内存和磁盘(当然接收方一直在接收)。具体处理逻辑后续会从源码确认。
消息已经发出(存储在本地),但是没有接收方的情况下,3天后依然可以继续接收消息。
稳定性与可靠性
主要围绕几个组件:nsqd,nsqlookup,worker进行测试
nsqlookup
为服务注册发现进程,在worker接收消息时,可以选择两种方式建立连接,一种是直接用nsqd的端口,另一种是通过nsqlookup端口查询nsqd端口再链接,此时需要nsqlookup存活。
但是在测试中发现,如果nsqlookup挂了,只要接收方知道nsqd端口,就一样可以建立连接,即使是使用新的topic、channel也可以。
前提是nsqd已经在nsqlookup上注册过了,因为启动nsqd时必须要配置nsqlookup
nsqlookup的另一个作用就是可以通过管理UI来监控各个组件,如果nsqlookup挂了则监控无法使用。
考虑到无用channel的危险性,必须要使用监控端
nsqd
这是一个直接与server交互的程序,利用程序手动错误处理重发,加上supervisor的自动重启(测试为2s重启时间),可以达到不丢失消息的目的。
消息会保存在本地内存或磁盘中,但是如果内存和磁盘同时存在消息,则会同时从内存和磁盘中发送消息,会造成断崖式的乱序,比如内存中序号1-1w的消息,磁盘1w-2w,接收方会接到1开始和1w开始的消息。生产环境中可以配置一个较大的内存消息数,同时匹配好收发速度;或者直接全部存储在磁盘中。
磁盘中处理速度5w左右,消息大小50b。消息首先储存如nsqd本地磁盘,当有人接收的时候,消息在拷贝到channel中,由接收方接收。瓶颈在nsqd->channel,都由磁盘来操作瓶颈5w左右。
接收方worker
接收消息的前提是已经与nsqd建立了TCP链接,如果此时强行中断worker,会导致已经发送的消息在in-flight状态,通过配置nsqd控制超时时间,超时过后消息重新加入nsqd队列。
worker的无序性体现在并发处理的速度不同导致的局部乱序。
顺序问题
用nsq-go接口发送消息,
目前主要问题
nsqd->channel的瓶颈
消息在channel中timeout会重传,破坏顺序
nsq-go发送问题
源码
https://github.com/Allen-ZhangM/nsq-client