rabbitmq之back queue草稿

主备队列进程一个是amqqueue_process进程一个是rabbit_amqqueue_mirror_slave进程。

通知队列进程用backing_queue去实现这个工作。

run_backing_queue(QPid, Mod, Fun) ->

gen_server2:cast(QPid, {run_backing_queue, Mod, Fun}).


 

rabbit_mirror_queue_master.erl

%%此处AsyncCallbackrun_backing_queue,实际意思为commit_by_backing_queue

init(Q, Recover, AsyncCallback) ->

{ok, BQ} = application:get_env(backing_queue_module),

%%rabbit_variable_queue

BQS = BQ:init(Q, Recover, AsyncCallback),

State = #state{gm = GM} = init_with_existing_bq(Q, BQ, BQS),

ok = gm:broadcast(GM, {depth, BQ:depth(BQS)}),

State.


rabbit_variable_queue.erl

%%起动持久化的进程,消息/索引

init(Queue, Recover, Callback) ->

init(

Queue, Recover, Callback,

fun (MsgIds, ActionTaken) ->

msgs_written_to_disk(Callback, MsgIds, ActionTaken)

end,

fun (MsgIds) -> msg_indices_written_to_disk(Callback, MsgIds) end,

fun (MsgIds) -> msgs_and_indices_written_to_disk(Callback, MsgIds) end).



%%当创建的时候会走此流程

init(#amqqueue { name = QueueName, durable = IsDurable }, new,

AsyncCallback, MsgOnDiskFun, MsgIdxOnDiskFun, MsgAndIdxOnDiskFun) →

%%初始化队列索引状态(目录文件 ),并未产生新的进程

%%何时触发的这个动作,还需要考究下.

IndexState = rabbit_queue_index:init(QueueName,

MsgIdxOnDiskFun, MsgAndIdxOnDiskFun),

init(IsDurable, IndexState, 0, 0, [],

case IsDurable of

true -> msg_store_client_init(?PERSISTENT_MSG_STORE,

MsgOnDiskFun, AsyncCallback);

false -> undefined

end,

%%消息转储的进程

msg_store_client_init(?TRANSIENT_MSG_STORE, undefined, AsyncCallback));


首先看索引相关

rabbit_queue_index.erl

队列索引是用来


重点看下这个函数

-define(TRANSIENT_MSG_STORE, msg_store_transient).

msg_store_client_init(?TRANSIENT_MSG_STORE, undefined, AsyncCallback));


msg_store_client_init(MsgStore, MsgOnDiskFun, Callback) ->

msg_store_client_init(MsgStore, rabbit_guid:gen(), MsgOnDiskFun,

Callback).


msg_store_client_init(MsgStore, Ref, MsgOnDiskFun, Callback) ->

CloseFDsFun = msg_store_close_fds_fun(MsgStore =:= ?PERSISTENT_MSG_STORE),

rabbit_msg_store:client_init(MsgStore, Ref, MsgOnDiskFun,

fun () -> Callback(?MODULE, CloseFDsFun) end).


如果使用的msg_store?以发送端发送消息为例.

rabbit_channel处理basic.pubish然后 deliver_to_queues

DeliveredQPids = rabbit_amqqueue:deliver(Qs, Delivery),主队列和备队列都收到发送消息请求(deliver)

主队列收到消息后deliver_or_enqueue,其中如果attempt_delivery失败后,则会准备将消息发到队列中BQS3 = BQ:publish(Message, Props, Delivered, SenderPid, Flow, BQS2),backing queue收到publish消息知道消息将要进入队列,则广播通知各个备队列gm:broadcast(GM, {publish, ChPid, Flow, MsgProps, Msg}, rabbit_basic:msg_size(Msg)),并让最终的backing queue来做处理BQ:publish(Msg, MsgProps, IsDelivered, ChPid, Flow, BQS),






publish(Msg = #basic_message { is_persistent = IsPersistent, id = MsgId },

MsgProps = #message_properties { needs_confirming = NeedsConfirming },

IsDelivered, _ChPid, _Flow,

State = #vqstate { q1 = Q1, q3 = Q3, q4 = Q4,

next_seq_id = SeqId,

in_counter = InCount,

durable = IsDurable,

unconfirmed = UC }) ->

IsPersistent1 = IsDurable andalso IsPersistent,

%%格式化消息

MsgStatus = msg_status(IsPersistent1, IsDelivered, SeqId, Msg, MsgProps),

{MsgStatus1, State1} = maybe_write_to_disk(false, false, MsgStatus, State),

 State2 = case ?QUEUE:is_empty(Q3) of

