rocketmq-baiji / rocketmq

Mirror of Apache RocketMQ
Apache License 2.0
4 stars 20 forks source link

Document Translation #3

Open xiaozongyang opened 6 years ago

xiaozongyang commented 6 years ago

Since the Apache RocketMQ is a top-level project which has users and developers around the world we need multi-language support. We are now calling for contribution about translating official document which is in English to Chinese. The translation will help users, developers and contributors in China understand the concepts, design principles and implementation details of the Apache RocketMQ.

qingywen commented 6 years ago

第十组 RocketMQ项目文档翻译(第二题)


1-Best Practice For Consumer

消费者最佳实践

一些有用的用户提示。

消费者组和订阅

首先您要注意的是,不同的消费者组可以独立地消费同样的主题,并且每个消费者都有自己的消费偏移量。请确保同一组中的每个消费者订阅相同的主题。

消息监听器

顺序

消费者将锁定每个 MessageQueue 以确保它按顺序逐个被使用。这个设计会导致性能下降,但在你关注消息顺序时非常有用。我们建议您返回 ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT ,而不是直接抛出异常。

并行

顾名思义,消费者将同时使用这些消息。我们推荐使用此方法以获得良好的性能。此外,我们建议您返回 ConsumeConcurrentlyStatus.RECONSUME_LATER,而不是直接抛出异常。

消费状况

对于 MessageListenerConcurrently ,您可以返回 RECONSUME_LATER 以告诉消费者你现在不能使用它并希望稍后重新消费,之后您可以继续消费其他消息。对于 MessageListenerOrderly ,因为您关心顺序所以不能跳过消息,但是您可以返回 SUSPEND_CURRENT_QUEUE_A_MOMENT 来告诉消费者等待片刻。

阻塞

我们不建议阻塞监听器,因为这样会阻塞线程池,并可能最终会终止消费程序。

线程数

消费者使用一个 ThreadPoolExecutor 来处理内部的消费,因此您可以通过设置 setConsumeThreadMin 或 setConsumeThreadMax 来更改它。

从何处开始消费

建立一个新的消费者组时,您需要决定是否消费代理中已经存在的历史消息。CONSUME_FROM_LAST_OFFSET 将忽略历史消息,并消费此后生成的任何内容。CONSUME_FROM_FIRST_OFFSET 将消耗Broker中存在的所有消息。您还可以使用 CONSUME_FROM_TIMESTAMP 来消费在指定的时间戳之后生成的消息。

重发

许多情况可能导致重发,例如:

因此,如果您的应用程序不能容忍重发,那么您可能需要做一些外部工作来处理这个问题,例如检查DB的主键。


2-Best Practice For NameServer

NameServer最佳实践

在Apache RocketMQ中,名称服务(NameServer)被设计用于协调分布式系统的每个组件,这种协调主要通过管理主题的路由信息来实现。

管理由两部分组成:

因此,在启动代理和客户端之前,我们需要告诉它们如何通过向名称服务提供名称服务地址列表的方式来访问名称服务。 在Apache RocketMQ中,可以通过四种方式来完成这个操作。

编程的方式

对于代理,我们可以在代理配置文件中指定namesrvAddr = name-server-ip1:port; name-server-ip2:port

对于生产者和消费者,我们可以使用如下方式向它们提供名称服务地址列表:

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

如果您在shell上以管理员身份使用命令行,也可以通过下列语句进行指定:

sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION

下面这个例子假设在一个名称服务节点上查询集群信息:sh mqadmin -n localhost:9876 clusterList

如果您已将管理工具集成到自己的仪表板中,则可以:

DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

Java选项

您还可以在启动应用程序前通过指定后续java选项rocketmq.namesrv.addr来将名称服务地址列表提供给应用程序。

环境变量

您可以导出NAMESRV_ADDR环境变量。如果环境变量的值已被设置,代理和客户端将检查并使用该值。

HTTP端点

如果您未使用前面提到的方法指定名称服务地址列表,Apache RocketMQ将访问以下HTTP端点来获取并更新名称服务地址列表。这一行为每两分钟进行一次,初始延迟为10秒。

默认情况下,端点是:

http://jmenv.tbsite.net:8080/rocketmq/nsaddr

您可以使用Java选项jmenv.tbsite.netrocketmq.namesrv.domain来重写jmenv.tbsite.net ,您还可以使用Java选项rocketmq.namesrv.addr来重写nsaddr部件。

如果您在生产环境中运行Apache RocketMQ,建议使用此方法,因为它提供了最大程度上的灵活性——您可以根据名称服务的系统负载情况,动态添加或删除名称服务节点,而无需重新启动代理和客户端。

优先级

文章中先介绍的方法优于其后的方法:

编程方式 > Java选项 > 环境变量 > HTTP端点

izuomeng commented 6 years ago

第4组 文档翻译(第四题)

1

NameServer最佳实践

在 Apache RocketMQ 中,NameServer(名称服务器)旨在协调分布式系统的各个组件,而协调的方式主要是通过管理主题路由信息来实现的。

管理由两部分组成:

编程的方式

对于 brokers,我们可以在 broker 的配置文件中指定namesrvAddr=name-server-ip1:port;name-server-ip2:port

对于生产者和消费者,我们可以给他们提供下列姓名服务器地址列表:

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

如果你从 shell 中使用管理命令行,你也可以这样指定:

sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION

一个简单的例子是 sh mqadmin -n localhost:9876 clusterList 指定在名称服务器节点上查询集群信息。

如果你将管理工具集成到你自己的仪表盘中,你可以:

DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

Java 参数

还可以通过指定后续的 java 参数 rocketmq.namesrvv.addr 来为你的应用程序提供名称服务器地址列表。

环境变量

你可以设置 NAMESRV_ADDR 环境变量。如果设置了,Broker 和 clients 将检查并使用这个值。

HTTP 端点(HTTP Endpoint)

如果你没有使用前面提到的方法指定名称服务器地址列表,Apache RocketMQ 将每 2 分钟访问一次 HTTP 端点以获取和更新名称服务器地址列表,初始延迟 10 秒。

默认情况下,终点是:

http://jmenv.tbsite.net:8080/rocketmq/nsaddr

你可以使用这个 Java 选项:rocketmq.namesrv.domain 覆盖jmenv.tbsite.net,也可以使用 rocketmq.namesrv.domain.subgroup 覆盖 nsaddr 部分

如果在生产环境中运行 Apache RocketMQ,建议使用此方法,因为它提供了最大程度的灵活性——你可以动态地添加或删除名称服务器节点,而无需根据你的名称服务器的系统负载重新启动代理和客户端。

优先级

先介绍的方法优先于后一种方法:

编程方式 > Java 选项 > 环境变量 > HTTP 端点

2

生产者的最佳实践

为用户提供的一些小技巧

发送状态 SendStatus

当发送一则消息时,你会得到一个发送结果,结果中包含了发送状态。首先,我们假定消息的 isWaitStoreMsgOK 字段值为 true(默认配置),否则在没有异常抛出的情况下,这个字段的值总是 SEND_OK,下面是对其他可能值的描述:

FLUSH_DISK_TIMEOUT

如果 Broker 将消息存储配置的 FlushDiskType 字段设置为 SYNC_FLUSH(默认是 ASYNC_FLUSH),并且 Broker 没有在消息存储配置的 syncFlushTimeout 时间内(默认是 5 秒)完成磁盘刷新,会得到这个返回值

FLUSH_SLAVE_TIMEOUT

如果 Broker 的角色是 SYNC_MASTER(默认是 ASYNC_MASTER),并且 slave Broker 没有在消息存储配置的 syncFlushTimeout 时间内(默认是 5 秒)完成与主 Broker 的同步,会得到这个返回值

SLAVE_NOT_AVAILABLE

如果 Broker 的角色是 SYNC_MASTER(默认是 ASYNC_MASTER),但是没有配置 slave Broker,会得到这个返回值

SEND_OK

得到这个返回值并不意味着它是可靠的。为了确保不会丢失消息,还应该启用 SYNC_MASTER 或者 SYNC_FLUSH

Duplication 或者 Missing

如果你得到 FLUSH_DISK_TIMEOUT 和 FLUSH_SLAVE_TIMEOUT 这两个返回值,并且 Broker 在这个时候刚好宕机了,你会丢失所发送的消息。这种时候你有两个选择,一是放任不管,当然这个消息也会丢失;二是重新发送这个消息,这有可能会引发消息重复。通常情况下我们建议重发消息并且在消费时处理消息重复的问题,除非你觉得丢失几条消息也没什么大不了。但是要注意,如果你得到的返回值是 SLAVE_NOT_AVAILABLE,那么重发消息也是没用的,这时你应该记录下来,向集群管理员反映问题。

超时

在客户端(Client)向 Broker 发送请求并等待响应的过程中,如果经过最大等待时间仍然未得到响应,客户端会给出一个远程超时的警告。一般而言,客户端默认的等待时间是 3 秒,但也可以利用 send(msg, timeout)代替 send(msg)的方式,对超时参数进行修改。由于 Broker 将消息写入磁盘或进行主从同步的操作本身需要花费一定的时间,因此并不建议将超时时间设置得过小。而如果超时参数超过 syncFlushTimeout 也没什么大的影响,因为 Broker 可能在超时之前已经返回了 FLUSH_SLAVE_TIMEOUT 或 FLUSH_SLAVE_TIMEOUT。

消息大小

建议发送消息的大小不要超过 512k。

异步发送

默认的 send(msg)方式会使得操作在前一个响应信息返回之前一直处于中断状态。因此,如果你想要获得更好的性能,建议使用 send(msg, timeout)代替 send(msg),这种方式可以异步返回响应信息。

生产者组

一般而言,信息的生产者对于整个过程信息传递的流程并没有什么影响。在默认条件下,同一个 JVM 中,相同的生产者组只能创建一个生产者,通常情况下这是足够的。但如果你处理的是一个复杂的事务,则需要进一步关注生产者对于整个流程的影响。

线程安全

生产者是线程安全的,可以放心使用。

性能

如果你需要处理大数据,并要在一个 JVM 中使用超过一个生产者,我们建议你:

Weiweitb8 commented 6 years ago

第三组 RocketMQ项目文档翻译(第三题)

1. RocketMQ JVM / Linux配置

这是配置RocketMQ中间件的JVM / OS参数的简介。它指出了在部署RocketMQ集群之前应该考虑的一些指定配置。

JVM选项

推荐使用最新发布的JDK 1.8版本,包括服务器编译器和一个8G的堆。为了防止JVM调整堆大小,设置相同的Xms和Xmx值以获得更好的性能。简单的JVM配置如下所示:

-server -Xms8g -Xmx8g -Xmn4g

如果您不关心RocketMQ中broker的启动时间,为了确保在JVM初始化期间能分配每个内存分页,预先分配Java堆内存是个更好的选择。不关心启动时间的人可以启用它:

-XX:+AlwaysPreTouch

