rocketMq-5.2.0双主双从搭建

news2024/9/29 18:48:20

最近在研究rocketmq5.x的运行机制,研究到高可用章节,看到rocketMq采用了主从机制实现高可用,将broker分成了master和slave。为了更好的理解主从源码,我觉着需要先搭建一个主从的集群,先了解主从集群是怎么使用的。
这篇文章,写完之后,我校了好几遍稿,也按照这个文档重新搭建了一遍,所以如果你的rocketmq相关目录和我是一致的,跟着文档搭建,最多1个小时内就能搞定,因为只需要你改动一下相关配置文件中的ip就行。

文章目录

  • 1、5.x架构图
  • 2、准备服务器
  • 3、服务器安全组配置
  • 4、下载rocketmq-5.2.0
  • 5、配置环境变量
  • 6、配置hosts
  • 7、主从配置文件修改
    • 7.1、配置文件说明
    • 7.2、手动创建目录
    • 7.3、master1配置
    • 7.4、slave2配置文件
    • 7.5、master2配置文件
    • 7.6、slave1配置文件
  • 8、proxy配置文件
    • 8.1、47.xxx.xxx.xxx配置
    • 8.2、39.xxx.xxx.xxx配置
  • 9、JVM参数修改
  • 10、启动脚本
    • 10.1、47.xxx.xxx.xxx启动脚本
    • 10.2、39.xxx.xxx.xxx启动脚本
  • 11、集群验证
  • 12、发送消息、消费消息验证
    • 12.1、创建topic
    • 12.2、rocketmq5.x的maven依赖
    • 12.3、生产者
    • 12.4、消费者
  • 13、dashboard监控
    • 13.1、下载dashboard
    • 13.2、修改dashboard配置
    • 13.3、启动dashboard

1、5.x架构图

这是我在网上找到的一张5.x的架构图,整体上先了解一下5.x的架构。
注意这张图是一主两从,不是我们要搭建的双主双从。
解释一下这张图。
5.x和4.x最大的不同就是5.x引入了一个proxy组件,引入这个组件的目的就是为了存算分离,更好的拥抱云原生
客户端不再连接namesrv,而是和proxy连接,proxy和namesrv交互获取broker的路由信息,和broker交互
在这里插入图片描述

2、准备服务器

我一共准备了两台阿里云的服务器。
一台机器的ip是47开头的,47.xxx.xxx.xxx
一台机器的ip是39开头的,39.xxx.xxx.xxx
两台服务器扮演的角色如下:

机器角色
47.xxx.xxx.xxxmaster1,slave2,namesrv1,proxy1
39.xxx.xxx.xxxmaster2,slave1,namesrv2,proxy2

master1,slave2,意思是master1节点和master2的slave节点部署在一起机器上,这是为了保证高可用,主从节点不能部署到一台机器上。

3、服务器安全组配置

服务器安全组,就是开通rocketmq相关的访问端口
需要开通的端口及作用如下

端口作用
9876namesrv端口
11011主从同步端口
10911broker监听的端口
10909、11009rocketmq-dashboard连接的端口
28081grpcRemote协议端口,客户端通过该端口连接proxy

两台机器都要开通上述端口

4、下载rocketmq-5.2.0

直接到官网下载就行了,官网下载地址
下载到本地后,把目录改短一点,我文章中改成了rocketmq-5.2.0

5、配置环境变量

两台机器的配置是一样的。
rocketmq的安装路径,建议和我的路径一致。要不然要改好多地方

ROCKETMQ_HOME=/opt/application/rocketmq-5.2.0
PATH=$PATH:$ROCKETMQ_HOME/bin

6、配置hosts

两台机器的配置是一样的
改动点:把xxx.xxx.xxx的地方换成你的ip

# namesrv域名地址
47.xxx.xxx.xxx rocketmq-nameserver1
39.xxx.xxx.xxx rocketmq-nameserver2

# broker域名配置
47.xxx.xxx.xxx rocketmq-master1
47.xxx.xxx.xxx rocketmq-slave2
39.xxx.xxx.xxx rocketmq-master2
39.xxx.xxx.xxx rocketmq-slave1

7、主从配置文件修改

7.1、配置文件说明

rocketmq主从配置分为同步模式和异步模式,我们这次搭建的是同步模式。
配置文件的路径是rocketmq-5.2.0/conf/2m-2s-sync,这些配置文件是官方给准备好的。
这个目录下一共有4个配置文件。

