• RabbitMQ Boot Step


    之前提到[链接]RabbitMQ会把启动过程分成若干阶段,按照依赖关系进行启动.rabbit_boot_step里面的requires 和 enables配置节是描述这种依赖关系的关键.require约定了该项目启动所依赖的前置条件,enables 表示当前项目启动之后可以启动什么;如果有多个项目enable一个项目(比如:external_infrastructure),要等这些项目都启动了external_infrastructure 才可以启动. 
     
       为什么要搞得那么复杂?一股脑调用启动不就行了?RabbitMQ启动过程中复杂的依赖关系,以及灵活扩展的要求,不可能随机顺序启动或者硬编码启动顺序.官方在GitHub上面举了一个例子:
     
       Boot steps can be separated into groups. A group of boot steps will enabled certain other group. For example routing_ready is actually enabled by many others boot steps, not just recovery. One of such steps is the empty_db_check that ensures that the Mnesia, Erlang's built-in distributed database, has the default data, like the default guest user for example. Also we can see that the recovery boot step also depends on empty_db_check so this logic takes care of running them in the right order that will satisfy the interdependencies they have.
     
     看一下上面所说的图形效果,这只是RabbitMQ整个启动过程的片段,[ 完整高清大图请点击这里 ]:
     

     
      整个启动过程,会被构造成一个有向无循环图,这里可以参考rabbit.erl的sort_boot_step方法
     
    复制代码
    sort_boot_steps(UnsortedSteps) ->
        case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2,
                                             UnsortedSteps) of
            {ok, G} ->
                %% Use topological sort to find a consistent ordering (if
                %% there is one, otherwise fail).
                SortedSteps = lists:reverse(
                                [begin
                                     {StepName, Step} = digraph:vertex(G,
                                                                       StepName),
                                     Step
                                 end || StepName <- digraph_utils:topsort(G)]),
                digraph:delete(G),
                %% Check that all mentioned {M,F,A} triples are exported.
                case [{StepName, {M,F,A}} ||
                         {StepName, Attributes} <- SortedSteps,
                         {mfa, {M,F,A}}         <- Attributes,
                         not erlang:function_exported(M, F, length(A))] of
                    []               -> SortedSteps;
                    MissingFunctions -> basic_boot_error(
                                          {missing_functions, MissingFunctions},
                                          "Boot step functions not exported: ~p~n",
                                          [MissingFunctions])
                end;
            {error, {vertex, duplicate, StepName}} ->
                basic_boot_error({duplicate_boot_step, StepName},
                                 "Duplicate boot step name: ~w~n", [StepName]);
            {error, {edge, Reason, From, To}} ->
                basic_boot_error(
                  {invalid_boot_step_dependency, From, To},
                  "Could not add boot step dependency of ~w on ~w:~n~s",
                  [To, From,
                   case Reason of
                       {bad_vertex, V} ->
                           io_lib:format("Boot step not registered: ~w~n", [V]);
                       {bad_edge, [First | Rest]} ->
                           [io_lib:format("Cyclic dependency: ~w", [First]),
                            [io_lib:format(" depends on ~w", [Next]) ||
                                Next <- Rest],
                            io_lib:format(" depends on ~w~n", [First])]
                   end])
        end.
    复制代码


    DEMO


     看一个具体例子,RabbitMQ in Action 一书中rabbit_exchange_type_recent_history扩展.代码url: https://github.com/rabbitinaction/sourcecode 看看它的启动规格说明:

    复制代码
    -rabbit_boot_step({?MODULE,
    [{description, "exchange type x-recent-history"},
    {mfa, {rabbit_registry, register,
    [exchange, <<"x-recent-history">>, ?MODULE]}},
    {requires, rabbit_registry},
    {enables, kernel_ready}]}).
    
    -rabbit_boot_step({rabbit_exchange_type_recent_history_mnesia,
    [{description, "recent history exchange type: mnesia"},
    {mfa, {?MODULE, setup_schema, []}},
    {requires, database},
    {enables, external_infrastructure}]}).
    复制代码
    
    
      参照上面的高清大图,可以看一下它会在什么位置完成上面两步操作.下面我们重新编译启动Rabbit,看下启动过程的输出,注意新增的部分:
     
    复制代码
    Eshell V5.9  (abort with ^G)
    (rabbit@nimbus)1>
    +---+   +---+
    |   |   |   |
    |   |   |   |
    |   |   |   |
    |   +---+   +-------+
    |                   |
    | RabbitMQ  +---+   |
    |           |   |   |
    |   v3.0.0  +---+   |
    |                   |
    +-------------------+
    AMQP 0-9-1 / 0-9 / 0-8
    Copyright (C) 2007-2012 VMware, Inc.
    Licensed under the MPL.  See http://www.rabbitmq.com/
    
    node           : rabbit@nimbus
    app descriptor : /data/rabbitmq-server-3.0.0/scripts/../ebin/rabbit.app
    home dir       : /root
    config file(s) : (none)
    cookie hash    : qhI/+VnjqUPUYcXLZ2jZMQ==
    log            : /var/log/rabbitmq/rabbit@nimbus.log
    sasl log       : /var/log/rabbitmq/rabbit@nimbus-sasl.log
    database dir   : /var/lib/rabbitmq/mnesia/rabbit@nimbus
    erlang version : 5.9
    
    -- rabbit boot start
    starting file handle cache server                                     ...done
    starting worker pool                                                  ...done
    starting database                                                     ...done
    starting database sync                                                ...done
    starting codec correctness check                                      ...done
    starting recent history exchange type: mnesia                         ...done  %%% 看这里 看这里
    -- external infrastructure ready
    starting statistics event manager                                     ...done
    starting logging server                                               ...done
    starting plugin registry                                              ...done
    starting auth mechanism amqplain                                      ...done
    starting auth mechanism cr-demo                                       ...done
    starting auth mechanism plain                                         ...done
    starting exchange type direct                                         ...done
    starting exchange type fanout                                         ...done
    starting exchange type headers                                        ...done
    starting exchange type x-recent-history                               ...done   %%%%   看这里 看这里 
    starting exchange type topic                                          ...done
    -- kernel ready
    starting node monitor                                                 ...done
    starting cluster delegate                                             ...done
    starting guid generator                                               ...done
    starting alarm handler                                                ...done
    starting memory monitor                                               ...done
    -- core initialized
    starting empty DB check                                               ...done
    starting background garbage collection                                ...done
    starting HA policy validation                                         ...done
    starting policy parameters                                            ...done
    starting exchange, queue and binding recovery                         ...done
    starting mirror queue slave sup                                       ...done
    starting adding mirrors to queues                                     ...done
    -- message delivery logic ready
    starting error log relay                                              ...done
    starting networking                                                   ...done
    starting notify cluster nodes                                         ...done
    starting direct client                                                ...done
    
    broker running
    复制代码
     
     
      感兴趣的话,可以输出rabbit:boot_steps()看一下,内容略长,请展开:
     
    Boot Step Dump
    sort_boot_steps(UnsortedSteps) ->
        case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2,
                                             UnsortedSteps) of
            {ok, G} ->
                %% Use topological sort to find a consistent ordering (if
                %% there is one, otherwise fail).
                SortedSteps = lists:reverse(
                                [begin
                                     {StepName, Step} = digraph:vertex(G,
                                                                       StepName),
                                     Step
                                 end || StepName <- digraph_utils:topsort(G)]),
                digraph:delete(G),
                %% Check that all mentioned {M,F,A} triples are exported.
                case [{StepName, {M,F,A}} ||
                         {StepName, Attributes} <- SortedSteps,
                         {mfa, {M,F,A}}         <- Attributes,
                         not erlang:function_exported(M, F, length(A))] of
                    []               -> SortedSteps;
                    MissingFunctions -> basic_boot_error(
                                          {missing_functions, MissingFunctions},
                                          "Boot step functions not exported: ~p~n",
                                          [MissingFunctions])
                end;
            {error, {vertex, duplicate, StepName}} ->
                basic_boot_error({duplicate_boot_step, StepName},
                                 "Duplicate boot step name: ~w~n", [StepName]);
            {error, {edge, Reason, From, To}} ->
                basic_boot_error(
                  {invalid_boot_step_dependency, From, To},
                  "Could not add boot step dependency of ~w on ~w:~n~s",
                  [To, From,
                   case Reason of
                       {bad_vertex, V} ->
                           io_lib:format("Boot step not registered: ~w~n", [V]);
                       {bad_edge, [First | Rest]} ->
                           [io_lib:format("Cyclic dependency: ~w", [First]),
                            [io_lib:format(" depends on ~w", [Next]) ||
                                Next <- Rest],
                            io_lib:format(" depends on ~w~n", [First])]
                   end])
        end.

      最后小图一张:迅哥,周末愉快!

    坚强2002和你一起回头再说... gmail 

    guess         read my mind!

    分类: Erlang
  • 相关阅读:
    Base4.net和IronPython的一些相关东东
    WPF E 文章汇总
    Novell 发布Mono 1.2 推动.NET跨平台
    Google真好,这么多的工具……
    bootstrap源码学习与示例:bootstrappopover
    bootstrap源码学习与示例:bootstrapscrollspy
    bootstrap源码学习与示例:bootstrapcollapse
    bootstrap源码学习与示例:bootstrapaffix
    bootstrap源码学习与示例:bootstraptab
    mass Framework attr模块 v3
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2820415.html
Copyright © 2020-2023  润新知