禁用偏向锁可以减少JVM卡顿:

-XX:-UseBiasedLocking

至于垃圾收集,建议使用带JDK 1.8的G1收集器:

-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30

这些GC选项看起来有点激进,但事实证明它在我们的生产环境中具有良好的性能。

不要给 -XX:MaxGCPauseMillis 设置太小的值,否则JVM将使用一部分新生代内存来实现这一目标,这将导致非常频繁的新生代GC。

建议使用滚动GC日志文件:

-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m

如果写入GC文件会增加代理的延迟,请考虑将GC日志文件重定向到内存文件系统:

-Xloggc:/dev/shm/mqgc%p.log

Linux内核参数

有一个os.sh脚本列出了bin文件夹中的许多内核参数,这些参数只要稍加修改,就可以在生产中使用,注意下面的参数,更多细节请参考/ proc / sys / vm / * [1]文档。

vm.extra_free_kbytes: 告诉VM在后台回收(kswapd)启动的阈值和直接回收(通过分配进程)的阈值之间保留额外的可用内存.RocketMQ使用此参数来避免内存分配中的高延迟。

vm.min_free_kbytes: 如果将其设置为低于1024KB,系统将会慢慢的被破坏,并且容易在高负载的情况下出现死锁。

vm.max_map_count: 限制进程可能具有的最大内存映射区域数。RocketMQ将使用mmap加载CommitLog和ConsumeQueue,因此建议为此参数设置更大的值。

vm.swappiness: 定义内核交换内存分页的数量。较高的值会增加交换量,较低的值会减少交换量。建议设定这个值为10来避免交换延迟。

File descriptor limits: RocketMQ需要为文件(CommitLog和ConsumeQueue)和网络连接打开文件描述符。我们建议将655350设置为文件描述符。

Disk scheduler: RocketMQ建议使用最后期限I/O调度器,它试图为requests[2]提供有保证的延迟。

参考文档

  1. https://www.kernel.org/doc/Documentation/sysctl/vm.txt
  2. https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/ch06s04s02.html 更新于2017年7月15日

2.消费者最佳实践

一些对用户有用的提示。

消费者组和订阅

首先您要注意的是,不同的消费者群体可以独立地使用相同的主题,并且每个消费者组都有自己的消费偏移量。请确保同一组内的每个消费者订阅相同的主题。

消息监听

有序

消费者将锁定每个消息队列以确保它按顺序逐个使用。这会导致性能损失,但是当您关心消息的顺序时它会很有用。不建议抛出异常,您可以返回ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT代替。

并行

顾名思义,消息消费者将同时接收消费这些消息。建议使用它以获得良好的性能。我们不建议抛出异常,您可以返回ConsumeConcurrentlyStatus.RECONSUME_LATER代替。

消费状况

对于 MessageListenerConcurrently ,您可以返回RECONSUME_LATER以告诉消息消费者您现在不能使用它并希望稍后重新创建它。然后,您可以继续使用其他消息。对于MessageListenerOrderly,因为您关心顺序,所以不能跳过消息,但是您可以返回SUSPEND_CURRENT_QUEUE_A_MOMENT来告诉消费者等待片刻。

阻塞

不建议阻塞监听器,因为它会阻塞线程池,并最终可能会停止消费过程。

线程数

消费者使用ThreadPoolExecutor在内部处理消费,因此您可以通过设置setConsumeThreadMin或setConsumeThreadMax来更改它。

消费位置

建立新的消费者组时,需要决定是否需要消费已经存在于Broker中的历史消息。CONSUME_FROM_LAST_OFFSET将忽略历史消息,并消费之后生成的任何内容。CONSUME_FROM_FIRST_OFFSET将使用Broker中存在的每条消息。您还可以使用CONSUME_FROM_TIMESTAMP来使用在指定时间戳之后生成的消息。

重发

许多情况都可能导致重复发送,例如:

因此,如果应用程序不能容忍重复发送,您可能需要做一些外部工作来处理这个问题。例如,您可以检查数据库的主键。 更新日期:2016年12月25日

xf1994 commented 6 years ago

第八组 RocketMQ项目文档翻译

1. 生产者最佳实践

一些对用户有用的提示

发送状态

当发送消息时,你需要获取一个包含发送状态的结果。首先,假设消息(Message)中的isWaitStoreMsgOK=true(默认为true)。如若不然,我们会在没有抛出异常的情况下始终得到SEND_OK,下面是几个状态的描述:

FLUSH_DISK_TIMEOUT

如果broker的消息存储设置参数(MessageStoreConfig)中FlushDiskType=SYNC_FLUSH(默认是ASYNC_FLUSH),并且broker没有在消息存储设置参数中的syncFlushTimeout时间内完成消息的存储(默认5秒),会返回这个状态值

FLUSH_SLAVE_TIMEOUT

如果broker的角色是SYNC_MASTER(默认ASYNC_MASTER),并且从broker没有和主broker在消息存储设置参数中的syncFlushTimeout时间内完成同步(默认5秒),会返回这个状态

SLAVE_NOT_AVAILABLE

如果broker的角色是SYNC_MASTER(默认ASYNC_MASTER),但是没有从broker被配置,会返回这个状态

SEND_OK

SEND_OK并不意味着它是可靠的。要确保消息不丢失,你需要开启SYNC_MASTER(同步主)或者SYNC_FLUSH(同步写)

重发或丢失