#master1从机配置
broker-a-s.properties
#master1配置
broker-a.properties
#master2从机配置
broker-b-s.properties
#master2配置
broker-b.properties

这里顺便提一下,如果你电脑用的是sublime编辑器,我推荐你装一个sftp的插件,然后连接上2台服务器,这样修改配置文件要方便很多。

7.2、手动创建目录

主从配置的存储目录需要我们手动创建,创建命令如下

mkdir -p /usr/local/rocketmq/store
mkdir -p /usr/local/rocketmq/store/commitlog
mkdir -p /usr/local/rocketmq/store/consumequeue
mkdir -p /usr/local/rocketmq/store/index
 
mkdir -p /usr/local/rocketmq/store_s
mkdir -p /usr/local/rocketmq/store_s/commitlog
mkdir -p /usr/local/rocketmq/store_s/consumequeue
mkdir -p /usr/local/rocketmq/store_s/index

两台机器都要执行

7.3、master1配置

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

# 所属集群名字
brokerClusterName=rocketmq-cluster
# broker名字,注意此处不同的配置文件填写的不一样,brokerName相同的机器为一对主从
brokerName=broker-a
# 0 表示 Master,>0 表示 Slave
brokerId=0
#所在机器的ip地址
brokerIP1=47.xxx.xxx.xxx
# nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
# 是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
# Broker 对外服务的监听端口
listenPort=10911
# 删除文件时间点,默认凌晨 4点
deleteWhen=04
# 文件保留时间,默认 48 小时
fileReservedTime=120
# commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
# 存储路径
storePathRootDir=/usr/local/rocketmq/store
# commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
# 消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
# 消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
# checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
# abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
# 限制的消息大小
maxMessageSize=65536
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SYNC_MASTER
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

7.4、slave2配置文件

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

# 配置信息如下:
# 所属集群名字
brokerClusterName=rocketmq-cluster
# broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
# 0 表示 Master,>0 表示 Slave
brokerId=1
#所在机器的ip地址
brokerIP1=47.xxx.xxx.xxx
# nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
# 是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
# Broker 对外服务的监听端口
listenPort=11011
# 删除文件时间点,默认凌晨 4点
deleteWhen=04
# 文件保留时间,默认 48 小时
fileReservedTime=120
# commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
# 存储路径
storePathRootDir=/usr/local/rocketmq/store_s
# commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store_s/commitlog
# 消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store_s/consumequeue
# 消息索引存储路径
storePathIndex=/usr/local/rocketmq/store_s/index
# checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store_s/checkpoint
# abort 文件存储路径
abortFile=/usr/local/rocketmq/store_s/abort
# 限制的消息大小
maxMessageSize=65536
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SLAVE
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

7.5、master2配置文件

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

# 所属集群名字
brokerClusterName=rocketmq-cluster
# broker名字,注意此处不同的配置文件填写的不一样,brokerName相同的机器为一对主从
brokerName=broker-b
# 0 表示 Master,>0 表示 Slave
brokerId=0
#所在机器的ip地址
brokerIP1=39.xxx.xxx.xxx
# nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
# 是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
# Broker 对外服务的监听端口
listenPort=10911
# 删除文件时间点,默认凌晨 4点
deleteWhen=04
# 文件保留时间,默认 48 小时
fileReservedTime=120
# commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
# 存储路径
storePathRootDir=/usr/local/rocketmq/store
# commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store/commitlog
# 消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
# 消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/index
# checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
# abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
# 限制的消息大小
maxMessageSize=65536
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SYNC_MASTER
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

7.6、slave1配置文件

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

# 配置信息如下:
# 所属集群名字
brokerClusterName=rocketmq-cluster
# broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
# 0 表示 Master,>0 表示 Slave
brokerId=1
#所在机器的ip地址
brokerIP1=39.xxx.xxx.xxx
# nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
# 是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
# Broker 对外服务的监听端口
listenPort=11011
# 删除文件时间点,默认凌晨 4点
deleteWhen=04
# 文件保留时间,默认 48 小时
fileReservedTime=120
# commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
# 存储路径
storePathRootDir=/usr/local/rocketmq/store_s
# commitLog 存储路径
storePathCommitLog=/usr/local/rocketmq/store_s/commitlog
# 消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store_s/consumequeue
# 消息索引存储路径
storePathIndex=/usr/local/rocketmq/store_s/index
# checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store_s/checkpoint
# abort 文件存储路径
abortFile=/usr/local/rocketmq/store_s/abort
# 限制的消息大小
maxMessageSize=65536
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SLAVE
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

