安装

直接在官网下载可执行文件运行,或者使用 Docker 运行,或者从源文件编译

产品配置

虽然 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 图表(要求打开 nsqdstatsd )。 我们仅需运行一个,并使它可以公开访问(安全)。
仅有一些 HTML 模板需要部署。默认 nsqadmin ,位于 /usr/local/share/nsqadmin/templates ,可以通过 --template-dir 重写。
要显示 graphite 图表,指定 --graphite-url 。如果你已经使用 statsd ,给所有的 keys 添加前缀,就需要 指定 --use-statsd-prefixes 。最后,如果 graphite 不能公开访问,通过指定 --proxy-graphite , 你可以使用 nsqadmin 代理这些请求。

Monitoring

每个守护进程,都拥有 /ping HTTP 端点,它可以用来创建监控检测。
即使实时调试,它也能运行的非常好:
$ watch -n 0.5 "curl -shttp://127.0.0.1:4151/stats"
一般通过 nsqadmin 进行调试,分析,管理。

拓扑模式

这个文档描述了一些 NSQ 模式,解决不同的问题。

免责申明: 已经有一些明显的技术建议,但是这个文档通常会忽略,深层的个人选择合适工具的细节,获取软件安装到生产环境,管理服务在哪里运行,服务配置,并管理运行进程 ( daemontoolssupervisordinit.d 等等)。

指标收集

无论你编译的是哪个类型的 Web 服务,多数情况下你会想收集各种指标,来了解你的基础架构,你的用户,你的业务。
对于 Web 服务,多数指标是由 HTTP 请求事件产生的,比如 API。本地的方法可能会结构化这个异步操作,通过 API 请求直接写到你的指标系统。
image.png
图片 4.1 naive approach

  • 当你的指标系统下降的时候会发生什么?
  • 你的 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)的细节。
image.png
图片 4.2 architecture with NSQ

完整的 NSQ 比较简单,注意几点:

  1. 在 API 应用所运行的主机上,运行 nsqd 实例。
  2. 更新你的 API 应用,写到本地 nsqd 实例队列事件,而不是写到指标系统。能够容易的内审和操作流,我们通常将数据格式化为 line-oriented JSON。写到 nsqd 可以简单的执行一个 HTTP post 请求到 /put 端点。
  3. 用 client libraries 在你的语言创建一个消费者。这个”工作者”将会订阅数据流,并会处理事件,写到你的指标系统。它也能运行在主机上,运行你的 API 应用和 nsqd

这有一个使用官方Python client library 写的例子:
除了解耦之外,通过使用我们官方的客户端库,当消息处理错误的时候,消费者可以优雅的降级。我们的库有 2 个关键特性:

  1. 重试 - 当你的消息处理函数返回失败,这个消息将会以 REQ (re-queue) 命令形式发送给 nsqd 。同时,如果在时间窗里消息还没被响应, nsqd 将会自动将消息超时(并重新队列)。这两个特性对于消息投 递保障非常关键。
  2. 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 实例到同一个主机,并且使用命令行如下:
/usr/local/bin/nsq_to_file --nsqd-tcp-address=127.0.0.1:4150 --topic=api_requests --channel=archive
image.png
图片 4.3 archiving the stream

分布式系统

可能你已经注意到了,目前系统还没有超出单机,这是明显的错误。

不幸的是,要建立一个分布式系统很难。幸运的是,NSQ 可以帮助你。底下的改变演示了 NSQ 如何减轻建立分布式系统的痛苦,以及如何完成高可用性和容错。

假设这个事件流非常重要。你希望能容忍主机错误,并保证消息最终能到归档,所以你增加了另一个主机。
image.png
图片 4.4 adding a second host

假设你已经在这两个主机间负载平衡,这样你就可以容忍单个主机错误。
现在,我们觉的持久化处理,压缩,传输这些日志会影响性能。如何切割这些责任到这些主机上,让它们拥有更高的 IO 能力?
image.png
图片 4.5 separate archive hosts