如果你发送后返回的结果是FLUSH_DISK_TIMEOUT,FLUSH_SLAVE_TIMEOUT,并且这时broker挂掉了,你会发现刚刚发送的消息丢失了。这种情况下你有两个选择,第一、丢就丢吧,这可能会导致这个消息的丢失。第二,再发一次,这可能会引发消息重复。通常我们建议是重发一次,并找到一个方法去处理发送重复引发的重复消费问题。除非你觉得消息丢失也没什么关系。但是记住当你得到的状态是SLAVE_NOT_AVAILABLE,重复发送的意义也不大。如果发生这个响应,应该记录下来,并向集群管理者报警

超时

客户端发送请求到Broker,等待响应,如果经过最大等待时间仍然没等到响应,客户端会抛出一个远程超时异常。默认等待时间是3秒。你可以使用send(msg, timeout)方法代替send(msg)方法来设置超时时间参数。注意,我们不建议你设置太小的超时时间,因为Broker需要一些时间去写磁盘还有做主从同步。另外,这个值设置得超过syncFlushTimeout并没什么大的影响,因为Broker可能在超时之前已经返回了带有FLUSH_SLAVE_TIMEOUTFLUSH_SLAVE_TIMEOUT的响应。

消息大小

我们建议大小不要超过512k

异步发送

默认的send(msg)方法会阻塞,直到返回响应信息。所以如果你关注性能,我们建议你使用会异步返回响应信息的seng(msg,callback)方法

生产者组

通常来讲,发送者组没什么影响。但是如果涉及复杂的事务,你就需要去关注它。默认情况下,同一个jvm中,你只需要在相同的发送者组中创建一个生产者即可满足需求

线程安全

生产者是线程安全的,你可以直接在你的业务解决方案中放心使用。

性能

在一个jvm中,如果你要使用多个生产者处理大数据,我们建议你:

2. 最佳实践之NameServer部分

在Apache RocketMQ中,名称服务器用于协调分布式系统的每个构成要素,这种协调主要通过管理主题路由信息来实现的。

管理由两部分组成:

因此,在启动中介(brokers)和客户端之前,我们需要告诉他们如何通过给他们提供一个名称服务器地址列表来使他们能够访问名称服务器。在Apache RocketMQ中,这可以用以下四种方式完成。

通过编程的方式

对于brokers,我们可以通过在其配置文件中指定 namesrvAddr=name-server-ip1:port;name-server-ip2:port实现。

对于生产者和消费者,我们可以用如下方式向他们提供姓名服务器地址列表:

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

如果您通过shell以管理员身份使用命令行,您也可以用这种方式指定:

sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION

一个简单的例子是: 使用sh mqadmin -n localhost:9876 clusterList 在名称服务器节点上查询集群信息。

如果您已将管理员权限工具集成到您自己的仪表板中,您可以使用:

DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

Java参数

通过在调用前指定后续的java参数rocketmq.namesrvv.addr,您的应用程序可以获得名称服务器的地址列表。

环境变量

您可以设置NAMESRV_ADDR环境变量。在配置之后,Brokers和客户端将检查并使用其值。

HTTP端点

如果您没有使用前面提到的方法指定名称服务器地址列表,Apache RocketMQ将每2分钟访问以下HTTP端点来获取和更新名称服务器地址列表,初始延迟为10秒。

默认情况下,这个端点为: http://jmenv.tbsite.net:8080/rocketmq/nsaddr

您可以使用这个Java选项:rocketmq.namesrv.domain 来覆盖jmenv.tbsite.net,您也可以使用这个Java选项: rocketmq.namesrv.domain.subgroup覆盖nsaddr部分。

如果您是在生产环境中运行Apache RocketMQ的,建议使用此方法。因为它为您提供了最大的灵活性——您可以动态地添加或删除名称服务器节点,而无需根据您的名称服务器的系统负载重新启动中介和客户端。

优先级

在文章中先介绍的方法优先级高于后介绍的方法:

通过编程的方式 > Java参数 > 环境变量 > HTTP端点

Jie77 commented 6 years ago

第二组RocketMQ项目文档翻译


消费者最佳实践

一些有用的用户提示。

消费者组和订阅

第一件你需要注意的事情是不同的消费者组可以独立的消费一些 topic,并且每个消费者组都有自己的消费偏移量,请确保同一组内的每个消费者订阅相同的 topic。

消息监听器

有序的

消费者将锁定每个消息队列,以确保他们被逐个消费,虽然这将会导致性能下降,但是当你关心消息顺序的时候会很有用。我们不建议抛出异常,你可以返回 ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT 作为替代。

并发的

顾名思义,消费者将并发消费这些消息,建议你使用它来获得良好性能,我们不建议抛出异常,你可以返回 ConsumeConcurrentlyStatus.RECONSUME_LATER 作为替代。

消费状态

对于并发的消费监听器,你可以返回 RECONSUME_LATER 来通知消费者现在不能消费这条消息,并且希望可以稍后重新消费它。然后,你可以继续消费其他消息。对于有序的消息监听器,因为你关心它的顺序,所以不能跳过消息,但是你可以返回 SUSPEND_CURRENT_QUEUE_A_MOMENT 告诉消费者等待片刻。

阻塞的

不建议阻塞监听器,因为它会阻塞线程池,并最终可能会终止消费进程。

线程数

消费者使用 ThreadPoolExecutor 在内部对消息进行消费,所以你可以通过设置 setConsumeThreadMin 或 setConsumeThreadMax 来改变它。

从何处开始消费信息