8、proxy配置文件

rocketmq-5.2.0多了proxy配置文件。配置文件路径
rocketmq-5.2.0/conf/rmq-proxy.json

8.1、47.xxx.xxx.xxx配置

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

{
  "rocketMQClusterName": "rocketmq-cluster",
  "namesrvAddr":"rocketmq-nameserver1:9876;rocketmq-nameserver2:9876",
  "brokerIP1":"47.xxx.xxx.xxx",
  "remotingListenPort":28080,
  "grpcServerPort":28081
}

28081是grpc协议端口,就是proxy的端口,客户端要连接这个端口,发送消息或者消费消息

8.2、39.xxx.xxx.xxx配置

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

{
  "rocketMQClusterName": "rocketmq-cluster",
  "namesrvAddr":"rocketmq-nameserver1:9876;rocketmq-nameserver2:9876",
  "brokerIP1":"39.xxx.xxx.xxx",
  "remotingListenPort":28080,
  "grpcServerPort":28081
}

9、JVM参数修改

JVM参数修改是改rocketmq的启动脚本。配置文件在rocketmq-5.2.0/bin目录下,一共需要修改2个配置文件
runbroker.sh、runserver.sh
默认情况下,broker的jvm堆大小是8g。
在这里插入图片描述

我买的机器,内存只有2g,所以要改小一点,否则mq的相关组件根本起不来。
经过验证,测试使用,128m就足够了。

-server -Xms128m -Xmx128m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m

10、启动脚本

因为要启动的角色有点多,所以写一个shell脚本,一键启动所有角色
脚本中引用的log文件需要自己手动创建。两台机器都要创建
创建log文件的命令

mkdir /opt/application/rocketmq-5.2.0/logs/
touch /opt/application/rocketmq-5.2.0/logs/mqnamesrv.log
touch /opt/application/rocketmq-5.2.0/logs/mqbroker.log
touch /opt/application/rocketmq-5.2.0/logs/mqbroker-s.log
touch /opt/application/rocketmq-5.2.0/logs/mqproxy.log

如果你的目录路径和我的不一样,自己改下

10.1、47.xxx.xxx.xxx启动脚本

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

#!/bin/bash
ROCKETMQ_DIR=/opt/application/rocketmq-5.2.0
CONFIG_DIR=$ROCKETMQ_DIR/conf/2m-2s-sync
NAMESRV_ADDRESSES="47.xxx.xxx.xxx:9876;39.xxx.xxx.xxx:9876"
 
nohup sh $ROCKETMQ_DIR/bin/mqnamesrv > "/opt/application/rocketmq-5.2.0/logs/mqnamesrv.log" 2>&1 &
sleep 5
nohup sh $ROCKETMQ_DIR/bin/mqbroker  -c $CONFIG_DIR/broker-a.properties > "/opt/application/rocketmq-5.2.0/logs/mqbroker.log" 2>&1 &
sleep 5
nohup sh $ROCKETMQ_DIR/bin/mqbroker  -c $CONFIG_DIR/broker-b-s.properties > "/opt/application/rocketmq-5.2.0/logs/mqbroker-s.log" 2>&1 &
sleep 5
nohup sh "${ROCKETMQ_DIR}/bin/mqproxy" -n "${NAMESRV_ADDRESSES}" -pc "${ROCKETMQ_DIR}/conf/rmq-proxy.json" > "${ROCKETMQ_DIR}/logs/mqproxy.log" 2>&1 &

10.2、39.xxx.xxx.xxx启动脚本

改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

#!/bin/bash
ROCKETMQ_DIR=/opt/application/rocketmq-5.2.0
CONFIG_DIR=$ROCKETMQ_DIR/conf/2m-2s-sync
NAMESRV_ADDRESSES="47.xxx.xxx.xxx:9876;39.xxx.xxx.xxx:9876"
 
