# 最佳实践

## 项目部署结构

为了方便添加维护，推荐用以下组织结构部署

* 将rocketmq与mongo等安装源码放于  `/usr/local/xxx`文件夹下,如以下样例

```bash
$ cd /usr/local/
$ ls 
....
maven  mongodb  mysql5.7  redis  rocketmq  rocketmq-externals 
```

* 通过启动参数配置日志到 `/opt/logs/` 文件夹下

```bash
#rocketmq 启动 rocketmq位置usr/local/rocketmq/rocketmq-4.5.2下
nohup sh ./bin/mqnamesrv >  /opt/rocketmq-4.5.2/logs/namesrvrun.log 2>&1 &
# 设置broker的部署方式，和日志位置
nohup sh ./bin/mqbroker -c ./conf/2m-2s-async/broker-a.properties -n "xxxx:9876" > /opt/rocketmq-4.5.2/logs/broker-a.log 2>&1 &

```

* 设置一个公用的`connector-plugins`目录,用于所有的connector包存放，如`/usr/local/rocketmq-external/connector-plugins`&#x20;

## Borker

#### &#x20;Broker 角色

​ Broker 角色分为 ASYNC\_MASTER（异步主机）、SYNC\_MASTER（同步主机）以及SLAVE（从机）。如果对消息的可靠性要求比较严格，可以采用 SYNC\_MASTER加SLAVE的部署方式。如果对消息可靠性要求不高，可以采用ASYNC\_MASTER加SLAVE的部署方式。如果只是测试方便，则可以选择仅ASYNC\_MASTER或仅SYNC\_MASTER的部署方式。

#### 3.2 FlushDiskType

​ SYNC\_FLUSH（同步刷新）相比于ASYNC\_FLUSH（异步处理）会损失很多性能，但是也更可靠，所以需要根据实际的业务场景做好权衡。

#### 3.3 Broker 配置

| 参数名                     | 默认值                       | 说明                                                                                                                  |
| ----------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| listenPort              | 10911                     | 接受客户端连接的监听端口                                                                                                        |
| namesrvAddr             | null                      | nameServer 地址                                                                                                       |
| brokerIP1               | 网卡的 InetAddress           | 当前 broker 监听的 IP                                                                                                    |
| brokerIP2               | 跟 brokerIP1 一样            | 存在主从 broker 时，如果在 broker 主节点上配置了 brokerIP2 属性，broker 从节点会连接主节点配置的 brokerIP2 进行同步                                    |
| brokerName              | null                      | broker 的名称                                                                                                          |
| brokerClusterName       | DefaultCluster            | 本 broker 所属的 Cluser 名称                                                                                              |
| brokerId                | 0                         | broker id, 0 表示 master, 其他的正整数表示 slave                                                                              |
| storePathCommitLog      | $HOME/store/commitlog/    | 存储 commit log 的路径                                                                                                   |
| storePathConsumerQueue  | $HOME/store/consumequeue/ | 存储 consume queue 的路径                                                                                                |
| mappedFileSizeCommitLog | 1024 \* 1024 \* 1024(1G)  | commit log 的映射文件大小                                                                                                  |
| deleteWhen              | 04                        | 在每天的什么时间删除已经超过文件保留时间的 commit log                                                                                    |
| fileReservedTime        | 72                        | 以小时计算的文件保留时间                                                                                                        |
| brokerRole              | ASYNC\_MASTER             | SYNC\_MASTER/ASYNC\_MASTER/SLAVE                                                                                    |
| flushDiskType           | ASYNC\_FLUSH              | SYNC\_FLUSH/ASYNC\_FLUSH SYNC\_FLUSH 模式下的 broker 保证在收到确认生产者之前将消息刷盘。ASYNC\_FLUSH 模式下的 broker 则利用刷盘一组消息的模式，可以取得更好的性能。 |

## NameServer

​RocketMQ 中，Name Servers 被设计用来做简单的路由管理。其职责包括：

* Brokers 定期向每个名称服务器注册路由数据。
* 名称服务器为客户端，包括生产者，消费者和命令行客户端提供最新的路由信息。​

## 消息幂等性

RocketMQ无法避免消息重复（Exactly-Once），所以如果业务对消费重复非常敏感，务必要在业务层面进行去重处理。可以借助关系数据库进行去重。首先需要确定消息的唯一键，可以是msgId，也可以是消息内容中的唯一标识字段，例如订单Id等。在消费之前判断唯一键是否在关系数据库中存在。如果不存在则插入，并消费，否则跳过。（实际过程要考虑原子性问题，判断是否存在可以尝试插入，如果报主键冲突，则插入失败，直接跳过）

msgId一定是全局唯一标识符，但是实际使用中，可能会存在相同的消息有两个不同msgId的情况（消费者主动重发、因客户端重投机制导致的重复等），这种情况就需要使业务字段进行重复消费。

## 参考连接

### [最佳实践](https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rocketmq-1.gitbook.io/rocketmq-connector/kai-fa-zhe-zhong-xin/zui-jia-shi-jian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