当建立一个新的消费者组时,需要决定是否需要消费已经存在于 Broker 中的历史消息。CONSUME_FROM_LAST_OFFSET 将会忽略历史消息,并消费之后生成的任何消息。CONSUME_FROM_FIRST_OFFSET 将会消费每个存在于 Broker 中的信息。你也可以使用 CONSUME_FROM_TIMESTAMP 来消费在指定时间戳后产生的消息。

重复

许多情况会导致重复,例如:

因此,如果你的应用程序无法容忍重复,你可能需要做一些外部工作来处理此问题。例如,你可以检查你数据库的主键。


NameServer的最佳实践

在 Apache RocketMQ 中,名称服务器(name servers)被设计用来协调分布式系统中的每个组件,协调主要通过管理 topic 路由信息来实现。

管理由两部分组成:

因此,在启动代理和客户端之前,我们需要通过提供给他们名称服务器地址列表告诉他们如何到达名称服务器 。在 Apache RocketMQ 中,这可以通过四种方式完成。

程序化的方式

对于brokers,我们可以在代理配置文件中指定namesrvAddr = name-server-ip1:port; name-server-ip2:port

对于生产者和消费者,我们可以按如下方式为他们提供名称服务器地址列表:

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

如果你在 shell 中使用 admin 命令行,也可以这样指定:

sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION

一个简单的例子是:sh mqadmin -n localhost:9876 clusterList 假设在名称服务器节点上查询集群信息。

如果你已经将管理工具集成到自己的控制面板中,你可以:

DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

Java选项

名称服务器地址列表也可以在启动之前通过指定后续 java 选项rocketmq.namesrv.addr来提供给你的应用程序。

环境变量

你可以导出NAMESRV_ADDR环境变量。如果设置后,Brokers 和 clients 将检查并使用这个变量值。

HTTP端点

如果你未使用前面提到的方法指定名称服务器地址列表,Apache RocketMQ 将访问以下 HTTP 端点,每隔两分钟获取并更新名称服务器地址列表,初始延迟为10秒。

默认情况下,端点是:

http://jmenv.tbsite.net:8080/rocketmq/nsaddr

你可以使用 Java 选项:rocketmq.namesrv.domain来覆盖jmenv.tbsite.net,你也可以使用 Java 选项rocketmq.namesrv.domain.subgroup来覆盖nsaddr

如果你正在生产环境中运行 Apache RocketMQ,建议使用此方法,因为它为你提供了最大的灵活性 - 你可以动态添加或删除名称服务器节点,而无需根据名称服务器的系统负载重新启动 brokers 和客户端。

优先级

首先介绍的方法优先于后者:

Programmatic Way > Java Options > Environment Variable > HTTP Endpoint

lostjeffle commented 6 years ago

第六组RocketMQ项目文档翻译

Consumer 最佳实践指南

本文列举了构建消费者 (consumer) 程序的几个建议。

消费者组 (Consumer Group) 与 订阅 (Subscriptions)

你需要知道的第一件事情是,不同的消费者组 (consumer group) 可以独立地消费同一个主题 (topic) 下的消息,此时各个消费者组具有各自独立的消费偏移量 (consuming offset)。

此外请确保同一个消费者组中的所有消费者订阅有相同的主题。

消息监听器 (MessageListener)

顺序 (Orderly)

(在顺序 (orderly) 消费模式下),消费者会获取消息队列 (message queue) 的锁,以顺序获取 消息队列中的消息。该模式会带来一定的性能损失,但是可以应用在关心消息顺序的场景下。(该模式下消息消费的顺序与消息在消息队列中的顺序相一致。)

一般不建议在消息监听器中抛出异常,因而在遇到错误时可以返回ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT

并行 (Concurrently)

(在并行 (concurrently) 消费模式下),消费者会并行获取消息队列中的(多个)消息。(此时消息消费的顺序与消息在消息队列中的顺序可能并不一致。)

一般不建议在消息监听器中抛出异常,因而在遇到错误时可以返回ConsumeConcurrentlyStatus.RECONSUME_LATER

消费状况 (Consume Status)

在并行消费模式下 (MessageListenerConcurrently) ,当消息监听器不能立即处理某个消息时,可以返回RECONSUME_LATER以表示推迟该消息的处理。之后消费者可以继续处理该消息队列中的其它消息。

在顺序消费模式下 (MessageListenerOrderly),(当消息监听器不能立即处理某个消息时)为了确保消息处理的顺序,我们不能跳过该消息(而处理消息队列中的其它消息),此时消息监听器可以返回SUSPEND_CURRENT_QUEUE_A_MOMENT,以提示消费者等待一段时间。

阻塞 (Blocking)

一般不推荐在消息监听器中阻塞,因为这样会阻塞线程池,最终甚至可能使整个消费者程序停止运行。

线程数量 (Thread Number)

消费者内部使用线程池 (ThreadPoolExecutor) 执行消息处理的任务,你可以通过修改setConsumeThreadMin 与 setConsumeThreadMax 参数,来配置线程池的线程数量。

从何处开始消费 (ConsumeFromWhere)

当一个消费者组新创建时,需要决定(该新创建的消费者组)是否需要处理 broker 中在此之前已经存在的消息。

当配置为CONSUME_FROM_LAST_OFFSET时,(新创建的消费者组)会忽略在其创建之前已经存在的消息,而只是处理之后产生的消息。

当配置为CONSUME_FROM_FIRST_OFFSET时,(新创建的消费者组)会处理 broker 中存在的所有消息。

此外你也可以配置为 CONSUME_FROM_TIMESTAMP,(此时新创建的消费者组)只会处理在特定时间戳(timestamp)之后产生的消息。

重复 (Duplication)

