2017-10-29 01:04:47 +03:00
< p align = "center" >
< img
2017-11-03 04:31:36 +03:00
src="logo.png"
2017-10-29 01:09:18 +03:00
width="213" height="75" border="0" alt="evio">
2017-10-29 01:04:47 +03:00
< br >
< a href = "https://travis-ci.org/tidwall/evio" > < img src = "https://img.shields.io/travis/tidwall/evio.svg?style=flat-square" alt = "Build Status" > < / a >
< a href = "https://godoc.org/github.com/tidwall/evio" > < img src = "https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt = "GoDoc" > < / a >
< / p >
2017-10-29 01:30:33 +03:00
2017-11-02 18:57:35 +03:00
`evio` is an event loop networking framework that is fast and small. It makes direct [epoll ](https://en.wikipedia.org/wiki/Epoll ) and [kqueue ](https://en.wikipedia.org/wiki/Kqueue ) syscalls rather than using the standard Go [net ](https://golang.org/pkg/net/ ) package, and works in a similar manner as [libuv ](https://github.com/libuv/libuv ) and [libevent ](https://github.com/libevent/libevent ).
2017-10-29 01:30:33 +03:00
2018-10-28 21:30:18 +03:00
The goal of this project is to create a server framework for Go that performs on par with [Redis ](http://redis.io ) and [Haproxy ](http://www.haproxy.org ) for packet handling. It was built to be the foundation for [Tile38 ](https://github.com/tidwall/tile38 ) and a future L7 proxy for Go.
2017-07-04 06:39:18 +03:00
2018-10-28 21:30:18 +03:00
*Please note: Evio should not be considered as a drop-in replacement for the standard Go net or net/http packages.*
2017-11-05 01:34:07 +03:00
2017-07-04 06:39:18 +03:00
## Features
2018-05-24 02:49:45 +03:00
- [Fast ](#performance ) single-threaded or [multithreaded ](#multithreaded ) event loop
- Built-in [load balancing ](#load-balancing ) options
2017-11-02 15:22:44 +03:00
- Simple API
2017-07-04 06:39:18 +03:00
- Low memory usage
2017-11-14 21:56:15 +03:00
- Supports tcp, [udp ](#udp ), and unix sockets
2017-11-02 16:49:13 +03:00
- Allows [multiple network binding ](#multiple-addresses ) on the same event loop
- Flexible [ticker ](#ticker ) event
2017-11-02 16:52:35 +03:00
- Fallback for non-epoll/kqueue operating systems by simulating events with the [net ](https://golang.org/pkg/net/ ) package
2018-03-19 22:47:53 +03:00
- [SO_REUSEPORT ](#so_reuseport ) socket option
2017-07-04 06:39:18 +03:00
## Getting Started
### Installing
2017-10-29 01:14:40 +03:00
To start using evio, install Go and run `go get` :
2017-07-04 06:39:18 +03:00
```sh
2017-10-29 01:14:40 +03:00
$ go get -u github.com/tidwall/evio
2017-07-04 06:39:18 +03:00
```
This will retrieve the library.
### Usage
2018-05-25 01:34:14 +03:00
Starting a server is easy with `evio` . Just set up your events and pass them to the `Serve` function along with the binding address(es). Each connections is represented as an `evio.Conn` object that is passed to various events to differentiate the clients. At any point you can close a client or shutdown the server by return a `Close` or `Shutdown` action from an event.
2017-11-02 15:22:44 +03:00
Example echo server that binds to port 5000:
2017-10-29 01:42:19 +03:00
```go
2017-11-02 15:22:44 +03:00
package main
import "github.com/tidwall/evio"
func main() {
var events evio.Events
2018-05-24 02:49:45 +03:00
events.Data = func(c evio.Conn, in []byte) (out []byte, action evio.Action) {
2017-11-02 15:22:44 +03:00
out = in
return
}
if err := evio.Serve(events, "tcp://localhost:5000"); err != nil {
panic(err.Error())
}
}
2017-10-29 01:42:19 +03:00
```
2017-11-02 16:33:27 +03:00
Here the only event being used is `Data` , which fires when the server receives input data from a client.
2017-11-02 16:36:16 +03:00
The exact same input data is then passed through the output return value, which is then sent back to the client.
2017-11-02 15:22:44 +03:00
Connect to the echo server:
```sh
$ telnet localhost 5000
```
2017-11-02 16:33:27 +03:00
### Events
2017-11-02 15:22:44 +03:00
2017-11-02 16:33:27 +03:00
The event type has a bunch of handy events:
2017-11-02 15:22:44 +03:00
2017-11-02 16:33:27 +03:00
- `Serving` fires when the server is ready to accept new connections.
- `Opened` fires when a connection has opened.
- `Closed` fires when a connection has closed.
- `Detach` fires when a connection has been detached using the `Detach` return action.
- `Data` fires when the server receives new data from a connection.
2017-11-02 17:00:47 +03:00
- `Tick` fires immediately after the server starts and will fire again after a specified interval.
2017-11-02 15:22:44 +03:00
2017-11-02 16:33:27 +03:00
### Multiple addresses
2018-05-25 01:34:14 +03:00
A server can bind to multiple addresses and share the same event loop.
2017-11-02 15:22:44 +03:00
2017-11-02 16:33:27 +03:00
```go
evio.Serve(events, "tcp://192.168.0.10:5000", "unix://socket")
```
2017-11-02 15:22:44 +03:00
2017-11-02 16:49:13 +03:00
### Ticker
The `Tick` event fires ticks at a specified interval.
The first tick fires immediately after the `Serving` events.
```go
events.Tick = func() (delay time.Duration, action Action){
log.Printf("tick")
delay = time.Second
return
}
```
2018-05-24 02:49:45 +03:00
## UDP
2017-07-04 06:39:18 +03:00
2018-05-24 02:49:45 +03:00
The `Serve` function can bind to UDP addresses.
2017-10-29 22:42:44 +03:00
2018-05-24 02:49:45 +03:00
- All incoming and outgoing packets are not buffered and sent individually.
- The `Opened` and `Closed` events are not availble for UDP sockets, only the `Data` event.
2017-10-29 22:42:44 +03:00
2018-05-24 02:49:45 +03:00
## Multithreaded
2017-11-02 16:33:27 +03:00
2018-05-24 02:49:45 +03:00
The `events.NumLoops` options sets the number of loops to use for the server.
2018-05-25 01:34:14 +03:00
A value greater than 1 will effectively make the server multithreaded for multi-core machines.
Which means you must take care when synchonizing memory between event callbacks.
Setting to 0 or 1 will run the server as single-threaded.
2018-05-24 02:49:45 +03:00
Setting to -1 will automatically assign this value equal to `runtime.NumProcs()` .
2017-10-29 22:42:44 +03:00
2018-05-24 02:49:45 +03:00
## Load balancing
2017-11-14 21:42:15 +03:00
2018-05-24 02:49:45 +03:00
The `events.LoadBalance` options sets the load balancing method.
Load balancing is always a best effort to attempt to distribute the incoming connections between multiple loops.
This option is only available when `events.NumLoops` is set.
2017-11-14 21:42:15 +03:00
2018-05-24 02:49:45 +03:00
- `Random` requests that connections are randomly distributed.
- `RoundRobin` requests that connections are distributed to a loop in a round-robin fashion.
- `LeastConnections` assigns the next accepted connection to the loop with the least number of active connections.
2017-11-14 21:42:15 +03:00
2018-03-19 22:47:53 +03:00
## SO_REUSEPORT
Servers can utilize the [SO_REUSEPORT ](https://lwn.net/Articles/542629/ ) option which allows multiple sockets on the same host to bind to the same port.
Just provide `reuseport=true` to an address:
```go
evio.Serve(events, "tcp://0.0.0.0:1234?reuseport=true"))
```
2017-10-29 02:20:47 +03:00
## More examples
2017-07-04 06:39:18 +03:00
2018-07-12 21:04:11 +03:00
Please check out the [examples ](examples ) subdirectory for a simplified [redis ](examples/redis-server/main.go ) clone, an [echo ](examples/echo-server/main.go ) server, and a very basic [http ](examples/http-server/main.go ) server.
2017-10-29 02:20:47 +03:00
To run an example:
2017-11-02 23:29:13 +03:00
```sh
2017-10-29 02:20:47 +03:00
$ go run examples/http-server/main.go
2017-11-02 16:33:27 +03:00
$ go run examples/redis-server/main.go
$ go run examples/echo-server/main.go
2017-07-04 06:39:18 +03:00
```
## Performance
2017-11-04 03:20:42 +03:00
### Benchmarks
2017-07-04 06:39:18 +03:00
2017-11-04 03:20:42 +03:00
These benchmarks were run on an ec2 c4.xlarge instance in single-threaded mode (GOMAXPROC=1) over Ipv4 localhost.
Check out [benchmarks ](benchmarks ) for more info.
2017-07-04 06:39:18 +03:00
2017-11-04 03:22:01 +03:00
< img src = "benchmarks/out/echo.png" width = "336" height = "144" border = "0" alt = "echo benchmark" > < img src = "benchmarks/out/http.png" width = "336" height = "144" border = "0" alt = "http benchmark" > < img src = "benchmarks/out/redis_pipeline_1.png" width = "336" height = "144" border = "0" alt = "redis 1 benchmark" > < img src = "benchmarks/out/redis_pipeline_8.png" width = "336" height = "144" border = "0" alt = "redis 8 benchmark" >
2017-07-04 06:39:18 +03:00
## Contact
Josh Baker [@tidwall ](http://twitter.com/tidwall )
## License
2017-10-29 02:20:47 +03:00
`evio` source code is available under the MIT [License ](/LICENSE ).
2017-07-04 06:39:18 +03:00