nohup sh $ROCKETMQ_DIR/bin/mqnamesrv > "/opt/application/rocketmq-5.2.0/logs/mqnamesrv.log" 2>&1 &
sleep 5
nohup sh $ROCKETMQ_DIR/bin/mqbroker  -c $CONFIG_DIR/broker-b.properties > "/opt/application/rocketmq-5.2.0/logs/mqbroker.log" 2>&1 &
sleep 5
nohup sh $ROCKETMQ_DIR/bin/mqbroker  -c $CONFIG_DIR/broker-a-s.properties > "/opt/application/rocketmq-5.2.0/logs/mqbroker-s.log" 2>&1 &
sleep 5
nohup sh "${ROCKETMQ_DIR}/bin/mqproxy" -n "${NAMESRV_ADDRESSES}" -pc "${ROCKETMQ_DIR}/conf/rmq-proxy.json" > "${ROCKETMQ_DIR}/logs/mqproxy.log" 2>&1 &

11、集群验证

2台机器,各要启动4个进程,如下

#broker
1425 BrokerStartup
#broker
1595 BrokerStartup
#proxy
1747 ProxyStartup
#namesrv
1359 NamesrvStartup

如果启动起来的进程少了,可以查看相关日志查看启动失败的原因,日志路径如下:

#namesrv日志
rocketmq-5.2.0/logs/mqnamesrv.log
#master日志
rocketmq-5.2.0/logs/mqbroker.log
#slave日志
rocketmq-5.2.0/logs/mqbroker-s.log
#proxy日志
rocketmq-5.2.0/logs/mqproxy.log

12、发送消息、消费消息验证

使用5.2.0的新版本客户端连接一下集群

12.1、创建topic

在此之前,先创建好topic,5.x不会自动创建,不提前创建会报错:
No topic route info in name server for the topic: NormalTopic
我这里创建的topic名称是:NormalTopic
改动点:把xxx.xxx.xxx的地方换成你的ip,其他不用改动

sh bin/mqadmin updatetopic -n "47.xxx.xxx.xxx:9876;39.xxx.xxx.xxx:9876" -t NormalTopic -c rocketmq-cluster

12.2、rocketmq5.x的maven依赖

<dependency>
      <groupId>org.apache.rocketmq</groupId>
      <artifactId>rocketmq-client-java</artifactId>
      <version>5.0.5</version>
    </dependency>

12.3、生产者

改动点:如果你的topic名称也是NormalTopic,那只需要把xxx.xxx.xxx的地方换成你的ip,其他不用改动

public static void main(String[] args) {
        // 接入点地址,需要设置成 Proxy 的地址和端口列表
        String endpoint = "47.xxx.xxx.xxx:28081";
        // 消息发送的目标Topic名称,需要提前创建。
        String topic = "NormalTopic";
        ClientServiceProvider provider = ClientServiceProvider.loadService();
        ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(endpoint);
        ClientConfiguration configuration = builder.build();

        // 初始化Producer时需要设置通信配置以及预绑定的Topic
        Producer producer = null;
        try {
            producer = provider.newProducerBuilder()
                    .setTopics(topic)
                    .setClientConfiguration(configuration)
                    .build();
        } catch (ClientException e) {
            log.error("构建producer发生异常",e);
        }

        // 普通消息发送
        Message message = provider.newMessageBuilder()
                .setTopic(topic)
                // 设置消息索引键,可根据关键字精确查找某条消息
                .setKeys("messageKey")
                // 设置消息Tag,用于消费端根据指定Tag过滤消息
                .setTag("messageTag")
                // 消息内容实体(byte[])
                .setBody("hello rocketMQ".getBytes())
                .build();
        try {
            // 发送消息,需要关注发送结果,并捕获失败等异常。
            SendReceipt sendReceipt = producer.send(message);
            log.info("send message successfully, messageId={}", sendReceipt.getMessageId());
        } catch (ClientException e) {
            log.error("failed to send message", e);
        }
        // 关闭
        try {
            producer.close();
        } catch (IOException e) {
            log.error("关闭producer,发生IO异常",e);
        }
    }

12.4、消费者

改动点:如果你的topic名称也是NormalTopic,那只需要把xxx.xxx.xxx的地方换成你的ip,其他不用改动

