Skip to content

Commit

Permalink
Update README, better command main
Browse files Browse the repository at this point in the history
  • Loading branch information
Mochi committed Feb 9, 2020
1 parent e96ef01 commit 073d825
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 120 deletions.
217 changes: 103 additions & 114 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,128 +1,117 @@
mqtt
# Mochi MQTT
### A High-performance MQTT server in Go (v3.0 | v3.1.1)

Mochi MQTT is an embeddable high-performance MQTT broker server written in Go, and compliant with the MQTT v3.0 and v3.1.1 specification for the development of IoT and smarthome projects. The server can be used either as a standalone binary or embedded as a library in your own projects.

## Benchmarks
#### What is MQTT?
MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. [Learn more](https://mqtt.org/faq)

#### Mochi MQTT Features
- Paho MQTT 3.0 / 3.1.1 compatible.
- Full MQTT Feature-set (QoS, Retained, $SYS)
- Trie-based Subscription model.
- Ring Buffer packet codec.
- TCP, Websocket, (including SSL/TLS) and Dashboard listeners.
- Interfaces for Client Authentication and Topic access control.
- Bolt-backed persistence and storage interfaces.

#### Roadmap
- Inline Pub-sub (without client) and event hooks
- Docker Image
- MQTT v5 Compatibility

#### Performance
...

```
BenchmarkNewClients-4 145755818 7.92 ns/op 0 B/op 0 allocs/op
BenchmarkClientsAdd-4 24870105 55.9 ns/op 0 B/op 0 allocs/op
BenchmarkClientsGet-4 55802703 23.2 ns/op 0 B/op 0 allocs/op
BenchmarkClientsLen-4 70591254 16.4 ns/op 0 B/op 0 allocs/op
BenchmarkClientsDelete-4 33240973 37.5 ns/op 0 B/op 0 allocs/op
BenchmarkNewClient-4 2598082 461 ns/op 448 B/op 6 allocs/op
BenchmarkNextPacketID-4 100000000 11.6 ns/op 0 B/op 0 allocs/op
BenchmarkClientNoteSubscription-4 24480771 46.5 ns/op 0 B/op 0 allocs/op
BenchmarkClientForgetSubscription-4 12960447 95.5 ns/op 0 B/op 0 allocs/op
BenchmarkInflightSet-4 17793058 67.1 ns/op 0 B/op 0 allocs/op
BenchmarkInflightGet-4 25092826 46.4 ns/op 0 B/op 0 allocs/op
BenchmarkNew-4 22918302 44.3 ns/op 0 B/op 0 allocs/op
BenchmarkServerAddListener-4 7614312 160 ns/op 0 B/op 0 allocs/op
BenchmarkServerServe-4 405841 4993 ns/op 556 B/op 4 allocs/op
BenchmarkServerClose-4 781466 1814 ns/op 192 B/op 3 allocs/op
BenchmarkServerProcessPacket-4 345994209 7.46 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessConnect-4 230116939 5.22 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessDisconnect-4 214293916 5.11 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessPingreq-4 796363 2678 ns/op 459 B/op 7 allocs/op
BenchmarkServerProcessPublish-4 8610757 237 ns/op 48 B/op 1 allocs/op
BenchmarkServerProcessPubrec-4 44983093 24.2 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessPubrel-4 48499730 25.6 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessPubcomp-4 46276398 22.8 ns/op 0 B/op 0 allocs/op
BenchmarkServerProcessSubscribe-4 590350 3744 ns/op 728 B/op 9 allocs/op
BenchmarkServerProcessUnsubscribe-4 508149 2687 ns/op 475 B/op 7 allocs/op
```

#### Using the Broker
Mochi MQTT can be used as a standalone broker. Simply checkout this repository and run the `main.go` entrypoint in the `cmd` folder which will expose tcp (:1883), websocket (:1882), and dashboard (:8080) listeners.

```
BenchmarkNewListeners-4 100000000 10.0 ns/op 0 B/op 0 allocs/op
BenchmarkAddListener-4 18383103 64.2 ns/op 0 B/op 0 allocs/op
BenchmarkGetListener-4 54720651 21.9 ns/op 0 B/op 0 allocs/op
BenchmarkLenListener-4 70944740 16.3 ns/op 0 B/op 0 allocs/op
BenchmarkDeleteListener-4 33414661 36.4 ns/op 0 B/op 0 allocs/op
BenchmarkServeListener-4 578126 3569 ns/op 529 B/op 2 allocs/op
BenchmarkServeAllListeners-4 266442 24929 ns/op 1592 B/op 7 allocs/op
BenchmarkCloseListener-4 5804686 211 ns/op 96 B/op 1 allocs/op
BenchmarkCloseAllListeners-4 8264860 392 ns/op 96 B/op 1 allocs/op
BenchmarkNewTCP-4 31808517 247 ns/op 96 B/op 1 allocs/op
BenchmarkTCPSetConfig-4 16300988 134 ns/op 32 B/op 1 allocs/op
BenchmarkTCPID-4 74531133 16.3 ns/op 0 B/op 0 allocs/op
cd cmd
go build -o mqtt && ./mqtt
```

#### Quick Start

``` go
import (
mqtt "github.com/mochi-co/mqtt/server"
)

func main() {
// Create the new MQTT Server.
server := mqtt.New()

// Create a TCP listener on a standard port.
tcp := listeners.NewTCP("t1", ":1883")

// Add the listener to the server with default options (nil).
err := server.AddListener(tcp, nil)
if err != nil {
log.Fatal(err)
}

// Start the broker. Serve() is blocking - see examples folder
// for usage ideas.
err = server.Serve()
if err != nil {
log.Fatal(err)
}
}
```
BenchmarkAllowAuth-4 1000000000 0.335 ns/op 0 B/op 0 allocs/op
BenchmarkAllowACL-4 1000000000 0.351 ns/op 0 B/op 0 allocs/op
BenchmarkDisallowAuth-4 1000000000 0.340 ns/op 0 B/op 0 allocs/op
BenchmarkDisallowACL-4 1000000000 0.345 ns/op 0 B/op 0 allocs/op
```

Examples of running the broker with various configurations can be found in the `examples` folder.

#### Network Listeners
The server comes with a variety of pre-packaged network listeners which allow the broker to accept connections on different protocols. The current listeners are:
- `listeners.NewTCP(id, address string)` - A TCP Listener, taking a unique ID and a network address to bind.
- `listeners.NewWebsocket(id, address string)` A Websocket Listener
- `listeners.NewHTTPStats()` An HTTP $SYS info dashboard

##### Configuring Network Listeners
When a listener is added to the server using `server.AddListener`, a `*listeners.Config` may be passed as the second argument.

##### Authentication and ACL
Authentication and ACL may be configured on a per-listener basis by providing an Auth Controller to the listener configuration. Custom Auth Controllers should satisfy the `auth.Controller` interface found in `listeners/auth`. Two default controllers are provided, `auth.Allow`, which allows all traffic, and `auth.Disallow`, which denies all traffic.

```go
err := server.AddListener(tcp, &listeners.Config{
Auth: new(auth.Allow),
})
```
BenchmarkNew-4 43395020 25.3 ns/op 0 B/op 0 allocs/op
BenchmarkPoperate-4 4947649 246 ns/op 0 B/op 0 allocs/op
BenchmarkSubscribe-4 4079262 301 ns/op 0 B/op 0 allocs/op
BenchmarkUnsubscribe-4 2971792 406 ns/op 0 B/op 0 allocs/op
BenchmarkSubscribers-4 2497588 462 ns/op 0 B/op 0 allocs/op
BenchmarkIsolateParticle-4 22714515 48.3 ns/op 0 B/op 0 allocs/op
BenchmarkRetainMessage-4 4361300 285 ns/op 0 B/op 0 allocs/op
BenchmarkMessages-4 3255422 359 ns/op 0 B/op 0 allocs/op

> If no auth controller is provided in the listener configuration, the server will default to _Disallowing_ all traffic to prevent unintentional security issues.
##### SSL
SSL may be configured on both the TCP and Websocket listeners by providing a public-private PEM key pair to the listener configuration as `[]byte` slices.
```go
err := server.AddListener(tcp, &listeners.Config{
Auth: new(auth.Allow),
TLS: &listeners.TLS{
Certificate: publicCertificate,
PrivateKey: privateKey,
},
})
```
> Note the mandatory inclusion of the Auth Controller!
```
BenchmarkDecodeString-4 78840612 23.0 ns/op 0 B/op 0 allocs/op
BenchmarkDecodeBytes-4 100000000 13.7 ns/op 0 B/op 0 allocs/op
BenchmarkDecodeByte-4 1000000000 0.978 ns/op 0 B/op 0 allocs/op
BenchmarkDecodeUint16-4 1000000000 0.756 ns/op 0 B/op 0 allocs/op
BenchmarkDecodeByteBool-4 1000000000 0.900 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeBool-4 1000000000 0.585 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeBytes-4 1000000000 0.441 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeUint16-4 1000000000 0.529 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeString-4 87987272 21.2 ns/op 0 B/op 0 allocs/op
BenchmarkConnackEncode-4 36861868 38.0 ns/op 14 B/op 0 allocs/op
BenchmarkConnackDecode-4 39480138 34.4 ns/op 0 B/op 0 allocs/op
BenchmarkConnackValidate-4 1000000000 0.374 ns/op 0 B/op 0 allocs/op
BenchmarkConnectEncode-4 7838436 136 ns/op 38 B/op 0 allocs/op
BenchmarkConnectDecode-4 14495463 74.0 ns/op 0 B/op 0 allocs/op
BenchmarkConnectValidate-4 335426919 3.51 ns/op 0 B/op 0 allocs/op
BenchmarkDisconnectEncode-4 70712485 18.8 ns/op 7 B/op 0 allocs/op
BenchmarkDisconnectDecode-4 44808872 29.1 ns/op 0 B/op 0 allocs/op
BenchmarkDisconnectValidate-4 1000000000 0.348 ns/op 0 B/op 0 allocs/op
BenchmarkFixedHeaderEncode-4 78281166 32.3 ns/op 6 B/op 0 allocs/op
BenchmarkFixedHeaderDecode-4 100000000 12.0 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeLength-4 100000000 15.1 ns/op 2 B/op 0 allocs/op
BenchmarkNewParser-4 1000000000 0.960 ns/op 0 B/op 0 allocs/op
BenchmarkRefreshDeadline-4 9184636 131 ns/op 0 B/op 0 allocs/op
BenchmarkReadFixedHeader-4 18477132 61.0 ns/op 0 B/op 0 allocs/op
BenchmarkRead-4 5692833 204 ns/op 96 B/op 2 allocs/op
BenchmarkPingreqEncode-4 82176246 15.7 ns/op 6 B/op 0 allocs/op
BenchmarkPingreqDecode-4 44557917 31.3 ns/op 0 B/op 0 allocs/op
BenchmarkPingreqValidate-4 1000000000 0.338 ns/op 0 B/op 0 allocs/op
BenchmarkPingrespEncode-4 79194856 16.4 ns/op 6 B/op 0 allocs/op
BenchmarkPingrespDecode-4 48515474 43.4 ns/op 0 B/op 0 allocs/op
BenchmarkPingrespValidate-4 1000000000 0.449 ns/op 0 B/op 0 allocs/op
BenchmarkPubackEncode-4 29720542 46.3 ns/op 9 B/op 0 allocs/op
BenchmarkPubackDecode-4 23842455 107 ns/op 0 B/op 0 allocs/op
BenchmarkPubackValidate-4 1000000000 0.373 ns/op 0 B/op 0 allocs/op
BenchmarkPubcompEncode-4 39364371 34.0 ns/op 13 B/op 0 allocs/op
BenchmarkPubcompDecode-4 35092684 31.5 ns/op 0 B/op 0 allocs/op
BenchmarkPubcompValidate-4 1000000000 0.335 ns/op 0 B/op 0 allocs/op
BenchmarkPublishEncode-4 15284678 66.6 ns/op 18 B/op 0 allocs/op
BenchmarkPublishDecode-4 23294798 53.3 ns/op 0 B/op 0 allocs/op
BenchmarkPublishCopy-4 1000000000 0.376 ns/op 0 B/op 0 allocs/op
BenchmarkPublishValidate-4 779486254 1.44 ns/op 0 B/op 0 allocs/op
BenchmarkPubrecEncode-4 40375525 34.6 ns/op 13 B/op 0 allocs/op
BenchmarkPubrecDecode-4 37656330 28.6 ns/op 0 B/op 0 allocs/op
BenchmarkPubrecValidate-4 1000000000 0.378 ns/op 0 B/op 0 allocs/op
BenchmarkPubrelEncode-4 36370036 32.8 ns/op 15 B/op 0 allocs/op
BenchmarkPubrelDecode-4 38191740 29.9 ns/op 0 B/op 0 allocs/op
BenchmarkPubrelValidate-4 1000000000 0.394 ns/op 0 B/op 0 allocs/op
BenchmarkSubackEncode-4 19691620 59.6 ns/op 27 B/op 0 allocs/op
BenchmarkSubackDecode-4 26178052 40.6 ns/op 0 B/op 0 allocs/op
BenchmarkSubackValidate-4 1000000000 0.366 ns/op 0 B/op 0 allocs/op
BenchmarkSubscribeEncode-4 6134076 187 ns/op 90 B/op 0 allocs/op
BenchmarkSubscribeDecode-4 2296219 472 ns/op 303 B/op 0 allocs/op
BenchmarkSubscribeValidate-4 1000000000 0.585 ns/op 0 B/op 0 allocs/op
BenchmarkUnsubackEncode-4 39235142 32.8 ns/op 13 B/op 0 allocs/op
BenchmarkUnsubackDecode-4 34655808 42.6 ns/op 0 B/op 0 allocs/op
BenchmarkUnsubackValidate-4 1000000000 0.458 ns/op 0 B/op 0 allocs/op
BenchmarkUnsubscribeEncode-4 7313114 171 ns/op 83 B/op 0 allocs/op
BenchmarkUnsubscribeDecode-4 3187930 372 ns/op 259 B/op 0 allocs/op
BenchmarkUnsubscribeValidate-4 1000000000 0.544 ns/op 0 B/op 0 allocs/op
#### Data Persistence
Mochi MQTT provides a `persistence.Store` interface for developing and attaching persistent stores to the broker. The default persistence mechanism packaged with the broker is backed by [Bolt](https://github.com/etcd-io/bbolt) and can be enabled by assigning a `*bolt.Store` to the server.
```go
// import "github.com/mochi-co/mqtt/server/persistence/bolt"
err = server.AddStore(bolt.New("mochi.db", nil))
if err != nil {
log.Fatal(err)
}
```
> Persistence is on-demand (not flushed) and will potentially reduce throughput when compared to the standard in-memory store. Only use it if you need to maintain state through restarts.
#### Paho Interoperability Test
You can check the broker against the [Paho Interoperability Test](https://github.com/eclipse/paho.mqtt.testing/tree/master/interoperability) by starting the broker using `examples/paho/main.go`, and then running the test with `python3 client_test.py` from the _interoperability_ folder.

## Contributions
Contributions and feedback are both welcomed and encouraged! Open an [issue](https://github.com/mochi-co/mqtt/issues) to report a bug, ask a question, or make a feature request.



17 changes: 12 additions & 5 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"flag"
"fmt"
"log"
"os"
Expand All @@ -14,7 +15,10 @@ import (
)

func main() {
var err error
tcpAddr := flag.String("tcp", ":1883", "network address for TCP listener")
wsAddr := flag.String("ws", ":1882", "network address for Websocket listener")
infoAddr := flag.String("info", ":8080", "network address for web info dashboard listener")
flag.Parse()

sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
Expand All @@ -25,21 +29,24 @@ func main() {
}()

fmt.Println(aurora.Magenta("Mochi MQTT Broker initializing..."))
fmt.Println(aurora.Cyan("TCP"), *tcpAddr)
fmt.Println(aurora.Cyan("Websocket"), *wsAddr)
fmt.Println(aurora.Cyan("$SYS Dashboard"), *infoAddr)

server := mqtt.New()
tcp := listeners.NewTCP("t1", ":1883")
err = server.AddListener(tcp, nil)
tcp := listeners.NewTCP("t1", *tcpAddr)
err := server.AddListener(tcp, nil)
if err != nil {
log.Fatal(err)
}

ws := listeners.NewWebsocket("ws1", ":1882")
ws := listeners.NewWebsocket("ws1", *wsAddr)
err = server.AddListener(ws, nil)
if err != nil {
log.Fatal(err)
}

stats := listeners.NewHTTPStats("stats", ":8080")
stats := listeners.NewHTTPStats("stats", *infoAddr)
err = server.AddListener(stats, nil)
if err != nil {
log.Fatal(err)
Expand Down
5 changes: 4 additions & 1 deletion examples/persistence/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"syscall"

"github.com/logrusorgru/aurora"
"go.etcd.io/bbolt"

mqtt "github.com/mochi-co/mqtt/server"
"github.com/mochi-co/mqtt/server/listeners"
Expand All @@ -34,7 +35,9 @@ func main() {
log.Fatal(err)
}

err = server.AddStore(bolt.New("mochi-test.db", nil))
err = server.AddStore(bolt.New("mochi-test.db", &bbolt.Options{
Timeout: 500 * time.Millisecond,
}))
if err != nil {
log.Fatal(err)
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/asdine/storm/v3 v3.1.0
github.com/gorilla/websocket v1.4.1
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/krylovsk/mqtt-benchmark v0.1.1 // indirect
github.com/logrusorgru/aurora v0.0.0-20191116043053-66b7ad493a23
github.com/rs/xid v1.2.1
github.com/stretchr/testify v1.4.0
Expand Down
Loading

0 comments on commit 073d825

Please sign in to comment.