-
Notifications
You must be signed in to change notification settings - Fork 20
zhangxinrun/fubar
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
== Fubar == An MQTT message broker written in erlang targeted to support internet scale applications. == Getting Started == 1. Getting dependencies and building $ make deps $ make 2. Starting a broker in interactive mode $ make test 3. Testing 3.1. Starting a node for client $ make client 3.2. Connecting clients (in the client shell) 1> C1 = mqtt_client:start([{client_id, <<"c1">>}]). 2> C2 = mqtt_client:start([{client_id, <<"c2">>}]). 3.3. Subscribing and publishing messages 3> C1 ! mqtt:subscribe([{topics, [<<"t1">>]}]). 4> C2 ! mqtt:publish([{topic, <<"t1">>}, {payload, <<"hello!">>}]). 3.4. Direct messaging This is an extra feature not originally stated in MQTT specification. One client may use the other client's client id as a topic name to send a message directly to the client. 5> C2 ! mqtt:publish([{topic, <<"c1">>}, {payload, <<"world!">>}]). 4. Shutting down the broker gracefully. (fubar@host)1> fubar:stop(). (fubar@host)2> q(). == More Features == 1. Adding a new broker node to existing broker cluster $ make test master=name@host Note) If you want to start more than one broker node in a computer, You have to use different node name and listen port as: $ make test master=name@host node=other mqtt_port=1884 2. Using account control Uncomment {auth, mqtt_account} in src/fubar.app.src to enable auth. Then, call mqtt_account:update/2 as: (fubar@host)1> mqtt_account:update(<<"romeo">>, <<"1234">>). 3. More parameters for a client Full list of client parameters are: 1> C3 = mqtt_client:start([{hostname, "localhost"}, {port, 1884}, {username, <<"romeo">>}, {password, <<"1234">>}, {client_id, <<"c1">>}, {keep_alive, 60}, clean_session, {will_topic, <<"will">>}, {will_message, <<"bye-bye">>}, {will_qos, at_least_once}, will_retain, socket_options, [...]]). Refer inet:setopts/2 for socket_options. 4. Starting a broker in daemon mode Use 'run' instead of 'test'. $ make run Note) You may not start more than one daemon in a machine. 5. Getting a daemon shell $ make debug Note) The debug shell is closely bound with the daemon. If you exit from the debug shell in a normal way, the daemon will stop. Use CTRL-D to stop debugging. 6. Broker state is preserved The broker restores all the state -- accounts, topics and subscriptions - on restart. To clear this state, do: $ make reset 7. Dumping logs to text files SASL logs can be taken as: $ make dump SASL logs show events happened in the start-up process and events not dealt with by the application. Application logs can be taken from the shell as: (fubar@host)1> fubar_log:dump(trace, "trace.log"). Or you can dump all the logs by: (fubar@host)1> fubar_log:dump(). Log classes are: - access % network addresses of clients and disconnect events - packet % bytes sent and received by the broker - protocol % mqtt messages sent and received by the broker - resource % long lasting resources such as sessions and topics - debug % message put for debugging purpose - info % irrelevant events taken but dropped - warning % abnormal conditions that are not considered critical - error % irrecoverable failures - trace % fubar packets marked as trace 8. Log management Basically, two types of logs are used in fubar. One is error_logger and the other is disk_log. Most of the runtime events use disk_log and system start-up, shutdown events use error_logger. error_logger is also called as SASL log. The other difference is the fact that disk_log supports distributed logging but SASL log doesn't, which means that you can read all the disk_logs created in many nodes in one place but you have to go to each node to read SASL log. Also, you can open/close/redirect disk_log at runtime. Refer fubar_log:open/1, close/1, out/1, out/2 for more info. Log configuration stored in src/fubar.app.src controls both logs. ~ {fubar_log, [{dir, "priv/log"}, ~ {max_bytes, 10485760}, ~ {max_files, 10}, ~ {classes, [{trace, standard_io}, {warning, "fubar"}]} ~ ]}, - dir % Log files are left under <dir>/<node> usually "priv/log/fubar" - max_bytes % Maximum individual log file size per class - max_files % Maximum number of rolling log files per class - classes % Initial disk_log classes to open Classes take {Class, Redirect} as values. Class is one of the log classes listed in section 7. Redirect is one of none, standard_io or "prefix". The meaning of the redirect is as follows. - none % No redirect. Logs are left in the binary files only. - standard_io % Redirect to tty. - "prefix" % Redirect to daily log files with the prefix. % e.g, "prefix_2012-12-29.log.1" As noted before, disk_log is distributed log. Common practice to use distributed log in production is to use one node for central log consumer and set all the other nodes as log producer. To configure your system like this, start a node with 'make run mqtt=undefined' command from a computer. Then you have a node 'fubar@host1' without a listener. Now start other nodes with 'make run master=fubar@host1' command from other computers. You may turn all the log classes off in all the other nodes and control in only one place, the monitor node. You will find following files under the log directory. - 1, 2,..., index % SASL logs, binary rolling files. - access.*,... % disk_logs for each class, binary rolling files. - run_erl.log % Broker start-up linux command (production only). - erlang.log.* % Erlang shell input/output history (production only). - *_YYYY-MM-DD.log.* % Daily logs, text files without size limit. If you have daily logs in your log directory, you have to delete them regularly. They are produced if you redirect any disk_log to file by setting {Class, "prefix"} in src/fubar.app.src or by calling fubar_log:out(Class, "prefix"). 9. SSL support 9.1. Prepare a certificate authority $ cd priv/ssl/ca $ mkdir certs private $ chmod 700 private $ echo 01 > serial $ touch index.txt $ openssl req -x509 -config openssl.cnf -newkey rsa:2048 -days 365 \ -out cacert.pem -outform PEM -subj /CN=fubar_ca/ -nodes $ openssl x509 -in cacert.pem -out cacert.cer -outform DER 9.2. Create a server certificate $ openssl genrsa -out ../key.pem 2048 $ openssl req -new -key ../key.pem -out ../req.pem -outform PEM \ -subj /CN=SomeHostName/O=YourOrganizationName/ -nodes $ openssl ca -config openssl.cnf -in ../req.pem -out ../cert.pem -notext -batch -extensions server_ca_extensions $ openssl pkcs12 -export -in ../cert.pem -out ../keycert.p12 \ -inkey ../key.pem -passout pass:YourPassword The processes in 9.1 and 9.2 are stored in batch script priv/ssl/ca/new-certs.sh. So you can just, $ cd priv/ssl/ca $ ./new-certs.sh 9.3. Testing Use mqtts_port command line parameter to start an SSL listener when starting the broker. $ cd ../../.. $ make test mqtts_port=8883 (fubar@host)1> Test basic connection with openssl s_client. $ openssl s_client -connect localhost:8883 If it succeeds, use {transport, ranch_ssl} option on the client side. $ make client 1> ssl:start(). 2> mqtt_client:start([{port, 8883},{transport, ranch_ssl}, {client_id, <<"ssltest">>}]). 10. Benchmarking You can simulate many client connections with a computer. First, start a client shell. $ make client 1> mqtt_client module provides batch functions, batch_start/2,3, batch_restart/0,1 and batch_stop/0. Prepare a list of client id. 1> Id = [list_to_binary(io_lib:format("~4..0B", [N])) || N <- lists:seq(1, 1000)]. [<<"0001">>,<<"0002">>,...,<<"1000">>] Now you can use the list to call batch_start/2,3 as: 2> mqtt_client:batch_start(Id, [{host, "broker addr"}, clean_session]). [<0.121.0>,<0.122.0>,...] It may take some time to complete the batch start operation. You should be able to connect more than 50k clients from a computer. But of course you need to do proper kernel tuning and ulimit setting to do that. Start another client for probing. We'll use this client later to generate load. 3> Probe = mqtt_client:start([{host, "broker addr"}, {client_id, <<"probe">>}, clean_session]). Now, we are ready to generate load. Let's try direct messaging. 4> Worker = mqtt_probe:start(Probe, Id, <<"...">>, 0). You should find endless messages printed by the batch clients. The above command spawns a Worker that publishes a message <<"...">> to one of the Id list every 0 millisecond using the client Probe. You may want to monitor the broker's cpu/memory/io performance during this benchmark. Use top or sar in that case. You can stop the worker any time. 5> mqtt_probe:stop(Worker). Let's try another type of load now. Make all the clients subscribe to a common topic. 6> [Pid ! mqtt:subscribe([{topics,<<"t1">>}]) || {_, Pid} <- mqtt_client_sup:running()]. Then, use the probe to publish messages to the common topic periodically. 7> f(Worker). 8> Worker = mqtt_probe:start(Probe, <<"t1">>, <<"...">>, 1000). And so it goes. == Configurations == Initial broker configuration is read from ebin/fubar.app which is compiled from src/fubar.app.src. You have to edit src/fubar.app.src to make your configuration applied whenever you restart the broker. Or you can call fubar:settings/2 to apply changes while the broker is running. (fubar@host)1> fubar:settings(mqtt_protocol, {max_packet_size, 8192}). The above sample shows changing maximum MQTT packet size to 8kB. This change affects all the clients connection from this point on. Note that some change applies immediately but others require further intervention. Refer src/fubar.app.src for details.
About
A scalable MQTT broker written in erlang
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published