NSQ之部署

2,733 阅读11分钟

原文地址:nsq.io/deployment/…

部署

安装

二进制发布包

可以下载适用于linux,darwin,freebsd和Windows的预编译二进制文件:

当前稳定版本: v1.2.0

较旧的稳定版本

Docker

请参阅有关使用Docker部署NSQ的文档

OSX

 $ brew install nsq

源码构建

先决条件

  • golang(需要版本1.9+

编译

NSQ使用go模块生成可靠的版本。

$ git clone https://github.com/nsqio/nsq
$ cd nsq
$ make

测试

$ ./test.sh

生产配置

尽管nsqd可以作为独立节点运行,但这些说明假定您想利用其设计的分布式特性。

需要安装和运行三个独立的二进制文件:

nsqd

nsqd 是接收,缓冲和传递消息到客户端的守护程序。

所有配置均通过命令行参数进行管理。我们力求使得默认配置适合大多数使用情况,但是一些特定选项值得注意:

--mem-queue-size调整每个主题/通道在内存中队列的消息数。消息由定义的--data-path被透明地写入磁盘。

另外,nsqd需要配置nsqlookupd地址(有关详细信息,请参见下文)。为每个实例指定 --lookupd-tcp-address选项。

就拓扑而言,我们建议nsqd与生产消息的服务并置运行。

nsqd配置可以通过指定--statsd-address将数据推送到statsdnsqdnsq.*命名空间下发送统计信息。请参见nsqd statsd

nsqlookupd

nsqlookupd是一个守护程序,它为消费者提供运行时发现服务,为其查找特定主题的nsqd 生产者。

它不维护任何持久状态,不需要与任何其他nsqlookupd 实例协作即可满足查询。

您可以任意地根据需求来运行。它们使用的资源很少,并且可以与其他服务并置运行。我们的建议是每个数据中心的集群至少运行3个。

nsqadmin

nsqadmin是用于实时检测和管理NSQ集群的Web服务。它与nsqlookupd实例进行对话以定位生产者,并利用graphite绘制图表(需要在nsqd端启用statsd)。

您只需要运行其中的1个,即可公开(安全地)访问它。

为了从graphite显示图表,请指定--graphite-url。如果您使用的statsd版本,将愚蠢的前缀添加到了所有键中,那么也要指定--use-statsd-prefixes。最后,如果graphite不能公开访问,您可以指定 --proxy-graphite来让nsqadmin代理那些请求。

Monitoring

每个守护程序都有一个/pingHTTP端点,用于创建Nagios检查。

对于实时调试,这也出奇地好用:

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

通常,大多数调试、分析和管理都是通过nsqadmin来进行。

拓扑模式

本文档描述了解决各种常见问题的一些NSQ模式。

免责声明:有一些明显的技术建议,但这篇文档通常会忽略深层的个人细节:选择合适的工具、在生产机器上安装软件、管理在哪里运行服务、服务配置、以及管理正在运行的进程(daemontoolssupervisordinit.d等)。

指标集合(Metrics Collection)

无论您要构建哪种类型的Web服务,在大多数情况下,您都希望收集某种形式的指标以了解您的基础架构,用户或业务。

对于Web服务,大多数情况下,这些指标是由HTTP请求(例如API)发生的事件产生的。天真的方法是同步地构建此结构,直接在API请求处理程序中写入到指标系统。

  • 当指标系统出现故障时会发生什么?
  • 您的API请求是否挂起和/或失败?
  • 您将如何应对不断增加的API请求数量或指标收集范围扩展的挑战?

解决所有这些问题的一种方法是,以某种方式异步执行写入指标系统的工作—也就是说,将数据以某个顺序放在本地队列中,然后通过其他进程(消费该队列)写入到下游系统。关注点分离使系统更加健壮和具有容错性。我们使用NSQ来实现这一目标。

简要的题外话:NSQ具有主题通道的概念。基本上,可以将主题视为唯一的消息流(例如上面的API事件流)。将通道视为给定的一组消费者的消息流副本。主题和通道也都是独立的队列。这些属性使NSQ既可以支持多播(multicast,将每个主题消息复制到N个通道)又可以支持分布式(一个通道将其消息平均分配给N个消费者)的消息传递。

要更彻底地处理这些概念,请阅读设计文档Golang NYC演讲中的幻灯片,尤其是幻灯片19至33,详细描述了主题和通道。

集成NSQ很简单,让我们以简单的情况为例:

  1. 在运行API应用程序的同一主机上运行nsqd实例。
  2. 更新您的API应用程序以写入本地nsqd实例以将事件排队,而不是直接写入指标系统。为了能够轻松地进行内部检查和操作数据流,我们通常使用面向行的JSON格式化此类数据。写入nsqd就像对/put端点执行HTTP POST请求一样简单。
  3. 使用我们的客户端库之一以您喜欢的语言创建一个消费者 。"worker"将订阅数据流并处理事件,然后写入指标系统。还可以在同时运行API应用程序和nsqd的主机上进行本地运行。

这是使用我们的官方Python客户端库编写的示例工作程序

import nsq
import json

def metrics_write(message):
    json_data = json.loads(message)
    
    # iterate over the metrics you want to record and write 
    # into your downstream metrics system
    
    if any_metrics_failed:
        # this will indicate to pynsq that it should re-queue 
        # the message for you
        return False
    
    return True

tasks = {"metrics_write": metrics_write}
r = nsq.Reader(tasks, nsqd_tcp_addresses=['127.0.0.1:4150'], 
        topic="api_requests", channel="metrics")
nsq.run()

除了解耦之外,通过使用我们官方客户端库之一,消费者可以在消息处理失败时正常降级。我们的库具有两个关键特征可帮助您解决此问题:

  1. 重试—当您的消息处理程序指示失败时,该消息将以REQ(重新排队)命令的形式发送到nsqd。此外,如果未在可配置的时间窗口中得到响应,则nsqd消息将自动超时(并重新排队)。这两个属性对于提供(消息)传递保证至关重要。
  2. 指数退避(Exponential Backoff )—当消息处理失败时,读取器库将根据连续失败的次数使接收其他消息的延迟时间成指数增长。当读取器处于退避状态并开始成功处理直到0时,则反之。

同时,这两个功能使系统能够自动响应下游故障。

持久化

好的,很好,现在您可以承受以下情况:指标系统不可用,没有数据丢失,也没有降级到其他端点的API服务。您还可以通过添加更多工作实例从同一通道进行消费来水平扩展流的处理。

但是,想要针对给定的API事件提前一点时间收集所有类型的指标很难。

拥有数据流的存档日志以供将来进行任何操作难道不好吗?日志进行冗余备份是相对容易的,因此可以在灾难性的下游数据丢失情况下使其成为某种"计划z"。但是,您是否希望同一消费者也负责归档消息数据?可能不会,因为整个"关注点分离"的事情。

归档NSQ主题是一种常见的模式,我们构建了一个实用程序nsq_to_file,该实用程序与NSQ打包在一起,可以完全满足您的需求。

请记住,在NSQ中,每个主题的每个通道都是独立的,并且会收到所有消息的副本。通过在新通道(archive)上进行归档,您可以利用它来发挥优势。实际上,这意味着如果您的指标系统出现问题并且metrics通道进行了备份,则不会影响单独的archive通道将消息持久保存到磁盘。

因此,将nsq_to_file实例添加到同一主机,并使用如下所示的命令行:

/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实例保持与nsqlookupd持久的TCP连接, 并通过网络推送状态变更。具体来说,对于给定的主题及其所知道的所有通道,nsqd 将自己注册为一个生产者。这样一来,消费者可以查询nsqlookupd来确定谁是其感兴趣的主题生产者,而不用硬编码该配置。随着时间的流逝,他们将了解新生产者的存在,并能够解决故障。

您唯一需要做的更改是将现有nsqd实例和消费者实例指向nsqlookupd(每个人都清楚地知道nsqlookupd实例在哪里,但消费者却不清楚生产者在哪里,反之亦然)。现在,拓扑结构如下所示:

乍一看,这可能看起来更复杂。但是,这具有欺骗性,因为不断增长的基础架构所产生的影响很难通过视觉方式进行交流。您已经有效地将生产者与消费者分离了,因为 nsqlookupd现在在它们之间充当目录服务。添加依赖于给定数据流的其他下游服务很简单,只需指定您感兴趣的主题即可(通过查询nsqlookupd可以发现生产者)。

但是,查询数据的可用性和一致性又如何呢?通常,我们建议您根据需要的可用性要求来决定要运行多少。nsqlookupd不会占用大量资源,并且可以轻松地与其他服务一起使用。同样,nsqlookupd实例不需要相互协调或保持一致。消费者通常只需要一个nsqlookupd就可以获得他们需要的信息(他们将合并所知道的所有nsqlookupd实例的响应)。从操作上讲,这很容易迁移到一组新的nsqlookupd

docker

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

有一个包含所有NSQ二进制文件的最小nsq镜像。在运行Docker时将二进制文件指定为命令即可运行每个二进制文件。基本格式为:

docker run nsqio/nsq /<command>

注意命令之前/。例如:

docker run nsqio/nsq /nsq_to_file

链接

运行nsqlookupd

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

运行nsqd

首先,获取Docker主机的IP:

ifconfig | grep addr

其次,运行nsqd容器:

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标志设置为先前运行nsqlookupd的主机的IP和TCP端口,即dockerIP:4160

例如,假设主机IP为172.17.42.1

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参数:

docker run --name nsqlookupd -p 5160:4160 -p 5161:4161 nsqio/nsq /nsqlookupd

这将使nsqlookupd在端口51605161Docker主机IP上可用。

使用TLS

要将TLS与容器化的NSQ二进制文件一起使用,您需要包括证书文件,私钥和根CA文件。Docker镜像在目录/etc/ssl/certs/下具有可用的卷挂载,可用于此目的。将包含文件的主机目录挂载到该卷,然后照常在命令行中指定文件:

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数据

要将nsqd数据存储在主机磁盘上,请将/data卷用作您的数据目录,该目录可让您挂载到仅数据的Docker容器 或挂载到主机目录:

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

使用docker-compose

要启动nsqdnsqlookupd以及nsqadmin共同使用docker-compose,然后创建一个docker-compose.yml

version: '3'
services:
  nsqlookupd:
    image: nsqio/nsq
    command: /nsqlookupd
    restart: always
    ports:
      - 4160:4160
      - 4161:4161
  nsqd:
    image: nsqio/nsq
    command: /nsqd --lookupd-tcp-address=nsqlookupd:4160 --data-path=/data
    restart: always
    depends_on:
      - nsqlookupd
    volumes:
      - ./data:/data
    ports:
      - 4150:4150
      - 4151:4151
  nsqadmin:
    image: nsqio/nsq
    command: /nsqadmin --lookupd-http-address=nsqlookupd:4161
    restart: always
    depends_on:
      - nsqlookupd
    ports:
      - 4171:4171

从创建docker-compose.yml相同的目录中开始运行以下命令。

docker-compose up -d

将创建一个专用网络,并使用该专用网络启动三个容器。在本地主机上,每个容器将具有一个随机端口,该端口映射到docker-compose.yml中暴露的端口。

查看正在运行的容器状态和映射的端口。

docker-compose ps

查看正在运行的容器中的日志。

docker-compose logs

假设nsqlookupd已将主机端口31001映射到容器端口4161,则可以使用进行简单的ping curl

curl http://127.0.0.1:31001/ping

Previous

NSQ之客户端