Wednesday, November 1, 2017

HOW TO: Enable Socket SO_REUSEPORT for Shadowsocks-libev on Ubuntu 16.04 Server

Introduction and Summary:

     Shadowsocks is an encrypted proxy for circumventing firewalls and geo-location restrictions.  There is an option to enable SO_REUSEPORT based on the adjustments to the Linux kernel in version 3.9 in 2013.  This option seems to be most useful on a Shadowsocks server when handling many users ("millions of packets per second") in order to deal with congestion on a multi-core server.  Some applications see a speed increase of about 20% of traffic throughput on a congested server.  A Cloudflare engineer summarized it with these statements:

When this flag is set on a socket descriptor, Linux will allow many processes to bind to the same port. In fact, any number of processes will be allowed to bind and the load will be spread across them. With SO_REUSEPORT each of the processes will have a separate socket descriptor. Therefore each will own a dedicated UDP receive buffer."
In the author's summary (Marek Majkowski), he concluding by recommending the SO_REUSEPORT option be enabled by saying:

Ensure traffic is distributed evenly across many RX queues and SO_REUSEPORT processes. In practice, the load usually is well distributed as long as there are a large number of connections (or flows).
It seems that for SO_REUSEPORT to have a significant effect on network performance, the following would need to be true of a Shadowsocks server:

  1. There are many users connecting to the server
  2. The server is equipped with multiple CPU cores for handling traffic
  3. The OS is Linux running kernel 3.9 or higher (a technical requirement)

Matt Haigh reinforces my understanding when he said the following in a Stack Overflow thread:

[SO_REUSEPORT] was added during the 3.9 cycle in a series of patches by Tom Herbert, as you can see here, in order to better support multithreaded web servers.
...
And yes, you can use SO_REUSEPORT to bind a socket to the same address and port as another connection, as long as the initial connection also uses SO_REUSEPORT (and any other connections sharing the source address and port). This is done to prevent port hijacking by rogue applications.
Note: That being said, there seems to be no disadvantage to enabling it if you are connecting from a Linux client, like OpenWRT.  I've enabled it with no noticeable adverse effects.  Nevertheless it's hard for me to comment yet if it has a significant positive effect since very few people are using my server.

Prerequisites:

  • Linux Ubuntu 16.04 LTS Server
  • Linux Kernel must be > 3.9.0
  • Console Access
  • Root level permission

Instructions:

1. Simply add the following line to your config.json file (formatted to be in the middle of the config, not the end

  "reuse_port":true,

or add this option to the command line string if you are not using the config file:

  --reuse-port

As far as I can tell, there's nothing to enable in Linux.  If the process declare to the SO_REUSEPORT to the kernel, it will automatically load balance connections.

Blog Formatting Guide:


  • Commands written in Consolas in BLUE are LOCAL Client Shell Commands (I'm running an Ubuntu local client)
  • Commands written in Consolas in RED are REMOTE Server Shell Commands (usually in SSH)
  • All commands in BOLD are CUSTOM user variables that your should change for your configuration.

Helpful References, for Shadowsocks:

Shadowsocks-libev on Github
TCP Page on Ubuntu.com
SO_REUSEPORT Tech Briefing at lwn.net
Gitlabs report from a School in Illinois
Cloudflare blog post on SO_REUSEPORT
CTOLIB.COM's schematic drawing
Ubuntu MAN page on getsockopt
Ubuntu MAN page on Sockets
Github conversation on failback mentions REUSEPORT as "distributes datagrams evenly across all of the receiving threads."