Netty的集群部署多channel解决方案之Rabbitmq

这里使用rabbitmq的订阅发布的广播模式(如果有其他服务可以使用Topic)
1、添加配置文件
```
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.0.3.RELEASE</version>
        </dependency>
```
```
server:
  port: 8888
  
nettyEventExchange: netty.event.exchange
nettyQueue: netty.${server.port}.message.queue

spring:
  rabbitmq:
    host: 127.0.0.1 
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    listener:
      retry:
        ####开启消费者(程序出现异常的情况下会)进行重试
        enabled: false #默认为false
        ####最大重试次数
        max-attempts: 5
        ####重试间隔次数
        initial-interval: 3000
      simple:
        acknowledge-mode: manual
      simple.concurrency: 10  #线程池大小,默认为10
      simple.max-concurrency: 100  #最大线程池大小,默认为10

```
2、添加配置文件和实体
```java
package yws.net.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EventMessage extends Throwable implements Serializable {

    /**
     * 消息队列的消息id
     */
    private String messageId;


    /**
     * 事件类型
     */
    private String eventMessageType;


    /**
     * 业务id
     */
    private String bizId;


    /**
     * 账号
     */
    private Long accountNo;


    /**
     * 消息体
     */
    private String content;

    /**
     * 备注
     */
    private String remark;

}

```
```java
package yws.net.config;

import lombok.Data;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 如果多集群部署需要使用
 * 推送消息时候使用订阅发布,对所有服务都发送,每个服务都查询自己
 * jvm里面是否有存储对应的channel,有的话推送,没有的话忽略
 * */
@Configuration
@Data
public class RabbitMQConfig {

    /**
     * 交换机
     */
    @Value("${nettyEventExchange}")
    private String nettyEventExchange;

    /**
     * 队列
     */
    @Value("${nettyQueue}")
    private String nettyQueue;

    /**
     * 创建交换机 Fanout类型
     * @return
     */
    @Bean
    public FanoutExchange nettyEventExchange(){
        //durable:开启持久化,autoDelete:不自动删除
        //return new TopicExchange(nettyEventExchange,true,false);
        return new FanoutExchange(nettyEventExchange,true,false);
    }

    /**
     * 消息转换器
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
    

    /**
     * 队列和交换机的绑定关系建立
     */
    @Bean
    public Binding nettyAddApiBinding() {
        return BindingBuilder.bind(nettyQueue()).to(nettyEventExchange());
    }

    /**
     * 普通队列,用于被监听
     */
    @Bean
    public Queue nettyQueue() {
        return new Queue(nettyQueue);
    }

}

```
3、添加监听
```java
package yws.net.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import yws.net.enums.BizCodeEnum;
import yws.net.exception.BizException;
import yws.net.model.EventMessage;
import yws.net.util.redis.RedisUtils;

import java.io.IOException;

/**
 * @author Yws
 * @since 2022/8/26 集群消息推送消费者
 */
@Component
@Slf4j
@RabbitListener(queues = "${nettyQueue}")
public class NettyMsgMqListener {

  @Autowired private RedisUtils redisUtils;

  @Value("${server.port}")
  public int port;

  @RabbitHandler
  public void nettyMsgHandler(EventMessage eventMessage, Message message, Channel channel)
      throws IOException {
      //测试多服务
    log.info("测试端口:{}",port);
    try {
        //查看对应的netty服务的本地存储里边是否有该channel,有的话推送消息、没有的话忽略

    } catch (Exception e) {
      // 处理业务异常,还有进行其他操作,比如记录失败原因
      log.error("消费失败1:" + eventMessage);
    }
     //确认消息消费成功,
     channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

  }
}

```
4、启动多个springboot项目,启动多个消费者,多集群可以添加jvm参数
```
-Dserver.port=8910 -Dnetty.port=7001
```

