linux 下安装 RabbitMq 及 .net core 实操多种模式

当前系统

Debian GNU/Linux 12

安装命令

  1、sudo apt update    //更新系统
  2、sudo apt-get install rabbitmq-server    //安装rabbitMq 服务
  3、sudo service rabbitmq-server start     //启动 rabbitMq
  4、sudo systemctl enable rabbitmq-server //设置开机启动
  5、sudo rabbitmq-plugins enable rabbitmq_management    //启动管理平台 15672
  sudo service rabbitmq-server status   //查看服务状态

 

  netstat -lnpt | grep 15672  //查看端口是否运行

 

  

访问管理平台

http://服务器ip:15672/

默认帐号及密码:guest

异常:User can only log in via localhost

sudo rabbitmqctl add_user admin 123456    //创建 admin 管理员,密码 123456   

sudo rabbitmqctl set_user_tags admin administrator    //将新用户设置为管理员

sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"  //为新用户分配所有权限

注意:新版的 RabbitMq 就算设置了管理员权限,登录后台后很多权限无法操作或显示 404或405,这时必需使用 localhost:15672,如果部署在远程服务器可以使用隧道隐射后在用 localhost 访问权限才显示正常

 RabbitMq 缺点及功能特色:

RabbitMq 由于是单线程处理,故性能方面一般;但在一些特殊场景使用,主要用于队列中消息可以多个客户端同时处理,不会对同一条消息进行多次处理;

1、现有 .net 客户端没有异步操作(建议使用单例服务);

2、消息被分配到客户端后,如果未 Ack 操作,可以关闭通道、断开连接、结束客户端进程才会回滚到处理队列;

3、队列消息被客户端获取后,其它客户端获取不到同一条消息;

4、初始化通道时可选是否持久化,创建消息时可以配置是否持久化;

 几种常见模式:

RabbitMq 主要是由交换机和队列组织,简单理解就是将消息发送到交换机,由交换机将消息投送到队列中;

fanout    订阅/发布模式,指定一些队列绑定到交换机,消息发送到交换机后,会自动投递到绑该交换机的队列中; 

topic      主题模式:两种特殊字符“*”与“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词。(可以给队列添加多个 routingKey ,添加后必需要绑定交换机),消息发布相对比较慢

direct     简单方式,队列模式就是这种方式,在发布的时候需要指定 队列名,交换机名可以为空;

headers      根据发送的消息内容中的 headers 属性进行匹配,一般用的很少;

 

C# RabbitMq 常用单例服务代码

using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;


