EMQ学习笔记

--------------------------------debugger-----------------------

werl -setcookie emqsecretcookie -name node_3@CN00209774 -remsh emq@CN00209774

 

or

werl -sname observer -hidden -setcookie emqsecretcookie -run observer

Ctrl+G

r 'emq@CN00209774'

j

c 2

--load new module into vm---

code:add_pathz("C:/Program Files/erl9.3/lib/debugger-4.2.4/ebin").

l(debugger).

debugger:start().

ii(emqttd_app).

 

--------------------rebar---------relx.config-----定义了应用的版本及依赖的应用-----------------------------------

 

要定义一个发布,首先要创建一个 发布资源文件 ,简称 .rel 文件,我们在这里指定发布的名称和版本、它基于哪个ERTS版本,以及它由哪些应用组成:

{release, { Name,Vsn}, {erts, EVsn},
 [{
Application1, AppVsn1},
   ...
  {
ApplicationN, AppVsnN}]}.

 

 

生成启动脚本

在SASL模块 systools 里面有很多可以用来构建和检验发布的工具。函数读取 .rel 和 .app 文件并执行语法和依赖性检查。函数systools:make_script/1,2 用于生成启动脚本。

当使用启动脚本启动Erlang/OTP时, .rel 文件中的所有应用都会被自动加载和启动

那么对于一些辅助lib呢,我们希望它被打包在应用发布目录中,但不希望它们被启动(它们可能根本不能启动),一种方法是将mylib指定为{mylib, load}(参见Issue1, Issue2),列表中的依赖项默认被relx解释为{mylib, permanent},即以常驻的方式启动应用。

 

 

------------------------------------------emqtt 启动流程------------------------------------------------------------------------

{application,emqttd,

[{description,"ErlangMQTTBroker"},

{vsn,"2.3.9"},

{modules,['emqttd','emqttd_access_control','emqttd_access_rule','emqttd_acl_internal','emqttd_acl_mod','emqttd_alarm','emqttd_app','emqttd_auth_mod','emqttd_base62','emqttd_boot','emqttd_bridge','emqttd_bridge_sup','emqttd_bridge_sup_sup','emqttd_broker','emqttd_cli','emqttd_cli_config','emqttd_client','emqttd_cm','emqttd_cm_sup','emqttd_config','emqttd_ctl','emqttd_gc','emqttd_gen_mod','emqttd_guid','emqttd_hooks','emqttd_http','emqttd_inflight','emqttd_keepalive','emqttd_message','emqttd_metrics','emqttd_mgmt','emqttd_misc','emqttd_mod_sup','emqttd_mqueue','emqttd_net','emqttd_packet','emqttd_parser','emqttd_plugins','emqttd_pmon','emqttd_pool_sup','emqttd_pooler','emqttd_protocol','emqttd_pubsub','emqttd_pubsub_sup','emqttd_rest_api','emqttd_router','emqttd_serializer','emqttd_server','emqttd_session','emqttd_session_sup','emqttd_sm','emqttd_sm_helper','emqttd_sm_sup','emqttd_stats','emqttd_sup','emqttd_sysmon','emqttd_sysmon_sup','emqttd_time','emqttd_topic','emqttd_trace','emqttd_trace_sup','emqttd_trie','emqttd_vm','emqttd_ws','emqttd_ws_client','emqttd_ws_client_sup','gen_server2','lager_emqtt_backend','priority_queue']},

{registered,[emqttd_sup]},

{applications,[kernel,stdlib,gproc,lager,esockd,mochiweb,pbkdf2]},

{env,[]},

{mod,{emqttd_app,[]}},

{maintainers,["FengLee<feng@emqtt.io>"]},

{licenses,["Apache-2.0"]},

{links,[{ "Github","https://github.com/emqtt/emqttd"}]}]}.

 

----------------------------------------------------------------

Emqttd.app.src   application定义源文件生成emqttd.app文件

{mod,{emqttd_app,[]}}

 

-----------------------------------------------------------------------------

--> emqttd_app.erl

ekka:start(), 启动ekka

 

%%--------------------------------------------------------------------

%%MnesiaBootstrap

%%--------------------------------------------------------------------

 

mnesia(boot) 系统启动的时候创建mqtt_route mnesia 表。

 

mnesia(boot)->

