Improve performance on Linux with many network interfaces #60
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The existing implementation of
New()has a performance issue on Linux for the case when there are a large number (~ thousands) of network interfaces on the system.Calling
Addrs()on anet.Interfacetriggers a netlink request (RTM_GETADDR) that dumps addresses for all network interfaces, then filters the response messages to the ones matching the specified interface. Wheniface.Addrs()is separately called on every item returned bynet.Interfaces(), this results in O(n2) data being sent through netlink, and can cause significant performance issues on systems managing thousands of network interfaces (virtual TAP devices, in my case).Ideally a fix will eventually be implemented upstream (see discussion), but in the meantime, a workaround is to collect all network addresses through a single netlink call and assign the addresses to each network interface by index. I've created a simple drop-in module at github.com/wjordan/netinterfaces to help apply the fix with minimal diff to the existing codebase (see the implementation here).
I've included a simple benchmark test against the
New()function, and compared the results before/after this PR on a single production host (with 1329 network interfaces):before (~8255 ms/op)
after (~141 ms/op)
-98.28%
$ benchstat go-netroute-master.txt go-netroute-perf_fix.txt goos: linux goarch: amd64 pkg: github.com/libp2p/go-netroute cpu: AMD EPYC 7502P 32-Core Processor │ go-netroute-master.txt │ go-netroute-perf_fix.txt │ │ sec/op │ sec/op vs base │ New-64 8255.0m ± 4% 141.8m ± 20% -98.28% (p=0.000 n=10)