/// <summary> /// 表示amqp客户端 /// </summary> public class RabbitClient : IDisposable { private readonly IOptionsMonitor<RabbitOptions> options; private readonly ConnectionFactory factory; private readonly object syncRoot = new object(); private IConnection? _connection; //持久化消息,需要跟持久化队列共同使用 private IBasicProperties? properties = null; private IModel? _channel; /// <summary> /// 获取Channel /// </summary> private IModel Channel { get { lock (this.syncRoot) { if (this._connection == null) { this._connection = this.factory.CreateConnection(); } if (this._channel == null) { this._channel = this._connection.CreateModel(); if (properties == null) { properties = this._channel.CreateBasicProperties(); properties.Persistent = this.options.CurrentValue.IsDurable; //持久化消息 } //创建默认队列 this._channel.QueueDeclare(this.options.CurrentValue.Queue, // 队列名称 durable: this.options.CurrentValue.IsDurable, //持久化队列 exclusive: false, //是否私有化,false表示所有消费者都可以访问,true表示只有第一次拥有它的消费者才能访问 autoDelete: false, //是否自动删除,true表示不再使用队列时自动删除队列 arguments: null); //其他额外参数 //创建配置交换机及队列 this._channel.ExchangeDeclare( this.options.CurrentValue.ExchangeOptions.Name, //交换机名称 ExchangeType.Fanout, //交换机类型 Fanout:广播模式, this.options.CurrentValue.IsDurable ); //创建主题交换机 this._channel.ExchangeDeclare( this.options.CurrentValue.TopicName, //交换机名称 ExchangeType.Topic, //交换机类型 Fanout:主题模式, this.options.CurrentValue.IsDurable ); //交换机机下创建队列 foreach (var item in this.options.CurrentValue.ExchangeOptions.Queues) { //创建队列 this._channel.QueueDeclare(item, // 队列名称 durable: this.options.CurrentValue.IsDurable, //持久化队列 exclusive: false, //是否私有化,false表示所有消费者都可以访问,true表示只有第一次拥有它的消费者才能访问 autoDelete: false, //是否自动删除,true表示不再使用队列时自动删除队列 arguments: null); //其他额外参数 //绑定队列到交换机 this._channel.QueueBind( item, //队列名称 this.options.CurrentValue.ExchangeOptions.Name, //交换机名称 "" ); //给队列添加routingKey,并绑定 topic交换机 this._channel.QueueBind( item, //队列名称 this.options.CurrentValue.TopicName, //交换机名称 $"#.{item}.#" //路由关键字,发布订阅模式写""即可 ); } } return this._channel; } } } /// <summary> /// amqp客户端 /// </summary> /// <param name="optionsMonitor"></param> public RabbitClient(IOptionsMonitor<RabbitOptions> optionsMonitor) { this.options = optionsMonitor; this.factory = new ConnectionFactory { UserName = options.CurrentValue.UserName, Password = options.CurrentValue.Password, HostName = options.CurrentValue.HostName, Port = options.CurrentValue.Port, AutomaticRecoveryEnabled = true }; } /// <summary> /// 简单模式发布消息 /// </summary> /// <param name="msg">消息内容</param> public void SimplePublish(string msg) { var message = Encoding.UTF8.GetBytes(msg); this.Channel.BasicPublish( "", //交换机名,""表示默认交换机direct this.options.CurrentValue.Queue, //路由键,简单模式就是队列名 properties, //其他额外参数 message //要传递的消息字节数组 ); } /// <summary> /// 交换机模式发布消息 /// </summary> /// <param name="msg">消息内容</param> public void ExchangePublish(string msg) { var message = Encoding.UTF8.GetBytes(msg); //持久化消息,需要跟持久化队列共同使用 this.Channel.BasicPublish( options.CurrentValue.ExchangeOptions.Name, //交换机名,""表示默认交换机direct "", //路由键,简单模式就是队列名 properties, //其他额外参数 message //要传递的消息字节数组 ); } /// <summary> /// 主题模式发布消息 /// </summary> /// <param name="msg"></param> /// <param name="topic"></param> public void TopicPublish(string msg, string? topic = null) { var message = Encoding.UTF8.GetBytes(msg); var routingKey = string.IsNullOrEmpty(topic) ? "anonymous.info" : topic; this.Channel.BasicPublish( this.options.CurrentValue.TopicName, //交换机名,""表示默认交换机direct routingKey, //路由键 properties, //其他额外参数 message //要传递的消息字节数组 ); } /// <summary> /// 提取交换机消息 /// </summary> /// <param name="queue">交换机中的队列名称</param> /// <param name="autoAck"></param> /// <returns></returns> public RabbitMessage? GetExchange(string queue, bool autoAck = false) { var result = this.Channel.BasicGet(queue, autoAck); return result == null ? null : new RabbitMessage(result.DeliveryTag, result.Body); } /// <summary> /// 提取消息 /// </summary> /// <param name="autoAck">是否同时从服务器中删除消息</param> /// <returns></returns> public RabbitMessage? Get(bool autoAck = false) { var result = this.Channel.BasicGet(this.options.CurrentValue.Queue, autoAck); return result == null ? null : new RabbitMessage(result.DeliveryTag, result.Body); } /// <summary> /// 监听简单队列 /// </summary> /// <param name="callback"></param> /// <param name="autoAck"></param> public void SimpleConsume(string queue, Action<RabbitMessage> callback, bool autoAck = false) { var consumer = new EventingBasicConsumer(this.Channel); this.Channel.BasicConsume(queue, autoAck, consumer); consumer.Received += (model, ea) => { var msg = new RabbitMessage(ea.DeliveryTag, ea.Body); callback(msg); }; } /// <summary> /// 确认并删除消息 /// </summary> /// <param name="tag">消息标记</param> public void Ack(ulong tag) { this.Channel.BasicAck(tag, false); } /// <summary> /// 释放资源 /// </summary> public void Dispose() { if (this._channel != null) { this._channel.Dispose(); } if (this._connection != null) { this._connection.Dispose(); } }

 

/// <summary>
/// 表示amqp消息
/// </summary>
public class RabbitMessage
{
    /// <summary>
    /// 标记
    /// </summary>
    public ulong Tag { get; }

    /// <summary>
    /// 内容
    /// </summary>
    public byte[] Body { get; }

    /// <summary>
    /// amqp消息
    /// </summary>
    /// <param name="tag"></param>
    /// <param name="body"></param>
    public RabbitMessage(ulong tag, ReadOnlyMemory<byte> body)
    {
        this.Tag = tag;
        this.Body = body.ToArray();
    }

    /// <summary>
    /// 转换为字符串
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return System.Text.Encoding.UTF8.GetString(this.Body);
    }
}

  

public class RabbitOptions
{
    /// <summary>
    /// 用户名
    /// </summary>
    public string UserName { get; set; } = string.Empty;

    /// <summary>
    /// 密码
    /// </summary>
    public string Password { get; set; } = string.Empty;

    /// <summary>
    /// 域名
    /// </summary>
    public string HostName { get; set; } = string.Empty;

    /// <summary>
    /// 端口
    /// </summary>
    public int Port { get; set; } = 5672;

    /// <summary>
    ///  队列名称
    /// </summary>
    public string Queue { get; set; } = string.Empty;

    /// <summary>
    /// 交换机信息
    /// </summary>
    public ExchangeOptions ExchangeOptions { get; set; } = new ExchangeOptions();

    /// <summary>
    /// 是否持久化
    /// </summary>
    public bool IsDurable { get; set; } = false;

    /// <summary>
    /// 主题模式名称
    /// </summary>
    public string TopicName { get; set; } = "topic_test";
}

/// <summary>
/// 交换机信息
/// </summary>
public class ExchangeOptions
{
    /// <summary>
    /// 交换机名称
    /// </summary>
    public string? Name { get; set; }

    /// <summary>
    /// 队列集合
    /// </summary>
    public string[] Queues { get; set; } = Array.Empty<string>();
}

  

 

posted @ 2024-09-20 11:45  皓月青峰  阅读(6)  评论(0编辑  收藏  举报