很多情况会导致消息的重复,例如

因而如果你的程序不能容忍重复的消息,你自己必须实现额外的逻辑以解决这一问题,例如你可能需要检查数据库的主键 (primary key)。

NameServer 最佳实践指南

Apache RocketMQ 中,name server 通过管理消息主题 (topic) 的路由信息,以使得系统中分散的各个组件协同工作。

name server 主要提供以下两部分的管理

因而为了使 broker 与客户端程序成功访问 name server,在其启动之前我们必须向其传递 name server 的地址。

Apache RocketMQ 中有以下四种方式实现这一目的。

通过编程的方式 (Programmatic Way)

对于 broker,我们可以在其配置文件中通过 namesrvAddr=name-server-ip1:port;name-server-ip2:port 配置 name sever 的地址。

对于 producer 与 consumer,我们可以按照以下形式指定 name sever 的地址。

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

如果你习惯在命令行中使用 mqadmin 命令,那么你可以通过以下格式为执行的命令指定 name server 的地址。

sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION

一个简单的例子是 sh mqadmin -n localhost:9876 clusterList,其中指定查询 localhost:9876 地址处的 name server 中存储的 broker 集群的路由信息。

而如果你希望在代码中调用 mqadmin 命令,那么你可以通过以下形式指定 name server 的地址。

DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt("please_rename_unique_group_name");
defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");

Java 参数 (Java option)

在启动 broker 与客户端程序之前,你也可以通过配置 rocketmq.namesrv.addr 参数来指定 name server 的地址。

环境变量 (Environment Variable)

你可以通过 NAMESRV_ADDR 环境变量来设置 name server 的地址,当 NAMESRV_ADDR 环境变量存在设置时,broker 与客户端会使用该环境变量的值作为 name server 的地址。

HTTP 站点 (HTTP Endpoint)

当以上配置方式均未使用时,Apache RocketMQ 会每隔两分钟访问某个特定的 HTTP 地址,以获取并更新 name server 的地址。程序在启动10秒后开始以上轮询操作。

默认配置下,该 HTTP 地址为

http://jmenv.tbsite.net:8080/rocketmq/nsaddr

你可以使用 Java option 对该 HTTP 地址进行配置,其中 rocketmq.namesrv.domain 用于配置其中的 jmenv.tbsite.net 参数,rocketmq.namesrv.domain.subgroup 用于配置其中的 nsaddr 参数。

如果你是在生产环境中使用Apache RocketMQ ,那么我们推荐使用这种配置方式,因为该方式具有最大的灵活性。你可以根据 name server 的负载变化,动态地增加或减少 name server 的数量,而不必重启 broker 与客户端程序。

优先级 (Priority)

以上介绍的几种配置方式,其优先级递减,即

Programmatic Way > Java Options > Environment Variable > HTTP Endpoint
xjtushilei commented 6 years ago

第9组 第1篇

核心概念

image

根据上面的模型,我们可以深入研究一些关于消息传递系统设计的话题:

生产者

生产者发送业务中产生的消息到 brokers,RocketMQ 提供了多种发送方式:同步,异步,单程。

生产者组

把相同角色的生产者组织到一起。在事务提交后,生产组中的不同实例都可以连接 broker 执行提交或回滚事务,以防原生产者在提交后就挂掉。

注意: 考虑到生产者有很强的消息发送能力,每个生产者组只允许有一个实例用来避免不必要的初始化。

消费者

消费者从 brokers 拉取消息给应用使用。在用户应用方面,提供了两种类型的消费者:

拉取型

拉取型主动从 broker 拉取信息,一次拉取一批,用于消费应用进行消费。

推送型

推送型是另一种思路,它封装了消息的拉取、消费的进程和其他的内部工作细节,只提供一个在消息到达时的回调接口。

消费者组

与先前提到的生产者组类似,相同的消费者角色组织到一起命名为消费者组

消费者组是一个不错的概念,它实现了负载平衡和容错的目标,在信息消费方面,非常简单。

注意: 一个消费者组中的消费者实例必须订阅相同的主题。

主题

主题是生产者传递消息和消费者拉动消息的类别。主题与生产者与消费者之间是松耦合的。特别强调,一个主题可以有零个,一个或者多个生产者向它发送消息。相反,一个生产者可以向多个不同的主题发送消息。从消费者角度讲,一个主题可以被零个或者一个或者多个消费者组订阅,同样的一个消费者组可以订阅一个或多个主题,只要这个消费者组保持一致的订阅即可。

消息

消息是将要传递的信息。消息必须有一个主题,可以理解为你写信时邮寄的地址。消息也可能有一个标签选项和额外的键值对。例如,你可能发送一条消息时设置一个 key 标记,并通过这个 key 在 broker 中筛选这条消息,用来判断在开发阶段的问题。

消息队列

主题被划分为一个或多个子主题,这就是消息队列。

标签

标签可以理解为更细化一级的主题,为使用者提供更灵活的查找。有了标签同一业务产生的消息可以有相同的主题不同的标签,不同标签标记的可以有不同的用途。标签可以让你的代码变得清晰连贯,还可以给 RocketMQ 提供更好的查询支持。

代理

Broker 是 RocketMQ 系统的重要组成部分。它接受并存储来自生产者发送的消息,并且准备去处理来自消费者的拉取请求。它也存储和消息有关的信息,包括消费者组,消费位置,还有主题/队列的信息。

名称服务

名称服务按照路由信息提供服务。生产者/消费者客户端通过主题来查找具有一致性的代理列表。

消息模式

消息顺序