false -> State1 #vqstate { q1 = ?QUEUE:in(m(MsgStatus1), Q1) };

true -> State1 #vqstate { q4 = ?QUEUE:in(m(MsgStatus1), Q4) }

end, 

InCount1 = InCount + 1,

UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC),

State3 = stats({1, 0}, {none, MsgStatus1},

State2#vqstate{ next_seq_id = SeqId + 1,

in_counter = InCount1,

unconfirmed = UC1 }),

a(reduce_memory_use(maybe_update_rates(State3))).


一、如何将消息写入磁盘

%%尝试将消息和索引写入到磁盘中

maybe_write_to_disk(ForceMsg, ForceIndex, MsgStatus, State) ->

{MsgStatus1, State1} = maybe_write_msg_to_disk(ForceMsg, MsgStatus, State),

maybe_write_index_to_disk(ForceIndex, MsgStatus1, State1).




maybe_write_msg_to_disk(Force, MsgStatus = #msg_status {

msg = Msg, msg_id = MsgId,

is_persistent = IsPersistent },

State = #vqstate{ msg_store_clients = MSCState,

disk_write_count = Count})

when Force orelse IsPersistent ->

case persist_to(MsgStatus) of

msg_store -> ok = msg_store_write(MSCState, IsPersistent, MsgId,

prepare_to_store(Msg)),

{MsgStatus#msg_status{msg_in_store = true},

State#vqstate{disk_write_count = Count + 1}};

queue_index -> {MsgStatus, State}

end;

(_Force, MsgStatus, State) ->

{MsgStatus, State}.






 


备队列




































初始化主队列之后从coordinator获取gm,来实现队列进程之间的通信

init_with_existing_bq(Q = #amqqueue{name = QName}, BQ, BQS) ->

{ok, CPid} = rabbit_mirror_queue_coordinator:start_link(

Q, undefined, sender_death_fun(), depth_fun()),

GM = rabbit_mirror_queue_coordinator:get_gm(CPid),

Self = self(),

ok = rabbit_misc:execute_mnesia_transaction(

fun () ->

[Q1 = #amqqueue{gm_pids = GMPids}]

= mnesia:read({rabbit_queue, QName}),

ok = rabbit_amqqueue:store_queue(

Q1#amqqueue{gm_pids = [{GM, Self} | GMPids],

state = live})

end),

%%获取slave节点

{_MNode, SNodes} = rabbit_mirror_queue_misc:suggested_queue_nodes(Q),

 

%%增加镜像队列

rabbit_mirror_queue_misc:add_mirrors(QName, SNodes, sync),

#state { name = QName,

gm = GM,

coordinator = CPid,

backing_queue = BQ,

backing_queue_state = BQS,

seen_status = dict:new(),

confirmed = [],

known_senders = sets:new() }.




add_mirrors(QName, Nodes, SyncMode) ->

[add_mirror(QName, Node, SyncMode) || Node <- Nodes],

ok.


add_mirror(QName, MirrorNode, SyncMode) ->

case rabbit_amqqueue:lookup(QName) of

{ok, Q} ->

rabbit_misc:with_exit_handler(

rabbit_misc:const(ok),

fun () ->

SPid = rabbit_amqqueue_sup_sup:start_queue_process(

MirrorNode, Q, slave) ,

log_info(QName, "Adding mirror on node ~p: ~p~n",

[MirrorNode, SPid]),

rabbit_mirror_queue_slave:go(SPid, SyncMode)

end);

{error, not_found} = E ->

E

end.



rabbit_mirror_queue_slave:go(SPid, SyncMode)

go(SPid, sync) -> gen_server2:call(SPid, go, infinity);


进程刚创建起来之后state仍是{not_started,Q}

handle_call(go, _From, {not_started, Q} = NotStarted) ->

case handle_go(Q) of

{ok, State} -> {reply, ok, State};

{error, Error} -> {stop, Error, NotStarted}

end;


handle_go

创建gm,加入groupqueue_name)



rabbit_mirror_queue_slave使用 gm gen_server2两种behaviour,但是对于gm的使用只是实现了其中的一些回调函数。如果出现rabbit_mirror_queue_slave进程处理gm中的add_on_right等消息是错误的。


之所以主队列进程的backing queue不直接是variable queue,而是rabbit_mirror_queue_master,是因为主队列需要在对消息处理完后,需要同步给备队列,所以可以使用gm

你可能感兴趣的:(rabbitmq)