![1672817085032](https://logaaaaa.oss-cn-beijing.aliyuncs.com/1672817085032.jpg)
5、添加测试类
```java
package yws.net.biz;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import yws.net.MainApplication;
import yws.net.config.RabbitMQConfig;
import yws.net.model.EventMessage;

/**
 * @author Yws
 * @since 2023/1/4
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MainApplication.class)
@Slf4j
public class NettyTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Test
    public void test(){
        String nettyEventExchange = rabbitMQConfig.getNettyEventExchange();
        System.out.println(nettyEventExchange);
        //构建消息
        EventMessage eventMessage = EventMessage.builder()
                .content("test")
                .build();
        rabbitTemplate.convertAndSend(rabbitMQConfig.getNettyEventExchange(),
                "", eventMessage);
    }

}
```


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 在使用 Netty集群中,您可以使用 `ChannelGroup.find()` 方法来通过 channel ID 获取 channel 对象。首先,您需要创建一个 `ChannelGroup` 对象,然后将所有 channel 添加到该对象中。例如: ``` ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); // 添加 channelchannelGroup 中 channelGroup.add(channel1); channelGroup.add(channel2); ... // 通过 channel ID 获取 channel Channel channel = channelGroup.find(channelId); ``` 如果找不到与给定 ID 匹配的 channel,则返回 `null`。 注意:这种方法的性能可能较低,因为它需要遍历整个 channelGroup 以查找与给定 ID 匹配的 channel。如果您需要快速查找 channel,可以考虑使用其他数据结构(例如,哈希表)来存储 channel。 ### 回答2: Netty中的ChannelId是用来唯一标识一个Channel对象的。每个Channel对象都会在创建时自动创建一个唯一的ChannelId,可以通过Channel的方法`id()`来获取该ChannelChannelId。 在一个集群环境中,不同的Netty服务器上可能存在多个Channel对象,通过ChannelId可以准确地找到对应的Channel对象。为了实现这一功能,可以使用NettyChannelGroup类。ChannelGroup是一个用来管理多个Channel对象的容器,可以通过ChannelId来获取对应的Channel对象。 首先,在创建Channel时,可以将Channel对象添加到ChannelGroup中,例如: ```java ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); channelGroup.add(channel); ``` 接下来,可以通过ChannelId来查找对应的Channel对象,例如: ```java ChannelId channelId = channel.id(); Channel channel = channelGroup.find(channelId); ``` 通过以上的代码,可以通过ChannelId在集群中查找到对应的Channel对象。 需要注意的是,当Channel对象关闭时,应该将其从ChannelGroup中移除,避免无用的Channel对象占用资源: ```java channelGroup.remove(channel); ``` 通过上述方法,可以在集群环境中通过ChannelId来获取和管理Channel对象。 ### 回答3: 在Netty中,可以通过ChannelId来获取对应的Channel对象。ChannelId是一个在Channel被创建时自动生成的唯一标识符,可以用来检索和管理Channel对象。 要通过ChannelId获取Channel对象,可以使用ChannelGroup或ChannelGroupMap来实现ChannelGroup是一个用于管理多个Channel对象的集合,而ChannelGroupMap是一个能够将ChannelId与Channel对象进行映射的Map。 首先,我们可以创建一个ChannelGroup对象,用于管理所有连接到集群Channel。通过调用ChannelGroup的add方法,我们可以将每个新加入集群Channel对象添加到ChannelGroup中,以便进行管理。 接着,当需要根据ChannelId获取对应的Channel对象时,可以调用ChannelGroup的find方法,并传入要查找的ChannelId作为参数。这样,ChannelGroup会返回一个对应的Channel对象,可以通过该对象进行后续操作。 此外,在Netty中还可以使用ChannelGroupMap来实现更灵活的标识符到Channel对象的映射。ChannelGroupMap是一个将ChannelId与Channel对象一一映射的Map数据结构。通过在ChannelGroupMap中保存ChannelId和对应的Channel对象的关系,可以直接通过ChannelId获取对应的Channel对象,而无需再遍历整个ChannelGroup。 总结起来,通过ChannelId可以在Netty集群中获取对应的Channel对象。通过ChannelGroup或ChannelGroupMap等数据结构,可以方便地管理和操作各个Channel对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巧克力的骄傲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值