design.rst 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. ==============
  2. Design Guide
  3. ==============
  4. ---------------
  5. Pubsub Sequence
  6. ---------------
  7. ## PubSub Sequence
  8. ### Clean Session = 1
  9. ```
  10. title PubSub Sequence(Clean Session = 1)
  11. ClientA-->PubSub: Publish Message
  12. PubSub-->ClientB: Dispatch Message
  13. ```
  14. ![PubSub_CleanSess_1](http://emqtt.io/static/img/design/PubSub_CleanSess_1.png)
  15. ### Clean Session = 0
  16. ```
  17. title PubSub Sequence(Clean Session = 0)
  18. ClientA-->SessionA: Publish Message
  19. SessionA-->PubSub: Publish Message
  20. PubSub-->SessionB: Dispatch Message
  21. SessionB-->ClientB: Dispatch Message
  22. ```
  23. ![PubSub_CleanSess_0](http://emqtt.io/static/img/design/PubSub_CleanSess_0.png)
  24. ## Qos
  25. PubQos | SubQos | In Message | Out Message
  26. -------|--------|------------|-------------
  27. 0 | 0 | 0 | 0
  28. 0 | 1 | 0 | 0
  29. 0 | 2 | 0 | 0
  30. 1 | 0 | 1 | 0
  31. 1 | 1 | 1 | 1
  32. 1 | 2 | 1 | 1
  33. 2 | 0 | 2 | 0
  34. 2 | 1 | 2 | 1
  35. 2 | 2 | 2 | 2
  36. ## Topic Functions Benchmark
  37. Mac Air(11):
  38. Function | Time(microseconds)
  39. -------------|--------------------
  40. match | 6.25086
  41. triples | 13.86881
  42. words | 3.41177
  43. binary:split | 3.03776
  44. iMac:
  45. Function | Time(microseconds)
  46. -------------|--------------------
  47. match | 3.2348
  48. triples | 6.93524
  49. words | 1.89616
  50. binary:split | 1.65243
  51. --------------
  52. Cluster Design
  53. --------------
  54. ## Cluster Design
  55. 1. One 'disc_copies' node and many 'ram_copies' nodes.
  56. 2. Topic trie tree will be copied to every clusterd node.
  57. 3. Subscribers to topic will be stored in each node and will not be copied.
  58. ## Cluster Strategy
  59. TODO:...
  60. 1. A message only gets forwarded to other cluster nodes if a cluster node is interested in it. this reduces the network traffic tremendously, because it prevents nodes from forwarding unnecessary messages.
  61. 2. As soon as a client on a node subscribes to a topic it becomes known within the cluster. If one of the clients somewhere in the cluster is publishing to this topic, the message will be delivered to its subscriber no matter to which cluster node it is connected.
  62. ....
  63. ## Cluster Architecture
  64. ![Cluster Design](http://emqtt.io/static/img/Cluster.png)
  65. ## Cluster Command
  66. ```sh
  67. ./bin/emqttd_ctl cluster DiscNode
  68. ```
  69. ## Mnesia Example
  70. ```
  71. (emqttd3@127.0.0.1)3> mnesia:info().
  72. ---> Processes holding locks <---
  73. ---> Processes waiting for locks <---
  74. ---> Participant transactions <---
  75. ---> Coordinator transactions <---
  76. ---> Uncertain transactions <---
  77. ---> Active tables <---
  78. mqtt_retained : with 6 records occupying 221 words of mem
  79. topic_subscriber: with 0 records occupying 305 words of mem
  80. topic_trie_node: with 129 records occupying 3195 words of mem
  81. topic_trie : with 128 records occupying 3986 words of mem
  82. topic : with 93 records occupying 1797 words of mem
  83. schema : with 6 records occupying 1081 words of mem
  84. ===> System info in version "4.12.4", debug level = none <===
  85. opt_disc. Directory "/Users/erylee/Projects/emqttd/rel/emqttd3/data/mnesia" is NOT used.
  86. use fallback at restart = false
  87. running db nodes = ['emqttd2@127.0.0.1','emqttd@127.0.0.1','emqttd3@127.0.0.1']
  88. stopped db nodes = []
  89. master node tables = []
  90. remote = []
  91. ram_copies = [mqtt_retained,schema,topic,topic_subscriber,topic_trie,
  92. topic_trie_node]
  93. disc_copies = []
  94. disc_only_copies = []
  95. [{'emqttd2@127.0.0.1',ram_copies},
  96. {'emqttd3@127.0.0.1',ram_copies},
  97. {'emqttd@127.0.0.1',disc_copies}] = [schema]
  98. [{'emqttd2@127.0.0.1',ram_copies},
  99. {'emqttd3@127.0.0.1',ram_copies},
  100. {'emqttd@127.0.0.1',ram_copies}] = [topic,topic_trie,topic_trie_node,
  101. mqtt_retained]
  102. [{'emqttd3@127.0.0.1',ram_copies}] = [topic_subscriber]
  103. 44 transactions committed, 5 aborted, 0 restarted, 0 logged to disc
  104. 0 held locks, 0 in queue; 0 local transactions, 0 remote
  105. 0 transactions waits for other nodes: []
  106. ```
  107. ## Cluster vs Bridge
  108. Cluster will copy topic trie tree between nodes, Bridge will not.
  109. -------------
  110. Hooks Design
  111. -------------
  112. ## Overview
  113. emqttd supported a simple hooks mechanism in 0.8.0 release to extend the broker. The designed is improved in 0.9.0 release.
  114. ## API
  115. emqttd_broker Hook API:
  116. ```
  117. -export([hook/3, unhook/2, foreach_hooks/2, foldl_hooks/3]).
  118. ```
  119. ### Hook
  120. ```
  121. -spec hook(Hook :: atom(), Name :: any(), MFA :: mfa()) -> ok | {error, any()}.
  122. hook(Hook, Name, MFA) ->
  123. ...
  124. ```
  125. ### Unhook
  126. ```
  127. -spec unhook(Hook :: atom(), Name :: any()) -> ok | {error, any()}.
  128. unhook(Hook, Name) ->
  129. ...
  130. ```
  131. ### Foreach Hooks
  132. ```
  133. -spec foreach_hooks(Hook :: atom(), Args :: list()) -> any().
  134. foreach_hooks(Hook, Args) ->
  135. ...
  136. ```
  137. ### Foldl Hooks
  138. ```
  139. -spec foldl_hooks(Hook :: atom(), Args :: list(), Acc0 :: any()) -> any().
  140. foldl_hooks(Hook, Args, Acc0) ->
  141. ...
  142. ```
  143. ## Hooks
  144. Name | Type | Description
  145. --------------- | ----------| --------------
  146. client.connected | foreach | Run when client connected successfully
  147. client.subscribe | foldl | Run before client subscribe topics
  148. client.subscribe.after | foreach | Run After client subscribe topics
  149. client.unsubscribe | foldl | Run when client unsubscribe topics
  150. message.publish | foldl | Run when message is published
  151. message.acked | foreach | Run when message is acked
  152. client.disconnected | foreach | Run when client is disconnnected
  153. ## End-to-End Message Pub/Ack
  154. Could use 'message.publish', 'message.acked' hooks to implement end-to-end message pub/ack:
  155. ```
  156. PktId <-- --> MsgId <-- --> MsgId <-- --> PktId
  157. |<--- Qos --->|<---PubSub--->|<-- Qos -->|
  158. ```
  159. ## Limit
  160. The design is experimental.
  161. --------------
  162. Plugin Design
  163. --------------
  164. ## Overview
  165. **Notice that 0.11.0 release use rebar to manage plugin's deps.**
  166. A plugin is just an erlang application that extends emqttd broker.
  167. The plugin application should be put in "emqttd/plugins/" folder to build.
  168. ## Plugin Project
  169. You could create a standalone plugin project outside emqttd, and then add it to "emqttd/plugins/" folder by "git submodule".
  170. Git submodule to compile emqttd_dashboard plugin with the broker, For example:
  171. ```
  172. git submodule add https://github.com/emqtt/emqttd_dashboard.git plugins/emqttd_dashboard
  173. make && make dist
  174. ```
  175. ## plugin.config
  176. **Each plugin should have a 'etc/plugin.config' file**
  177. For example, project structure of emqttd_dashboard plugin:
  178. ```
  179. LICENSE
  180. README.md
  181. ebin
  182. etc
  183. priv
  184. rebar.config
  185. src
  186. ```
  187. etc/plugin.config for emqttd_dashboard plugin:
  188. ```
  189. [
  190. {emqttd_dashboard, [
  191. {listener,
  192. {emqttd_dashboard, 18083, [
  193. {acceptors, 4},
  194. {max_clients, 512}]}}
  195. ]}
  196. ].
  197. ```
  198. ## rebar.config
  199. **Plugin should use 'rebar.config' to manage depencies**
  200. emqttd_plugin_pgsql plugin's rebar.config, for example:
  201. ```
  202. %% -*- erlang -*-
  203. {deps, [
  204. {epgsql, ".*",{git, "https://github.com/epgsql/epgsql.git", {branch, "master"}}}
  205. ]}.
  206. ```
  207. ## Build emqttd with plugins
  208. Put all the plugins you required in 'plugins/' folder of emqttd project, and then:
  209. ```
  210. make && make dist
  211. ```
  212. ## Load Plugin
  213. './bin/emqttd_ctl' to load/unload plugin, when emqttd broker started.
  214. ```
  215. ./bin/emqttd_ctl plugins load emqttd_plugin_demo
  216. ./bin/emqttd_ctl plugins unload emqttd_plugin_demo
  217. ```
  218. ## List Plugins
  219. ```
  220. ./bin/emqttd_ctl plugins list
  221. ```
  222. ## API
  223. ```
  224. %% Load all active plugins after broker started
  225. emqttd_plugins:load()
  226. %% Load new plugin
  227. emqttd_plugins:load(Name)
  228. %% Unload all active plugins before broker stopped
  229. emqttd_plugins:unload()
  230. %% Unload a plugin
  231. emqttd_plugins:unload(Name)
  232. ```