diff --git a/README.md b/README.md index d6be54b..32a0daf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # rathole ![rathole-logo](./docs/img/rathole-logo.png) -A fast, secure and stable reverse proxy for NAT traversal, written in Rust +A secure, stable and high-performance reverse proxy for NAT traversal, written in Rust rathole, like [frp](https://github.com/fatedier/frp) and [ngrok](https://github.com/inconshreveable/ngrok), can help to expose the service on the device behind the NAT to the Internet, via a server with a public IP. @@ -131,13 +131,14 @@ If `RUST_LOG` is not present, the default logging level is `info`. ## Benchmark -rathole has similiar latency to [frp](https://github.com/fatedier/frp), but can handle more connections. Also it can provide much better bandwidth than frp. +rathole has similiar latency to [frp](https://github.com/fatedier/frp), but can handle a more connections, provide larger bandwidth, with less memory usage. See also [Benchmark](./docs/benchmark.md). +![http_throughput](./docs/img/http_throughput.svg) ![tcp_bitrate](./docs/img/tcp_bitrate.svg) - -![tcp_latency](./docs/img/tcp_latency.svg) +![udp_bitrate](./docs/img/udp_bitrate.svg) +![mem](./docs/img/mem-graph.png) ## Development Status diff --git a/benches/scripts/http/latency.sh b/benches/scripts/http/latency.sh new file mode 100644 index 0000000..d7e43c3 --- /dev/null +++ b/benches/scripts/http/latency.sh @@ -0,0 +1,24 @@ +#!/bin/sh +RATE="1 1000 2000 3000 4000" +DURATION="60s" + +RATHOLE="http://127.0.0.1:5202" +FRP="http://127.0.0.1:5203" + +echo warming up frp +echo GET $FRP | vegeta attack -duration 10s > /dev/null +for rate in $RATE; do + name="frp-${rate}qps-$DURATION.bin" + echo $name + echo GET $FRP | vegeta attack -rate $rate -duration $DURATION > $name + vegeta report $name +done + +echo warming up rathole +echo GET $RATHOLE | vegeta attack -duration 10s > /dev/null +for rate in $RATE; do + name="rathole-${rate}qps-$DURATION.bin" + echo $name + echo GET $RATHOLE | vegeta attack -rate $rate -duration $DURATION > $name + vegeta report $name +done diff --git a/benches/scripts/mem/mem.sh b/benches/scripts/mem/mem.sh new file mode 100644 index 0000000..2c1218e --- /dev/null +++ b/benches/scripts/mem/mem.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +rm -v *-mem.log + +echo frp +while true; do + ps -C frpc -o rsz= >> frpc-mem.log +sleep 1 +done & + +while true; do + ps -C frps -o rsz= >> frps-mem.log +sleep 1 +done & + +echo GET http://127.0.0.1:5203 | vegeta attack -duration 30s -rate 1000 > /dev/null + +sleep 10 + +kill $(jobs -p) + + +echo rathole + +pid_s=$(ps aux | grep "rathole -s" | head -n 1 | awk '{print $2}') +while true; do + ps --pid $pid_s -o rsz= >> ratholec-mem.log +sleep 1 +done & + +pid_c=$(ps aux | grep "rathole -c" | head -n 1 | awk '{print $2}') +while true; do + ps --pid $pid_c -o rsz= >> ratholes-mem.log +sleep 1 +done & + +echo GET http://127.0.0.1:5202 | vegeta attack -duration 30s -rate 1000 > /dev/null + +sleep 10 + +kill $(jobs -p) + +gawk -i inplace '{print $1 "000"}' frpc-mem.log +gawk -i inplace '{print $1 "000"}' frps-mem.log +gawk -i inplace '{print $1 "000"}' ratholec-mem.log +gawk -i inplace '{print $1 "000"}' ratholes-mem.log diff --git a/benches/scripts/mem/plot.plt b/benches/scripts/mem/plot.plt new file mode 100644 index 0000000..ee4a548 --- /dev/null +++ b/benches/scripts/mem/plot.plt @@ -0,0 +1,18 @@ +set title "Memory Usage" font ",20" + +set term png small size 800,600 +set key box outside + +set output "mem-graph.png" + +set ylabel "RSZ" +set format y '%.0s%cB' + +set ytics nomirror + +set yrange [0:*] + +plot "frps-mem.log" using 1 with lines axes x1y1 title "frps RSZ", \ + "frpc-mem.log" using 1 with lines axes x1y1 title "frpc RSZ", \ + "ratholes-mem.log" using 1 with lines axes x1y1 title "ratholes RSZ", \ + "ratholec-mem.log" using 1 with lines axes x1y1 title "ratholec RSZ" diff --git a/docs/benchmark.md b/docs/benchmark.md index 71816a1..4a62089 100644 --- a/docs/benchmark.md +++ b/docs/benchmark.md @@ -1,17 +1,19 @@ # Benchmark -> Date: 2021/12/14 +> Date: 2021/12/28 +> +> Version: commit 1180c7e538564efd69742f22e77453a1b74a5ed2 > -> Arch Linux with 5.15.7-arch1-1 kernel +> Arch Linux with 5.15.11-arch2-1 kernel > -> Intel i7-6600U CPU @ 2.60GHz +> Intel Xeon CPU E5-2620 @ 2.00GHz *2 > -> 20GB RAM +> 16GB RAM - -## Bitrate +## Bandwidth ![tcp_bitrate](./img/tcp_bitrate.svg) +![udp_bitrate](./img/udp_bitrate.svg) rathole with the following configuration: ```toml @@ -19,14 +21,20 @@ rathole with the following configuration: remote_addr = "localhost:2333" default_token = "123" -[client.services.foo1] +[client.services.bench-tcp] +local_addr = "127.0.0.1:80" +[client.services.bench-udp] +type = "udp" local_addr = "127.0.0.1:80" [server] bind_addr = "0.0.0.0:2333" default_token = "123" -[server.services.foo1] +[server.services.bench-tcp] +bind_addr = "0.0.0.0:5202" +[server.services.bench-udp] +type = "udp" bind_addr = "0.0.0.0:5202" ``` @@ -41,16 +49,20 @@ token = 1233 # frpc.ini [common] server_addr = 127.0.0.1 -#server_addr = 47.100.208.60 server_port = 7000 authentication_method = token token = 1233 -[ssh] +[bench-tcp] type = tcp local_ip = 127.0.0.1 local_port = 80 remote_port = 5203 +[bench-udp] +type = udp +local_ip = 127.0.0.1 +local_port = 80 +remote_port = 5203 ``` ``` @@ -71,17 +83,50 @@ For frp benchmark: $ iperf3 -c 127.0.0.1 -p 5203 ``` -## Latency +## HTTP nginx/1.20.2 listens on port 80, with the default test page. frp and rathole configuration is same with the previous section. -Using [ali](https://github.com/nakabonne/ali) with different rate. +[vegeta](https://github.com/tsenart/vegeta) is used to generate HTTP load. + +### HTTP Throughput + +The following commands are used to benchmark rathole and frp. Note that if you want to do a benchmark yourself, `-max-workers` should be adjusted to get the accurate results for your machine. -e.g. for rathole 10 QPS benchmark: ``` -ali -r 10 http://127.0.0.1:5202 +echo 'GET http://127.0.0.1:5203' | vegeta attack -rate 0 -duration 30s -max-workers 48 +echo 'GET http://127.0.0.1:5202' | vegeta attack -rate 0 -duration 30s -max-workers 48 ``` -![tcp_latency](./img/tcp_latency.svg) +![http_throughput](./img/http_throughput.svg) + +### HTTP Latency + +`rathole` has very similar latency to `frp`, but can handle more connections + +Here's a table, latency is in ms + +|QPS|latency(rathole)|latency(frp)| +|--|--|---| +|1|2.113|2.55| +|1000|1.723|1.742| +|2000|1.845|1.749| +|3000|2.064|2.011| +|4000|2.569|7907| + +As you can see, for QPS from 1 to 3000, rathole and frp have nearly identical latency. +But with QPS of 4000, frp starts reporting lots of errors and the latency grows to even seconds. This kind of reflects the throughput in the previous section. + +Thus, in terms of latency, rathole and frp are nearly the same. But rathole can handle more connections. + +[Script to benchmark latency](../benches/scripts/http/latency.sh) + +## Memory Usage + +![mem](./img/mem-graph.png) + +rathole uses much less memory than frp. + +[Script to benchmark memory](../benches/scripts/mem/mem.sh) diff --git a/docs/img/http_throughput.svg b/docs/img/http_throughput.svg new file mode 100644 index 0000000..02f7c18 --- /dev/null +++ b/docs/img/http_throughput.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/img/mem-graph.png b/docs/img/mem-graph.png new file mode 100644 index 0000000..c355803 Binary files /dev/null and b/docs/img/mem-graph.png differ diff --git a/docs/img/tcp_bitrate.svg b/docs/img/tcp_bitrate.svg index 6a3065a..e7f8374 100644 --- a/docs/img/tcp_bitrate.svg +++ b/docs/img/tcp_bitrate.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/img/tcp_latency.svg b/docs/img/tcp_latency.svg deleted file mode 100644 index 172e802..0000000 --- a/docs/img/tcp_latency.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/img/udp_bitrate.svg b/docs/img/udp_bitrate.svg new file mode 100644 index 0000000..891f4a6 --- /dev/null +++ b/docs/img/udp_bitrate.svg @@ -0,0 +1 @@ + \ No newline at end of file