public void pushConsumerTest() throws Exception {
        ClientServiceProvider provider = ClientServiceProvider.loadService();
        // 接入点地址,需要设置成Proxy的地址和端口列表
        String endpoint = "47.xxx.xxx.xxx:28081";
        ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
                .setEndpoints(endpoint)
                .build();
        // 订阅消息的过滤规则,表示订阅所有Tag的消息
        String tag = "*";
        FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
        // 为消费者指定所属的消费者分组,Group需要提前创建
        String consumerGroup = "TestGroup";

        // 指定需要订阅哪个目标Topic,Topic需要提前创建
        String topic = "NormalTopic";
        // 初始化 PushConsumer,需要绑定消费者分组ConsumerGroup、通信参数以及订阅关系
        PushConsumer pushConsumer = provider.newPushConsumerBuilder()
                .setClientConfiguration(clientConfiguration)
                // 设置消费者分组
                .setConsumerGroup(consumerGroup)
                // 设置预绑定的订阅关系
                .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
                // 设置消费监听器
                .setMessageListener(messageView -> {
                    // 处理消息并返回消费结果
                    log.info("consume message successfully, messageId={}", messageView.getMessageId());
                    // 消息内容处理
                    ByteBuffer body = messageView.getBody();
                    String message = StandardCharsets.UTF_8.decode(body).toString();
                    body.flip();
                    log.info("message body={}", message);
                    return ConsumeResult.SUCCESS;
                }).build();
        Thread.sleep(Long.MAX_VALUE);
        // 如果不需要再使用 PushConsumer,可关闭该实例。
        pushConsumer.close();
    }

13、dashboard监控

13.1、下载dashboard

从github下载一个dashboard。下载地址

13.2、修改dashboard配置

修改一下namesrv的地址就行了

#连接一台namesrv就好
rocketmq:
	config:
		namesrvAddrs: 39.xxx.xxx.xxx:9876

13.3、启动dashboard

启动后,如果集群搭建的没有问题,可以看到集群的节点,2主2从
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1980038.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【practise】只出现一次的数字

现在给你一个数组&#xff0c;里面放了一些数字&#xff0c;里面都是两两成对&#xff0c;只有一个数字是单独的&#xff0c;要求找出其中只出现一次的数字。相必这道题是非常简单了&#xff0c;有很多解法比如说用暴力求解&#xff1f;比如说用位运算&#xff1f;甚至说用哈希…

使用Docker+ollama部署大模型

Docker的安装----在 Ubuntu 系统上安装 Docker 一&#xff1a;配置系统的 APT 软件包管理器 首先添加 Docker 的官方 GPG 密钥 # Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/ke…

使用 宝塔面板 部署 php网站

【语料库网站】宝塔面板 在线部署全过程 代码仓库&#xff1a;https://github.com/talmudmaster/RedCorpus 网站介绍 语料库提供双语文本检索和分享功能。供英语、翻译相关专业的爱好者&#xff0c;学生和老师学习使用。 该网站是对BiCorpus开源项目的二次开发。 技术栈&am…

DA14695 printf没办法打印浮点数

是因为没有打开浮点数库&#xff0c;添加了这个库也会导致堆内存的增加

基于Kahn算法|动态线程池,支持扩展点并发执行|召回|过滤

背景 在《分布式领域扩展点设计稿》一文中&#xff0c;我们提到针对业务横向扩展点和纵向扩展点的编排能力。 那有这样的一种场景&#xff1a;针对于一次会话&#xff0c;同时会调很多外部服务&#xff0c;同时这些RPC服务会有多种直接或间接的关系&#xff0c;是否有更高效的…

【Spring】Bean详细解析

1.Spring Bean的生命周期 整体上可以简单分为四步&#xff1a;实例化 —> 属性赋值 —> 初始化 —> 销毁。初始化这一步涉及到的步骤比较多&#xff0c;包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始…

【Vue3】组件通信之$refs

【Vue3】组件通信之$refs 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日…

操作系统|day4.Linux、Linux内核、Linux负载、Linux文件存储

文章目录 LinuxLinux内核定义功能态 Linux负载定义 Linux文件存储链接分类区别使用场景 拷贝 Linux Linux内核 定义 内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;它负责管理系统的进程、内存、设备驱动程序、文件和网络系统&#xff0c;决定着系统的性能…

【大模型系列】LanguageBind(ICLR2024.01)