ok=ekka_mnesia:create_table(mqtt_route

 

%%@docCreatemnesiatables.

create_tables()->

ekka_boot:apply_module_attributes(boot_mnesia). -- 该方法遍历所有已加载的应用和模块,查找模块中的属性,再调用对应方法创建表。

-boot_mnesia({mnesia,[boot]}).

 

 

 

EMQ工程目录下,有关键字-boot_mnesia({mnesia, [boot]}).和-copy_mnesia({mnesia, [copy]}).的模块是:

 

-module(emqttd_router).

-module(emqttd_sm). -- mqtt_session

-module(emqttd_trie).  -- mqtt_trie / mqtt_trie_node

 

 

 

 

 

-----------------------------------------------------------------------------

emqttd_sup:start_link()

--> emqttd_sup.erl  --emqttd_sup 监督进程

 

start_servers() 启动所有关联子进程。

--emqttd_ctl 命令行操作相关功能。

 --> emqttd_ctl.erl

启动创建mqttd_ctl_cmd

 

-----------------------------------------------------------------------------

--emqttd_hooks

EMQ 消息服务器在客户端上下线、主题订阅、消息收发位置设计了扩展钩子(Hook).

emqttd.erl 模块封装了 Hook 接口,

emqttd_hooks.erl 模块实现 Hook 机制,

创建mqtt_hook,

 

emq_plugin_template 提供了全部钩子的使用示例,例如端到端的消息处理回调。

 

-----------------------------------------------------------------------------

--emqttd_router

--> emqttd_router.erl

该模块提供了消息路由的功能。EMQ 按主题树(Topic Trie)发布订阅模式在集群节点间路由 MQTT 消息。

init([])->

ekka:monitor(membership),

ets:new(mqtt_local_route,[set,named_table,protected]),

{ok,TRef}=timer:send_interval(timer:seconds(1),stats),

{ok,#state{stats_timer=TRef}}.

启动的时候会调用ekka的monitor接口打开集群监控,

--> ekka.erl --> ekka_membership.erl

 

ekka_membership 提供集群监控的功能

创建ets表,membership

 

保存节点信息

 

 

创建ets表,mqtt_local_route

 

 

{ok, TRef} = timer:send_interval(timer:seconds(1), stats),

和timer_server模块建立连接,每秒更新一次mqtt_stats 状态,->

handle_info(stats,State)->

update_stats_(),

{noreply,State,hibernate};

 

update_stats_()  -> emqttd_stats.erl

handle_cast({setstats,Stat,MaxStat,Val},State)

 

 

 

14:37:23:671000 (<10624.222.0>) << stats

14:37:23:671001 (<10624.222.0>) in {erlang,hibernate,3}

14:37:23:671002 (<10624.222.0>) emqttd_stats ! {'$gen_cast',

                                                {setstats,'routes/count','routes/max',0}}

14:37:23:671003 (<10624.222.0>) emqttd_stats ! {'$gen_cast',

                                                {setstats,'topics/count','topics/max',0}}

14:37:23:671004 (<10624.222.0>) out {erlang,hibernate,3}

 

 

-----------------------------------------------------------------------------

--emqttd_pubsub_sup

create_table: [mqtt_subproperty, mqtt_subscriber, mqtt_subscription]

emqttd:env(pubsub) 从配置文件中获取到环境变量

mqtt.pubsub.pool_size = 8

mqtt.pubsub.async = true

 

(emq@CN00209774)15> emqttd_pubsub_sup:init([]).

{ok,{ {one_for_all,10,3600},

     [{pubsub_pool,

          {emqttd_pool_sup,start_link,

              [pubsub,hash,8,

               {emqttd_pubsub,start_link,[[{pool_size,8},{async,true}]]}]},

          transient,infinity,supervisor,

          [emqttd_pool_sup]},

      {server_pool,

          {emqttd_pool_sup,start_link,

              [server,hash,8,

               {emqttd_server,start_link,[[{pool_size,8},{async,true}]]}]},

          transient,infinity,supervisor,

          [emqttd_pool_sup]}]}}

 

 

[pool_sup(pubsub, Env), pool_sup(server, Env)] 创建两个进程池pubsub_pool对应emqtt_pubsub模块, server_pool对应emqtt_server模块,每个池包含8个进程,

-> emqttd_pool_sup.erl  

start_link(Pool,Type,Size,MFA)

init([Pool,Type,Size,{ M,F,Args}])

gproc_pool:add_worker(Pool,Name,Slot)

-> gproc_pool.erl  该模块实现了负载均衡服务器池,每个池都包含一定数量的worker和一个负载均衡策略,进程可以通过connect_worker/2 方法连接到池中的一个worker。用户可以通过pick/1方法获取到池中一个连接上的进程。

 

gproc 表存放进程池的相关信息

 

 

-----------------------------------------------------------------------------

emqttd_pubsub 提供pub/sub 相关的api

%%PubSubAPI.

-export([subscribe/3,async_subscribe/3,publish/2,unsubscribe/3,

async_unsubscribe/3,subscribers/1]).

 

-export([dispatch/2]).

 

emqttd_pubsub:publish(Topic,Msg1); -- 发送MQTT消息到对应topic

-> emqttd_router:match(Topic) --

-> emqttd_trie:match/1 -- 从mqtt_trie表和mqtt_trie_node表中匹配$SYS开头的系统topic,再从mqtt_route表中找出对应的route信息

-> emqttd_router:match_local(Topic) -- mqtt_local_route表中匹配本地订阅的topic

-> route() -- 没匹配到任何topicdrop掉消息,匹配到本地节点的topic则调用dispatch()发送消息,非本地节点则调用forward()方法发送消息到其他节点,再通过其他节点的dispatch()方法发送消息

-> dispatch() -- 先根据topicmqtt_subscriber表查出订阅列表,没有则drop掉消息,有则向订阅者的session进程发送dispatch消息。

 

 

-----------------------------------------------------------------------------

emqttd_server 提供pub/sub 以及管理相关的api

%%PubSubAPI.

-export([subscribe/1,subscribe/2,subscribe/3,publish/1,

unsubscribe/1,unsubscribe/2]).

 

%%AsyncPubSubAPI.

-export([async_subscribe/1,async_subscribe/2,async_subscribe/3,

async_unsubscribe/1,async_unsubscribe/2]).

 

%%ManagementAPI.

-export([setqos/3,subscriptions/1,subscribers/1,subscribed/2]).

 

%%DebugAPI

-export([dump/0]).

 

-----------------------------------------------------------------------------

--emqttd_stats emqtt 统计数据收集模块,收集client, topic, session, 等信息

 

 

 

%%ClientandSessionStats

-export([set_client_stats/2,get_client_stats/1,del_client_stats/1,

set_session_stats/2,get_session_stats/1,del_session_stats/1]).

 

%%StatisticsAPI.

-export([statsfun/1,statsfun/2,getstats/0,getstat/1,setstat/2,setstats/3]).

 

 

创建表 mqtt_stats / mqtt_client_stats / mqtt_session_stats

init([])->

%Ticktopublishstats

{ok,#state{tick=emqttd_broker:start_tick(tick)},hibernate}.

 

%%@docStartaticktimer.

start_tick(Msg)->

start_tick(emqttd:env(broker_sys_interval,60000),Msg).

每分钟发送一次tick消息,触发publish操作,向表中的topic发送统计数据

 

handle_info(tick,State)->

[publish(Stat,Val)||{ Stat,Val}<-ets:tab2list(?STATS_TAB)],

{noreply,State,hibernate};

 

 

-----------------------------------------------------------------------------

--emqttd_metrics emqtt 统计数据收集模块,收集数据包和消息发送接收详细信息

 

 

 

%%APIFunctionExports

-export([start_link/0]).

 

%%Received/SentMetrics

-export([received/1,sent/1]). -- 统计接收和发送包的数量

-export([all/0,value/1,inc/1,inc/2,inc/3,dec/2,dec/3,set/2]).

all -- 获取所有指标的值

value -- 获取指定指标的值

inc -- 指标值递增

dec -- 指标值递减

set -- 给指标设置一个值

 

创建表 mqtt_metric

 

%Ticktopublishmetrics

{ok,#state{tick=emqttd_broker:start_tick(tick)},hibernate}.

每分钟发送一次tick消息,触发publish操作,向表中的topic发送统计数据

 

-----------------------------------------------------------------------------

--emqttd_pooler 进程池管理模块

 

根据运行机器的CPU核数,启动相应数量的emqtt_pooler进程

erlang:system_info(schedulers)

 

{state,{<0.244.0>,emqttd_pool_sup},

       one_for_one,

       [{child,<0.248.0>,

               {emqttd_pooler,4},

               {emqttd_pooler,start_link,[pooler,4]},

               transient,5000,worker,

               [emqttd_pooler]},

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值