Giter Site home page Giter Site logo

zabrane / tcpserver Goto Github PK

View Code? Open in Web Editor NEW

This project forked from maurice2k/tcpserver

0.0 1.0 0.0 430 KB

High performance Golang IPv4 and IPv6 capable TCP server with TLS support, graceful shutdown and TCP FastOpen

License: MIT License

Shell 20.70% Go 67.83% Gnuplot 11.47%

tcpserver's Introduction

tcpserver

tcpserver is an extremely fast and flexible IPv4 and IPv6 capable TCP server with TLS support, graceful shutdown, Zero-Copy (on Linux with splice/sendfile) and supports TCP tuning options like TCP_FASTOPEN, SO_REUSEPORT and TCP_DEFER_ACCEPT.

This library requires at least Go 1.11 but has no other dependencies, does not contain ugly and incompatible hacks and thus fully integrates into Go's net/* universe.

Architecture

tcpserver uses a multi-accept-loop approach combined with an adaptive spawning go routine pool for incoming connections.

Each connection lives in it's own go routine and it served using a request handler function (RequestHandlerFunc func(conn tcpserver.Connection)). The connection is automatically closed when the request handler function returns.

Memory allocations in hot paths are reduced to a minimum using sync.Pool and the go routine pool from maurice2k/ultrapool

As tcpserver does not implement a non-blocking/asynchronous event loop itself (like packages such as evio or gnet) it is fully compatible with everything that is built on top of net.TCPConn.

Example (echo server)

server, err := tcpserver.NewServer("127.0.0.1:5000")

server.SetRequestHandler(requestHandler)
server.Listen()
server.Serve()

func requestHandler(conn tcpserver.Connection) {
    io.Copy(conn, conn)
}

Benchmarks

Benchmarks are always tricky, especially those that depend on network operations. I've tried my best to get fair and realistic results (given that these benchmarks are of course very synthetic).

The test server, an AWS c5.metal dual Intel(R) Xeon(R) Platinum 8275CL CPU @ 3.00GHz machine with a total of 96 cores and 192 GB of memory, was installed with latest Amazon Linux 2, Linux Kernel 4.14.214-160.339.amzn2.x86_64 and Golang 1.16. There were no other network daemons running except for SSH.

The tests are performed using a super simple HTTP server implementation on top of tcpserver and the other tested libraries. HTTP is well known, there are good benchmarking tools and it's easy to test throughput (using HTTP Keep-Alive) as well as handling thousands of short-lived connections.

Bombardier (version 1.2.5 from 2020-10-15) was used as HTTP benchmarking tool.

The following libraries were benchmarked:

All tests were performed against localhost.

Hint: If you're looking for a high performant HTTP library, just use fasthttp. It is extremly fast and has extraordinary good HTTP support. The second best option is probably to stick to net/http. evio, gnet and tcpserver are primarily designed for other use cases like your own protocols, proxy servers and the like. Don't re-invent the wheel ;)

Test #1: Static 1kB content massive connections test

1000 concurrent clients, 1kB of HTTP payload returned, Keep-Alive turned off, 10 seconds (each HTTP request is a new connection). Test 01

Test #1.1 (with TLS): Static 1kB content massive connections test

1000 concurrent clients, 1kB of HTTP payload returned, Keep-Alive turned off, 10 seconds (each HTTP request is a new connection).
Only net/http, fasthttp and tcpserver have been benchmarked, as evio and gnet do not support TLS. Test 01

Test #2: Static 1kB content throughput test

1000 concurrent clients, 1kB of HTTP payload returned, Keep-Alive turned on, 10 seconds (establishes exactly 1000 TCP connections that are serving HTTP requests). Test 02

Test #2.1 (with TLS): Static 1kB content throughput test

1000 concurrent clients, 1kB of HTTP payload returned, Keep-Alive turned on, 10 seconds (establishes exactly 1000 TCP connections that are serving HTTP requests).
Only net/http, fasthttp and tcpserver have been benchmarked, as evio and gnet do not support TLS. Test 02

Test #3: AES-128-CBC crypted 1kB content massive connections test

1000 concurrent clients, 1kB of AES-128-CBC crypted HTTP payload returned, Keep-Alive turned off, 10 seconds (each HTTP request is a new connection). Test 03

Test #4: AES-128-CBC crypted 1kB content throughput test

1000 concurrent clients, 1kB of AES-128-CBC crypted HTTP payload returned, Keep-Alive turned on, 10 seconds (establishes exactly 1000 TCP connections that are serving HTTP requests). Test 04

Test #5: Static 128 byte content throughput test with additional 1ms sleep

1000 concurrent clients, 128 bytes of HTTP payload returned and 1 ms sleep, Keep-Alive turned on, 10 seconds (establishes exactly 1000 TCP connections that are serving HTTP requests). Test 05

Test #6: Static 16kB content massive connections test

1000 concurrent clients, 16kB of HTTP payload returned, Keep-Alive turned off, 10 seconds (each HTTP request is a new connection). Test 06

Why?

I always find it enlightening to know why someone did something. That's why this section is here.

When I started writing a new high performance SOCKS5 and HTTP proxy server to replace danted in my setup, I realized that I needed some functionality that goes beyond the core listen-accept-handle logic like graceful restart/shutdown and strict error handling.

I evaluated evio and later gnet but that reminded me of doing async IO in PHP a decade ago which might have been a necessity there but Go has it's own event loop and I was curious why one would re-implement all this in a client library and relinquish the way you write network code in Go (basically by using a goroutine per connection) โ€“ the answer is was speed.

I started benchmarking the mentioned libraries against a naive go handle(...) approach and it soon turned out that spawning a new goroutine for each connection was simply too expensive. After creating a new goroutine worker pool (modeled after the one found in fasthttp) I was able to reach numbers (in reqs/sec) that were on par with these libraries.

Now, after some rounds of optimization, tcpserver is faster in almost all benchmarks than any other library I've come across and you get zero-copy and TLS "for free" โ€“ simply by using Go's own net/* functionality!

License

tcpserver is available under the MIT license.

tcpserver's People

Contributors

maurice2k avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.