DefaultMQPushConsumer 被设置好,你需要设置消费是顺序的还是并发的:

注意: 如果消费顺序被指定,最大的消费并发数就是这个消费者组的消息队列的订阅数。

注意: 这个模式下消息顺序不再被保证。

第9组 第2篇

Producer最佳实践

一些写给使用者的实用提示。

发送状态

在发送消息的时候,你会获得一个包含发送状态 SendStatus 的发送结果 SendResult 。首先,我们假设消息的isWaitStoreMsgOK 被配置为:isWaitStoreMsgOK = true(默认配置)。因为如果不这样配置的话,那么我们会在发送没有异常的情况下始终得到发送成功 SEND_OK 的发送状态。下边是关于每个状态的描述:

FLUSH_DISK_TIMEOUT

如果 Broker 设置 MessageStoreConfig 的属性 FlushDiskType 为: FlushDiskType = SYNC_FLUSH (默认配置是 ASYNC_FLUSH ),并且Broker没有在 syncFlushTimeout 参数配置的时间内(默认是5秒钟)完成刷盘的操作,那么消息发送将会获得这个返回状态。

FLUSH_SLAVE_TIMEOUT

如果 Broker 的角色是 SYNC_MASTER (默认是 ASYNC_MASTER ),并且从 Broker 没有在 syncFlushTimeout 参数配置的时间内(默认是5秒钟)完成同步,那么消息发送将会获得这个返回状态。

SLAVE_NOT_AVAILABLE

如果 Broker 的角色是 SYNC_MASTER (默认是 ASYNC_MASTER ),但是从 Broker 没有被配置,那么消息发送将会获得这个返回状态。

SEND_OK

SEND_OK 并不意味着就一定是可靠的。要确保消息不丢失,你还应启用 SYNC_MASTER 或者 SYNC_FLUSH 选项。

消息重复或消息丢失

如果你发送消息后返回的结果是 FLUSH_DISK_TIMEOUT, FLUSH_SLAVE_TIMEOUT,并且 Broker 这时正好挂掉了,那么你会发现刚发送的消息丢失了。这种情况下你会有两个选择:第一种是无为而治,但是这样做会导致消息的丢失;第二种是重发一次,但是这可能会引起消息的重复。通常情况下,我们建议重发一次,并且找到一个方法来处理因为重复发送而导致的重复消费问题。当然如果你觉得消息丢失也不是什么大问题的话也可以不这么做。但是请记住当你得到的状态是SLAVE_NOT_AVAILABLE 的时候,重复发送就没有作用了。如果确实收到了这种发送结果的话,应该将上下文记录下来,并向集群管理员报告。

超时

客户端发送请求到 Broker,然后等待响应,如果经过最大等待时间后仍然没等到响应,客户端会抛出一个远程超时的异常RemotingTimeoutException。默认的等待时间是3秒。如果要设置超时时间参数,你可以使用send(msg, timeout) 方法来代替 send(msg) 方法。请注意,我们并不建议你设置太小的超时时间,因为 Broker 还需要一些时间去进行刷盘或者主从同步的操作。除此之外,如果超时时间的值超过 syncFlushTimeout 很多,那么该值可能最终影响不大,因为 Broker 可能在超时之前就已经返回 FLUSH_SLAVE_TIMEOUTFLUSH_DISK_TIMEOUT 的状态了。

消息的大小

我们建议消息的大小不要超过512k。

异步发送

默认的发送函数 send(msg) 会保持阻塞直到响应信息的返回。所以如果你关注性能,那么我们建议你使用 seng(msg,callback) 这个方法,它会异步地返回响应信息。

生产者组

通常来讲,生产者组是没有任何影响的。但是当你需要处理一些复杂事务的时候,你就需要对它关注一下了。默认情况下,你只能在同一个 JVM 中创建一个具有相同生产者组的生产者,这样的方式其实就能够满足需求了。

线程安全

生产者是线程安全的,你可以在业务解决方案中尽情的使用它。

性能

如果你要在 JVM 中使用超过一个生产者来处理大数据的话,我们建议:

yilishan commented 6 years ago

第七组文档翻译

(一)

消费者最佳实践

一些有用的用户提示。

消费者群体和订阅

首先应当注意,不同的消费者群体可以独立地使用同一个队列集合,并且每个消费者群体都有自己的消费偏移量。请确保同一组内的每个消费者订阅同一个队列集合。

消息监听

有序

消费者将锁定每个消息队列以确保它被按顺序依次使用,这种方式会导致性能下降,但当你关心消息顺序时则会很有用。我们建议返回ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT来替换抛出异常。

并发

顾名思义,Consumer将并行使用这些消息。我们建议使用并发以获得良好的性能。我们建议返回ConsumeConcurrentlyStatus.RECONSUME_LATER来替换抛出异常。

消费状态

【reconsume】--->【consume】

对于MessageListenerConcurrently类,你可以返回RECONSUME_LATER来告诉消费者你现在不能使用它并希望稍后【消费】它。然后,你可以继续消费其他消息。对于MessageListenerOrderly类而言,因为关注顺序,所以不能跳过消息,但是你可以通过返回SUSPEND_CURRENT_QUEUE_A_MOMENT来告诉消费者等待片刻。

阻塞

我们不建议阻塞监听器,因为它会阻塞线程池,最终可能会导致消费进程阻塞。

线程数

消费者在内部使用ThreadPoolExecutor类处理消费,因此你可以通过setConsumeThreadMin方法或setConsumeThreadMax方法进行更改。

ConsumeFromWhere

