如果客户端配置为接收消息创建临时队列,是否可以配置只允许创建一个队列? 如果有错误的客户端在服务器上创建了太多队列,它对服务器来说会是一个大问题吗?
如何配置以防止客户浪费资源?
-module(amqp_example).
-include("amqp_client.hrl").
-compile([export_all]).
test() ->
%% Start a network connection
{ok, Connection} = amqp_connection:start(#amqp_params_network{}),
%% Open a channel on the connection
{ok, Channel} = amqp_connection:open_channel(Connection),
%% Declare a queue
#'queue.declare_ok'{queue = Q}
= amqp_channel:call(Channel, #'queue.declare'{}),
ok = create_temp_queue(Channel,10),
%% Publish a message
Payload = <<"foobar">>,
Publish = #'basic.publish'{exchange = <<>>, routing_key = Q},
amqp_channel:cast(Channel, Publish, #amqp_msg{payload = Payload}),
%% Get the message back from the queue
Get = #'basic.get'{queue = Q},
{#'basic.get_ok'{delivery_tag = Tag}, _Content}
= amqp_channel:call(Channel, Get),
%% Do something with the message payload
%% (some work here)
%% Ack the message
amqp_channel:cast(Channel, #'basic.ack'{delivery_tag = Tag}),
%% Close the channel
amqp_channel:close(Channel),
%% Close the connection
amqp_connection:close(Connection),
ok.
create_temp_queue(Channel,Loop)->
[ %% Declare a queue
#'queue.declare_ok'{queue = _Q}
= amqp_channel:call(Channel, #'queue.declare'{})
||
_X <- lists:seq(1,Loop)].
(emacs@yus-iMac.local)58> amqp_example:test().
** exception error: no match of right hand side value
[{'queue.declare_ok',
<<"amq.gen-AqAaMLydgMf43y_XoYSdq5">>,0,0},
{'queue.declare_ok',
<<"amq.gen-A75g--nsvheNbwYMr34M-E">>,0,0},
{'queue.declare_ok',
<<"amq.gen-wmkOrALHBIj6Ot6ZuZZOQJ">>,0,0},
{'queue.declare_ok',
<<"amq.gen-wX2NmwMHBeDaKLvoZgJhEh">>,0,0},
{'queue.declare_ok',
<<"amq.gen-gcvScDp-RFMVwxWpyWjI-9">>,0,0},
{'queue.declare_ok',
<<"amq.gen-Q4CS7jNu3cde0RNdVdO3PJ">>,0,0},
{'queue.declare_ok',
<<"amq.gen-QKNrG8IJPVvfAlLukq38x_">>,0,0},
{'queue.declare_ok',
<<"amq.gen-wqJ2V1HQDaJjOzRDhv8gT4">>,0,0},
{'queue.declare_ok',
<<"amq.gen-AYeZiuNYsFOUMVw6xKcZh4">>,0,0},
{'queue.declare_ok',
<<"amq.gen-AJDqT2h2fq9cZOsVbNESi0">>,0,0}]
in function amqp_example:test/0 (src/amqp_example.erl, line 16)
yus-iMac:~ yuchen$ sudo rabbitmqctl list_queues
Password:
Listing queues ...
amq.gen-Q4CS7jNu3cde0RNdVdO3PJ 0
amq.gen-QKNrG8IJPVvfAlLukq38x_ 0
amq.gen-AqAaMLydgMf43y_XoYSdq5 0
amq.gen-AJDqT2h2fq9cZOsVbNESi0 0
amq.gen-wqJ2V1HQDaJjOzRDhv8gT4 0
amq.gen-AYeZiuNYsFOUMVw6xKcZh4 0
amq.gen-wzvWzxXo2MJVZsyrwfzM8A 0
amq.gen-A75g--nsvheNbwYMr34M-E 0
amq.gen-gcvScDp-RFMVwxWpyWjI-9 0
amq.gen-wX2NmwMHBeDaKLvoZgJhEh 0
amq.gen-wmkOrALHBIj6Ot6ZuZZOQJ 0
...done.
答案 0 :(得分:0)
客户端应创建一个具有特定名称的队列,并确保将其设置为autodelete。这样,客户端将不会重新创建预先存在的队列。每个客户端都会创建自己的特定队列,因为每个客户端都会相应地命名其队列。
答案 1 :(得分:0)
好的。现在我们假设你有一个Erlang Rabbitmq client
的正确设置。使用用户指南 here 。
1。通用RABBITMQ连接器
-module(rabbit_utils). -compile(export_all). -define(RABBIT_SERVER,"localhost"). -define(RABBIT_PORT,9001). -record(pipe,{connection,channel}). create_pipe()-> try amqp_connection:start(#amqp_params_network{host = ?RABBIT_SERVER, port = RABBIT_PORT}) of {ok, Connection} -> try amqp_connection:open_channel(Connection) of {ok,Channel} -> #pipe{ connection = Connection, channel = Channel }; _ -> amqp_connection:close(Connection),error catch _:_ -> amqp_connection:close(Connection),error end; _ -> error catch _:_ -> error end. close_pipe(Channel,Connection)-> try amqp_channel:close(Channel) of _ -> ok catch _:_ -> ok end, try amqp_connection:close(Connection) of _ -> ok catch _:_ -> ok end, ok.
我们会继续注意到,我会继续创建管道并关闭管道。这是因为,在erlang rabbitmq client
的最新版本中,连接和通道变量是Erlang进程。每当某些内容未按计划在此库中进行时,这些进程将在运行时死亡。出于这个原因,我在try ... catch ... end
代码块中捕获了大多数代码。如果您正在使用gen_servers
,那么,将它们设为trap_exit = true
,然后将它们链接到RabbitMQ客户端进程(连接和通道)。因此,每当连接中断时,Connection
进程就会死亡,将其捕获到gen_server中,然后尝试另一个连接,如果失败,也许你可以拥有许多RABBITMQ
个服务器{{1 }} 至。概念很深入,但让我们继续。
2。 Exchange管理器
这确保fail over
服务器上存在交换。交换必须是RABBITMQ
。我假设我们需要持久的交流和队列。持久交换和队列的一个优点是您只需创建一次,即使重新启动RABBITMQ服务,它也会使用这些交换和队列进行引导。
ensure_exchange_exists(Exchange)-> case create_pipe() of error -> error; #pipe{connection = Connection,channel = Channel} -> RandomQueue = list_to_binary(guid()), #'queue.declare_ok'{} = amqp_channel:call(Channel,#'queue.declare'{queue = RandomQueue}), Binding = #'queue.bind'{queue = RandomQueue,exchange = Exchange, routing_key = <<"testing">>}, try amqp_channel:call(Channel, Binding) of #'queue.bind_ok'{} -> Delete = #'queue.delete'{queue = RandomQueue}, #'queue.delete_ok'{} = amqp_channel:call(Channel, Delete), close_pipe(Channel,Connection), ok; _ -> close_pipe(Channel,Connection), create_exchange(Exchange,Server) catch _R:_T -> close_pipe(Channel,Connection), create_exchange(Exchange,Server) end; _ -> error end. create_exchange(Exchange)-> case create_pipe() of error -> error; #pipe{connection = Connection,channel = Channel} -> Exc = #'exchange.declare'{exchange = Exchange,durable = true}, try amqp_channel:call(Channel,Exc) of #'exchange.declare_ok'{} -> ok; _ -> close_pipe(Channel,Connection),error catch _:_ -> close_pipe(Channel,Connection),error end end. guid()-> random:seed(now()), MD5 = erlang:md5(term_to_binary([random:uniform(7677771995517),{self(),time(),node(), now(), make_ref()}])), MD5List = lists:nthtail(2, binary_to_list(MD5)), F = fun(N) -> f("~2.16.0B", [N]) end, L = [F(N) || N <- MD5List], lists:flatten(L). f(S)-> f(S,[]). f(S,Args) -> lists:flatten(io_lib:format(S, Args)).
3。队列管理器
对于大型系统,我们发现使用一个交换机(或几个交换机)更容易,但拥有与系统需要交互的队列一样多的队列。想象一下,在集群中,每个系统都有一个队列,其他系统在需要从该系统询问某些内容时发送消息。此外,当系统从另一个系统获取请求时,它会通过将答案发送到该系统的队列来回复该请求。通过良好的消息格式协议,它可以实现系统识别,区分来自回复,时间戳,系统ping,远程过程调用的请求,e.t.c最终会在群集中显示消息路由器。在最近的一个项目中,我们提出了一个远程过程协议,使用binary
作为消息格式。系统可以通过AMQP接口调用方法并将参数传递给远程系统。我不能在这里详细介绍,但只是知道,我们现在依赖它JSON
Genuis
。{
无论如何,我们首先需要确定一个队列存在,然后,如果存在,检查它是否绑定到我们的交换。我们走吧 !!
ensure_queue(Queue,Exchange)->
#pipe{connection = Connection,channel = Channel} = create_pipe(), Get = #'basic.get'{queue = Queue}, Sure = try amqp_channel:call(Channel, Get) of #'basic.get_empty'{} -> queue_exists;
{#'basic.get_ok'{}, _Content} -> queue_exists; _ -> queue_missing catch _EE:_EE2 -> queue_missing end, close_pipe(Channel,Connection), case Sure of queue_exists -> ensure_bound(Queue,Exchange); queue_missing -> create_queue_and_ensure_bound(Queue,Exchange) end.
ensure_bound(Queue,Exchange)->
#pipe{connection = Connection,channel = Channel} = create_pipe(), B1 = #'queue.bind'{queue = Queue,exchange = Exchange,routing_key = Queue}, try amqp_channel:call(Channel, B1) of #'queue.bind_ok'{} -> close_pipe(Channel,Connection), ok; _OtherErr -> error catch _ET:_EY -> error end.
create_queue_and_ensure_bound(Queue,Exchange)-> #pipe{connection = Connection,channel = Channel} = create_pipe(), TheQ = #'queue.declare'{queue = Queue,durable = true}, try amqp_channel:call(Channel,TheQ) of #'queue.declare_ok'{} -> Binding = #'queue.bind'{queue = Queue,exchange = Exchange,routing_key = Queue}, try amqp_channel:call(Channel, Binding) of #'queue.bind_ok'{} -> close_pipe(Channel,Connection), error; _Other2 -> close_pipe(Channel,Connection), error catch _ER11:_ER22 -> close_pipe(Channel,Connection), error end; _Other -> close_pipe(Channel,Connection), error catch _ER1:_ER2 -> close_pipe(Channel2,Connection2), error end.
100%
服务器,并且您在所有RABBITMQ服务器上安装了所有相同的交换和队列,这样如果一台服务器丢失,其他服务器可用于继续服务。