NSQ部署

安装

Binary Releases

为 linux 和 darwin 预编译二进制文件 (nsqd, nsqlookupd, nsqadmin, 以及所有的例子应用),可用来下载。

当前稳定 Release 版本: v0.3.5

老的稳定 Release 版本

Docker

参见 the docs 使用 Docker 部署 NSQ。

OSX

1
$ brew install nsq

从源文件编译

Pre-requisites

  • golang (version 1.2+ is required)
  • gpm (dependency manager)

编译

NSQ 使用 gpm 来管理依赖文件。 编译源文件,gpm 是首选方案。

1
2
$ gpm install
$ go get github.com/bitly/nsq/...

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 图表(要求打开 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 端点,它可以用来创建监控检测。

即使实时调试,它也能运行的非常好:

1
$ watch -n 0.5 "curl -s http://127.0.0.1:4151/stats"

一般通过 nsqadmin 进行调试,分析,管理。

拓扑模式

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

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

指标收集

无论你编译的是哪个类型的 Web 服务,多数情况下你会想收集各种指标,来了解你的基础架构,你的用户,你的业务。

对于 Web 服务,多数指标是由 HTTP 请求事件产生的,比如 API。本地的方法可能会结构化这个异步操作,通过 API 请求直接写到你的指标系统。

naive approach

  • 当你的指标系统下降的时候会发生什么?
  • 你的 API 请求是否挂起和/或失败?
  • 你如何处理增长 API 请求挑战?

解决这些问题的一个方法是设法异步写入到你的指标系统,就是说,将数据放到本地队列中,并通过其他进程写到你的下行系统(消费这个队列)。这个独立操作让系统更加健壮,容错性更强。在 bitly,我们使用 NSQ 完成这个目标。

NSQ 有话题(topic)和通道(channel)两个概念。假设将话题当做消息的唯一流(如同我们的 API 事件流)。假设,将通道当做这个消息流的指定消费者集合的拷贝。话题和通道都是独立队列。这些特性允许 NSQ 支持多播(话题拷贝每个消息到 N 通道)并且分发消息投递(通道平分它的消息到 N 个消费)。

更多细节参考design docslides from our Golang NYC talk,尤其 slides 19 through 33 描述了话题(topic)和通道(channel)的细节。

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 实例到同一个主机,并且使用命令行如下:

1
/usr/local/bin/nsq_to_file --nsqd-tcp-address=127.0.0.1:4150 --topic=api_requests --channel=archive

archiving the stream

分布式系统

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

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

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

adding a second host

假设你已经在这两个主机间负载平衡,这样你就可以容忍单个主机错误。

现在,我们觉的持久化处理,压缩,传输这些日志会影响性能。如何切割这些责任到这些主机上,让它们拥有更高的 IO 能力?

separate archive hosts

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

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

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

adding 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
2
docker pull nsqio/nsq
docker run --name lookupd -p 4160:4160 -p 4161:4161 nsqio/nsq /nsqlookupd

运行 nsqd

首先,得到 docker 主机 ip:

1
ifconfig | grep addr

接着,运行 nsqd 容器:

1
2
3
4
5
docker pull nsqio/nsq
docker run --name nsqd -p 4150:4150 -p 4151:4151 \
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
2
3
4
docker run --name nsqd -p 4150:4150 -p 4151:4151 \
nsqio/nsq /nsqd \
--broadcast-address=172.17.42.1 \
--lookupd-tcp-address=172.17.42.1:4160

注意:这里使用端口 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
2
3
4
5
6
7
docker run -p 4150:4150 -p 4151:4151 -p 4152:4152 -v /home/docker/certs:/etc/ssl/certs \
nsqio/nsq /nsqd \
--tls-root-ca-file=/etc/ssl/certs/certs.crt \
--tls-cert=/etc/ssl/certs/cert.pem \
--tls-key=/etc/ssl/certs/key.pem \
--tls-required=true \
--tls-client-auth-policy=require-verify

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

持久化 NSQ 数据

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

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