新的消费者群体被建立时,这个消费者群体是否需要消费已经存在于Broker中的历史消息,这是由ConsumeFromWhere决定的。CONSUME_FROM_LAST_OFFSET将忽略历史消息,并消费之后生成的任何内容。CONSUME_FROM_FIRST_OFFSET将使用Broker中存在的每条消息,你还可以使用CONSUME_FROM_TIMESTAMP来使用在指定时间戳之后生成的消息。

重复

许多情况都可能导致重复,例如:

因此,如果你的应用程序无法容忍重复,你可能需要做一些额外工作来处理这个问题,例如检查数据库的主键。

更新: 2016年12月25日

(二)

RocketMQ JVM/Linux配置

本文是配置RocketMQ代理JVM/OS参数的简介。它指出了在部署RocketMQ集群之前应该考虑的某些指定配置。

JVM选项

推荐使用最新发布的JDK 1.8版本,包括服务器编译器和一个8g堆。通过设置相同的Xms和Xmx值来防止JVM调整堆大小以获得更好的性能。简单的JVM配置如下所示:

-server -Xms8g -Xmx8g -Xmn4g

如果您不关心RocketMQ代理的启动时间,还有一种更好的选择,就是通过预触摸Java堆以确保在JVM初始化期间每个页面都将被分配。那些不关心启动时间的人可以启用它:

-XX:+AlwaysPreTouch

禁用偏置锁定可能会减少JVM暂停:

-XX:-UseBiasedLocking

至于垃圾回收,建议使用带JDK 1.8的G1收集器:

-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30

这些GC选项看起来有点激进,但事实证明它在我们的生产环境中具有良好的性能。

不要把-XX:MaxGCPauseMillis的值设置太小,否则JVM将使用一个小的年轻代来实现这个目标,这将导致非常频繁的minor GC。

建议使用rolling GC日志文件:

-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m

如果写入GC文件会增加代理的延迟,可以考虑将GC日志文件重定向到内存文件系统:

-Xloggc:/dev/shm/mq_gc_%p.log123

Linux内核参数

os.sh脚本在bin文件夹中列出了许多内核参数,可以进行微小的更改然后用于生产用途。下面的参数需要注意,更多细节请参考/proc/sys/vm/*[1]的文档。

vm.extra_free_kbytes,告诉VM在后台回收(kswapd)启动的阈值与直接回收(通过分配进程)的阈值之间保留额外的可用内存.RocketMQ使用此参数来避免内存分配中的长延迟。

vm.min_free_kbytes,如果将其设置为低于1024KB,将会巧妙的将系统破坏,并且系统在高负载下容易出现死锁。

vm.max_map_count,限制一个进程可能具有的最大内存映射区域数。RocketMQ将使用mmap加载CommitLog和ConsumeQueue,因此建议将为此参数设置较大的值。 【agressiveness】—->【aggressiveness】

vm.swappiness,定义内核交换内存页面的积极程度。较高的值会增加攻击性,较低的值会减少交换量。建议将值设置为10来避免交换延迟。

File descriptor limits,RocketMQ需要为文件(CommitLog和ConsumeQueue)和网络连接打开文件描述符。我们建议设置文件描述符的值为655350。

Disk scheduler,RocketMQ建议使用I/O截止时间调度器,它试图为请求提供有保证的延迟[2]。

参考

  1. https://www.kernel.org/doc/Documentation/sysctl/vm.txt
  2. https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/ch06s04s02.html

更新: 2017年7月15日

lostjeffle commented 6 years ago

第六组的文档翻译

原文在一些方面的表述对于新手来说并不是非常清楚,因而我们在理解原文意思的基础上,在尊重原有文本的同时,进行适当润色。

同时原文档在一些表述上存在一些小问题,例如 Best Practice For Consumer 中的 Thread Number 原意为线程数量,我觉得改为 Number of Threads 更好。

hjy9548 commented 6 years ago

第七组评论第三组: ①RocketMQ JVM/Linux配置文章中【agressiveness】单词拼写错误,应该为【aggressiveness】 ②“我们建议将655350设置为文件描述符”翻译不准确,应该为“建议设置文件描述符的值为655350”

hjy9548 commented 6 years ago

第七组评论第三组: topic的翻译不是主题,而是队列集合

yilishan commented 6 years ago

第七组评论第三组: 第一篇文档“RocketMQ JVM / Linux”配置中的代码插入格式错误,现在是以引用的方式,应以代码形式展现,包括6处块级代码,3处行内代码

hjy9548 commented 6 years ago

第七组评论第三组 "建立新的消费者组时,需要决定是否需要消费已经存在于Broker中的历史消息。CONSUME_FROM_LAST_OFFSET将忽略历史消息,并消费之后生成的任何内容。"翻译不准确,应该为“的消费者群体被建立时,这个消费者群体是否需要消费已经存在于Broker中的历史消息,这是由ConsumeFromWhere决定的。”

xiaozongyang commented 6 years ago

@xjtushilei 第九组:

第一篇

  1. Connection Multiplex 应该是“连接复用”
  2. Name Server翻译成“名称服务”不太准备,建议不翻译
  3. 建议Broker如果不翻译全文都不翻译,统一风格

    第二篇

    客户端发送请求到 Broker,然后等待响应,如果经过最大等待时间后仍然没等到响应,客户端会抛出一个远程超时的异常RemotingTimeoutException。默认的等待时间是3秒。

建议调整下语序,把“默认的等待时间是3秒”改成“如果经过最大等待时间(默认是3秒)后仍然没等到响应”