当前系统
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 //查看端口是否运行
访问管理平台
默认帐号及密码: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;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | <br> /// <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(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /// <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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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 >(); } |