NSQ部署
NSQ部署
安装
Binary Releases
为 linux 和 darwin 预编译二进制文件 (nsqd
, nsqlookupd
, nsqadmin
, 以及所有的例子应用),可用来下载。
当前稳定 Release 版本: v0.3.5
老的稳定 Release 版本
- nsq-0.3.2.darwin-amd64.go1.4.1.tar.gz
- nsq-0.3.2.linux-amd64.go1.4.1.tar.gz
- nsq-0.3.1.darwin-amd64.go1.4.1.tar.gz
- nsq-0.3.1.linux-amd64.go1.4.1.tar.gz
- nsq-0.3.0.darwin-amd64.go1.3.3.tar.gz
- nsq-0.3.0.linux-amd64.go1.3.3.tar.gz
- nsq-0.2.31.darwin-amd64.go1.3.1.tar.gz
- nsq-0.2.31.linux-amd64.go1.3.1.tar.gz
Docker
OSX
1 | brew install nsq |
从源文件编译
Pre-requisites
- golang (version 1.2+ is required)
- gpm (dependency manager)
编译
NSQ 使用 gpm 来管理依赖文件。 编译源文件,gpm 是首选方案。
1 | gpm install |
NSQ 保持了 go get
兼容,但是不推荐,因为之后不能保证仍然能稳定编译。
Testing
1 | ./test.sh |
产品配置
虽然 nsqd
可以单独运行成节点,我们还是假设你希望使用分布式系统的优势。
以下是独立的二进制文件,需要安装并运行:
nsqd
nsqd
是守护进程,接收,缓存,并投递消息给客户端
所有的配置都通过命令行参数来管理。我们希望默认配置能满足多数应用场景,有一部分参数值得注意:
--mem-queue-size
调整每个话题(topic)/通道(channnel)消息队列数。超过上限的消息,将会写到持平,通过 --data-path
定义。
同时,nsqd
将会需要通过 nsqlookupd
配置(参见以下详情),为每个实例指定参数。
拓扑结构,我们推荐运行 nsqd
,和生产消息服务共同写作。
nsqd
可以配置来推送数据到 statsd,通过指定 --statsd-address
。在 nsq.*
命令空间里,nsqd
发送统计数据,参见 nsqd statsd。
nsqlookupd
nsqlookupd
是一个守护进程,为消费者提供运行时发现服务,来查找指定话题(topic)的生产者 nsqd
。
它维护非持久化状态,并且不需要和其他 nsqlookupd
实例来满足产线。
运行数据取决于你的冗余需求。使用很少的支援,并且可以和其他服务协同操作。我们推荐每个数据中心最少运行 3 个集群。
nsqadmin
nsqadmin
是 Web 服务,用来实时的管理你的 NSQ 集群。它通过和 nsqlookupd
实例交流,来确定生产者和 graphite 图表(要求打开 nsqd
端 statsd
)。
我们仅需运行一个,并使它可以公开访问(安全)。
仅有一些 HTML 模板需要部署。默认 nsqadmin
,位于 /usr/local/share/nsqadmin/templates
,可以通过 --template-dir
重写。
要显示 graphite
图表,指定 --graphite-url
。如果你已经使用 statsd
,给所有的 keys 添加前缀,就需要指定 --use-statsd-prefixes
。最后,如果 graphite 不能公开访问,通过指定--proxy-graphite
, 你可以使用 nsqadmin
代理这些请求。
Monitoring
每个守护进程,都拥有 /ping
HTTP 端点,它可以用来创建监控检测。
即使实时调试,它也能运行的非常好:
1 | watch -n 0.5 "curl -s http://127.0.0.1:4151/stats" |
一般通过 nsqadmin
进行调试,分析,管理。
拓扑模式
这个文档描述了一些 NSQ 模式,解决不同的问题。
免责申明: 已经有一些明显的技术建议,但是这个文档通常会忽略,深层的个人选择合适工具的细节,获取软件安装到生产环境,管理服务在哪里运行,服务配置,并管理运行进程 (daemontools
,supervisord
,init.d
等等)。
指标收集
无论你编译的是哪个类型的 Web 服务,多数情况下你会想收集各种指标,来了解你的基础架构,你的用户,你的业务。
对于 Web 服务,多数指标是由 HTTP 请求事件产生的,比如 API。本地的方法可能会结构化这个异步操作,通过 API 请求直接写到你的指标系统。
- 当你的指标系统下降的时候会发生什么?
- 你的 API 请求是否挂起和/或失败?
- 你如何处理增长 API 请求挑战?
解决这些问题的一个方法是设法异步写入到你的指标系统,就是说,将数据放到本地队列中,并通过其他进程写到你的下行系统(消费这个队列)。这个独立操作让系统更加健壮,容错性更强。在 bitly,我们使用 NSQ 完成这个目标。
NSQ 有话题(topic)和通道(channel)两个概念。假设将话题当做消息的唯一流(如同我们的 API 事件流)。假设,将通道当做这个消息流的指定消费者集合的拷贝。话题和通道都是独立队列。这些特性允许 NSQ 支持多播(话题拷贝每个消息到 N 通道)并且分发消息投递(通道平分它的消息到 N 个消费)。
更多细节参考design doc 和 slides from our Golang NYC talk,尤其 slides 19 through 33 描述了话题(topic)和通道(channel)的细节。
完整的 NSQ 比较简单,注意两点:
- 在 API 应用所运行的主机上,运行
nsqd
实例。 - 更新你的 API 应用,写到本地
nsqd
实例队列事件,而不是写到指标系统。能够容易的内审和操作流,我们通常将数据格式化为 line-oriented JSON。写到nsqd
可以简单的执行一个 HTTP post 请求到/put
端点。 - 用 client libraries 在你的语言创建一个消费者。这个"工作者"将会订阅数据流,并会处理事件,写到你的指标系统。它也能运行在主机上,运行你的 API 应用和
nsqd
。
这有一个使用官方Python client library 写的例子:
除了解耦之外,通过使用我们官方的客户端库,当消息处理错误的时候,消费者可以优雅的降级。我们的库有 2 个关键特性:
- 重试 - 当你的消息处理函数返回失败,这个消息将会以
REQ
(re-queue) 命令形式发送给nsqd
。同时,如果在时间窗里消息还没被响应,nsqd
将会自动将消息超时(并重新队列)。这两个特性对于消息投递保障非常关键。 - Backoff指数 - 当消息处理失败,读取库将会延迟附加信息的收据,放大建立在 # 连续的失败指数。当读取者处于 backoff 状态,并且开始处理成功,直到为 0 时,会发生相反序列.
从概念上来说,这两个特性允许系统优雅的自动响应下行失败。
持久化
好,现在你可以应付你的指标系统因为没有数据并且没有 degraded 的 API 服务到其他端点,导致的不可用。你也可以通过从同一个通道(channel)添加更多的工作实例给消费者,放大这个流系统的水平线。
但是,提前想清楚所有的 API 事件的指标,也不太可能。
是否有数据流系统的 log,能满足未来任何操作?日志会很容易导致冗余备份,可以把它作为 downstream 系统发生灾难时的 "plan z"。但是,你会希望消费者来完成消息数据的备份?也许不是,因为这是整个 "separation of concerns" 的事情。
归档 NSQ 话题(topic)非常常见,所以我们建了一个工具,nsq_to_file(使用 NSQ 打包),你可用它来完成。
记住,在 NSQ 中,每个话题(topic)的通道(channel)是独立的,并且接收所有消息的拷贝。你可以利用这个特性,来完成流的归档。实际上,这意味着如果你的指标系统已经有这些问题,并且 metrics
通道得到支持,它就不会影响到独立的 archive
通道,你将会持久化消息到磁盘。
所以,添加一个 nsq_to_file
实例到同一个主机,并且使用命令行如下:
1 | /usr/local/bin/nsq_to_file --nsqd-tcp-address=127.0.0.1:4150 --topic=api_requests --channel=archive |
分布式系统
可能你已经注意到了,目前系统还没有超出单机,这是明显的错误。
不幸的是,要建立一个分布式系统很难。幸运的是,NSQ 可以帮助你。底下的改变演示了 NSQ 如何减轻建立分布式系统的痛苦,以及如何完成高可用性和容错。
假设这个事件流非常重要。你希望能容忍主机错误,并保证消息最终能到归档,所以你增加了另一个主机。
假设你已经在这两个主机间负载平衡,这样你就可以容忍单个主机错误。
现在,我们觉的持久化处理,压缩,传输这些日志会影响性能。如何切割这些责任到这些主机上,让它们拥有更高的 IO 能力?
这个拓扑结构和配置可以容易放大到双位主机,但是你仍然手工管理这些服务配置。尤其对于每个消费者,这个创建过程很难从代码上确定 nsqd
实例在哪里。你真正希望的是配置能进化,并且在 NSQ 集群的状态基础上运行时可访问。这是我们建立 nsqlookupd
的目的。
nsqlookupd
是一个守护进程记录并传播 NSQ 集群运行时候的状态。nsqd
实例维护 TPC 连接的持久化来 nsqlookupd
,并且推送状态变化。具体来说,nsqd
将自己注册为某个话题(topic)的生产者,以及所有它知道的通道(channel)。它允许消费者查询 nsqlookupd
,来确定谁是感兴趣的话题(topic)的生产者。久而久之,他们将会知道新的生产者的存在,并能路由失败。
你需要做的改变仅仅是,nsqlookupd
时指出存在的 nsqd
和消费者实例(每个人都知道 nsqlookupd
实例在哪里,但是消费者不会明确的知道生产者在哪里,反之亦然)。现在拓扑结构如下:
乍一看,这个图变复杂了。这图具有误导性,整个图节点变多了,导致很难直接通讯。因为 nsqlookupd
能作为文件夹服务,你能高效的把生产者和消费者解耦。依赖于已有的流添加一个下行服务非常简单,只需指定你感兴趣的话题(topic)(通过 nsqlookupd
可以找到生产者)。
如何保证查找数据的可用性和一致性?nsqlookupd
并不会占用大量资源,并且能很容易和其他服务器在一起工作。同时 nsqlookupd
实例不需要调整,或者和其他组合。消费者通常只需要一个 nsqlookupd
(它们将会联合它们所知的nsqlookupd
实例响应)。这样就很容易迁移到新的 nsqlookupd
组合中。
Docker
这篇文章详细介绍了如何部署并在 Docker 容器里运行 NSQ 二进制文件。
这有一个最小化的 NSQ 镜像文件,它包含了所有的 NSQ 二级制文件。每个二进制文件可以通过命令指定运行。基本格式如下:
1 | docker run nsqio/nsq /<command> |
注意命令前的 /
,例如:
1 | docker run nsqio/nsq /nsq_to_file |
链接
运行 nsqlookupd
1 | docker pull nsqio/nsq |
运行 nsqd
首先,得到 docker 主机 ip:
1 | ifconfig | grep addr |
接着,运行 nsqd
容器:
1 | docker pull nsqio/nsq |
设置 --lookupd-tcp-address
标志位到主机 IP,以及之前运行的 TCP 端口:
nsqlookupd
, i.e. dockerIP:4160
:
例如,指定主机IP 172.17.42.1
:
1 | docker run --name nsqd -p 4150:4150 -p 4151:4151 \ |
注意:这里使用端口 4160
,端口暴露了什么我们什么开始运行 nsqlookupd
容器 (它也是 nsqlookupd
的端口)。
如果你不想使用默认端口,改变 -p
参数:
1 | docker run --name nsqlookupd -p 5160:4160 -p 5161:4161 nsqio/nsq /nsqlookupd |
它将会使得 nsqlookupd 在主机 IP 上的端口 5160 和 5161 可用。
使用 TLS
如果在 NSQ 容器上使用 TLS,你必须包含证书文件,私钥文件,和根 CA 文件。Docker 镜像里 /etc/ssl/certs/
包含这些内容。挂载一个主机文件夹包含这些文件,并在命令行里指定,比如:
1 | docker run -p 4150:4150 -p 4151:4151 -p 4152:4152 -v /home/docker/certs:/etc/ssl/certs \ |
上面的代码,运行的时候将会从 /home/docker/certs
里加载文件到 Docker 容器里。
持久化 NSQ 数据
使用 /data
目录来存储 nsqd
到主机磁盘上,它能让你加载到 data-only Docker container ,或者加载主机文件夹里:
1 | docker run nsqio/nsq /nsqd \ |