这个拓扑结构和配置可以容易放大到双位主机,但是你仍然手工管理这些服务配置。尤其对于每个消费者,这个创建过程很难从代码上确定 nsqd 实例在哪里。你真正希望的是配置能进化,并且在 NSQ 集群的状态基础上运 行时可访问。这是我们建立 nsqlookupd 的目的。

nsqlookupd 是一个守护进程记录并传播 NSQ 集群运行时候的状态。 nsqd 实例维护 TPC 连接的持久化来 nsqlookupd ,并且推送状态变化。具体来说, nsqd 将自己注册为某个话题(topic)的生产者,以及所有它知道的通道(channel)。它允许消费者查询 ,来确定谁是感兴趣的话题(topic)的生产者。久而久之,他们将会知道新的生产者的存在,并能路由失败。

你需要做的改变仅仅是指出存在的 nsqd 和消费者实例(每个人都知道 nsqlookupd 实例在哪里,但是消费者不会明确的知道生产者在哪里,反之亦然)。现在拓扑结构如下:
image.png
图片 4.6 adding nsqlookupd

乍一看,这个图变复杂了。这图具有误导性,整个图节点变多了,导致很难直接通讯。因为 nsqlookupd 能作为 文件夹服务,你能高效的把生产者和消费者解耦。依赖于已有的流添加一个下行服务非常简单,只需指定你感兴 趣的话题(topic)(通过 nsqlookupd 可以找到生产者)。

如何保证查找数据的可用性和一致性? nsqlookupd 并不会占用大量资源,并且能很容易和其他服务器在一起工 作。同时 nsqlookupd 实例不需要调整,或者和其他组合。消费者通常只需要一个 nsqlookupd (它们将会联 合它们所知的 nsqlookupd 实例响应)。这样就很容易迁移到新的 nsqlookupd 组合中。

Docker

这篇文章详细介绍了如何部署并在 Docker 容器里运行 NSQ 二进制文件。

这有一个最小化的 NSQ 镜像文件,它包含了所有的 NSQ 二级制文件。每个二进制文件可以通过命令指定运 行。基本格式如下:
docker run nsqio/nsq /<command>
注意命令前的 / ,例如:
docker run nsqio/nsq /nsq_to_file

运行 nsqlookupd

  1. docker pull nsqio/nsq
  2. docker run --name lookupd -p 4160:4160 -p 4161:4161 nsqio/nsq /nsqlookupd

运行 nsqd

首先,得到 docker 主机 ip:
ifconfig | grep addr
接着,运行 nsqd 容器:

  1. docker pull nsqio/nsq
  2. docker run --name nsqd -p 4150:4150 -p 4151:4151 \
  3. nsqio/nsq /nsqd \ --broadcast-address=<host> \ --lookupd-tcp-address=<host>:<port>

设置 --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 \
  2. nsqio/nsq /nsqd \
  3. --broadcast-address=172.17.42.1 \
  4. --lookupd-tcp-address=172.17.42.1:4160

注意:这里使用端口 4160 ,端口暴露了什么我们什么开始运行 nsqlookupd 容器 (它也是 nsqlookupd 的端 口)。
如果你不想使用默认端口,改变 -p 参数:
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 \
  2. nsqio/nsq /nsqd \
  3. --tls-root-ca-file=/etc/ssl/certs/certs.crt \
  4. --tls-cert=/etc/ssl/certs/cert.pem \
  5. --tls-key=/etc/ssl/certs/key.pem \
  6. --tls-required=true \
  7. --tls-client-auth-policy=require-verify

上面的代码,运行的时候将会从 /home/docker/certs 里加载文件到 Docker 容器里。

持久化 NSQ 数据

使用 /data 目录来存储 nsqd 到主机磁盘上,它能让你加载到 data-only Docker container ,或者加载主机文件夹里:

  1. docker run nsqio/nsq /nsqd \
  2. --data-path=/data