Paper&#xff1a;https://arxiv.org/abs/2310.01852Github&#xff1a;https://github.com/PKU-YuanGroup/LanguageBindHuggingface&#xff1a;https://huggingface.co/spaces/LanguageBind/LanguageBindAuthor&#xff1a;Bin Zhu et al. 北大袁粒团队 文章目录 1 LanguageB…

临床试验的五大意义是什么?

临床试验是临床数据科学和现代医学研究中至关重要的环节&#xff0c;它通过严格的科学方法验证新药、新疗法以及医疗器械的安全性和有效性。临床试验不仅推动了医学科学的进步&#xff0c;也为患者提供了新的治疗选择&#xff0c;提升了公共卫生水平&#xff0c;具有重大的意义…

牛客JS题(二十二)数组过滤

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; 合理封装范围判断函数 题干&#xff1a; 我的答案 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /></head><body><select name"&q…

【C语言】C语言期末突击/考研--详解一维数组与字符数组

目录 ​一、一维数组 1.数组的定义 2.一维数组在内存中的存储 二、数组访问越界与数组的传递 1.数组的访问越界 2.数组的传递 三、字符数组与scanf读取字符串 1.字符数组的初始化及传递 2.scanf读取字符串 四、gets函数与puts函数&#xff0c;str系列字符串操作函数 …

「iOS」自定义Modal转场——抽屉视图的实现

「iOS」自定义Modal转场——抽屉视图的实现 文章目录 「iOS」自定义Modal转场——抽屉视图的实现前言错误尝试自定义Modal转场实现流程自定义动画类UIPresentationController 成果展示参考文章 前言 在仿写网易云的过程之中&#xff0c;看到学长之前仿写时实现的抽屉视图&…

Java面试题-集合类

目录 1、请简单介绍下 Java 的集合类吧。 Collection Set TreeSet和HashSet List ArrayList 和 LinkedList 数组和链表的区别 Java 的列表有哪些实现类&#xff1f; Vector Queue Map 能说下 HashMap 的实现原理吗&#xff1f; 能说下 HashMap 的扩容机制吗&#x…

达梦数据库的系统视图v$cachepln

达梦数据库的系统视图v$cachepln 达梦数据库的系统视图V$CACHEPLN的主要作用是提供缓存中SQL执行计划的信息&#xff0c;在 ini 参数 USE_PLN_POOL !0 时才统计。通过查询这个视图&#xff0c;用户可以获取到缓存中的执行计划及其相关信息&#xff0c;如SQL语句文本等。这有助…

JavaScript青少年简明教程:DOM和CSS简介

JavaScript青少年简明教程&#xff1a;DOM和CSS简介 DOM简介 DOM&#xff08;Document Object Model&#xff09;将文档表示为一个树形结构&#xff0c;其中每个节点都是一个对象&#xff0c;每个对象都有其自身的属性和方法。 通过对DOM的操作&#xff0c;开发者可以使用编…

Mojo 不安全指针 详解

该UnsafePointer类型创建对内存中某个位置的间接引用。您可以使用UnsafePointer来动态分配和释放内存,或指向由其他代码分配的内存。您可以使用这些指针编写与低级接口交互的代码,与其他编程语言交互,或构建某些类型的数据结构。但顾名思义,它们本质上是不安全的。例如,当…

各地级市能源消费总量、夜间灯光值数据(2000-2022年)

全国各地级市能源消费总量、夜间灯光值数据&#xff08;2000-2022年&#xff09; 数据年限&#xff1a;2000-2022年 数据格式&#xff1a;excel 数据内容&#xff1a;337个地级市能源消费总量、夜间灯光值数据&#xff0c;包括城市、省份、年份、夜间灯光值&#xff08;总和&am…

子比主题允梦美化插件全开源版本

在其他论坛看到的一款不错的子比美化插件&#xff0c;功能也比较全面&#xff0c;因为插件作者上学没有时间维护&#xff0c;现在开源给大家&#xff0c;插件本站未做测试&#xff0c;需要的朋友自行下载测试&#xff0c;如果有授权的话可以到允梦作者网站进行咨询。需要其他美…

Java高级面试题(二)-- JVM

Jvm虚拟机&#xff0c;运行在操作系统之上&#xff0c;编译执行java代码 1, 面试官&#xff1a;手绘一个类加载过程 补充&#xff1a; 这里的执行硬件 java 调用 c 指令 创建线程 &#xff0c;new thread()->start() 底层代码就是 native start0&#xff08;&#xff09;&…