Getting beyond 10k qps?


I’ve been experimenting with higher traffic servers running on VM’s. I’ve tried FreeBSD and Ubuntu, I’ve played with ntpsec, legacy ntp and chrony. In all cases I max out around 60% cpu and 10-12k qps and then start dropping packets. All the ntp implementations seem to be single thread so adding cores doesn’t help (I tried it just in case the net stack might end up on a different thread, it didn’t). Digital ocean seems to behave a bit better than linode (plus they don’t actually measure the bandwidth) but neither do that well.

If the load were relatively stable I could tune the bandwidth settings but it’s very spiky, I saw a 40k qps 10 min spike on my Bangalore server yesterday. My singapore server has +/- 80% traffic swings in an hour.

Has anybody managed to get beyond the 10-12 k qps range on a VM and if so what setup are you using?

Has anybody done any work on a multithreaded server?


In my tests about 6 months ago I didn’t have much success in pushing multicore servers for server higher NTP traffic loads. In the end I built a docker NTP container and by running multiple containers on a physical box was able to load it up fairly well.

You need to run a load balancer or multiple public IPs to distribute the queries across the containers.


My CentOS 7 server in Singapore handles an avg of 30k qps per day, with 5 minute peaks of 50+k qps with standard ntpd. and have some stats. has the CPU load graphs (one core until week 12, two cores thereafter, so ntpd takes around 35-40% of a single CPU core at 30k qps). At this rate I would consume some 6TB/month, but I guess I’ll need to change to a lower netspeed setting to keep my bandwidth consumption below my 4TB/month limit. Of course they have plans with higher tranfer limits, but those cost more. The 4TB/month package is $20.

The VM is from UpCloud. If you want to try, see
They have servers in Frankfurt, Helsinki, Amsterdam, Singapore, London and Chicago.

(full disclosure: “You can earn bonus credits to your UpCloud account by sharing your unique referral link or code with your friends. For every new user who signs up using your referral code and makes at least the minimum one time payment, you will receive $50 worth of free credits. Every new user also receives a bonus worth of $25 credits when signing up through the referral program.”)


There is a multithreaded NTP server written in Rust I was playing with some time ago:

On a VMware guest I have in the pool the maximum throughput improved from about 55kpps to 110kpps. The average rate is about 2kpps (with the maximum speed setting), so it only made a difference for spikes happening on midnight, like this one: (rsntp wasn’t running here, so it responded only to about 55kpps).

Please note that the CPU utilization doesn’t scale linearly with traffic. With interrupt coalescing the kernel can process multiple packets per interrupt, so an NTP server should be able to handle more than double of what it can handle at 50% utilization, even if it is single-threaded.


I wondered who the other operators in Singapore were — the traffic volume is stupendous. I’m staring at 2.5TB/month inbound (5TB month inbound+outbound). I’m running FreeBSD 11 with 2 core and stock ntpd. I did see dropped packets during spikes when I had one vCPU, but I upgraded to two and I haven’t seen them since.


I just upgraded my singapore digital ocean droplet to a three core 1GB ($15/month). I also flipped it to run rsntp from @mlichvar (

What’s interesting about singapore is how spiky the usage is:


I have the same 3 core setup in Bangalore that that really sees some traffic. I’ve seen 75k/qps peaks. and it’s handing about 2 billion requests a day (that was at 500M setting on ipv4, I just turned it up to the full 1G)


Both of these machine are not doing much beyond ntp. rsntp seems to work really well. Here is the CPU usage for the Bangalore machine for the same 24 hrs.


The only weirdness I saw was rsntp would not play nice with the floating IP setup Digital Ocean uses, not sure why, Regular NTP and Chrony both handle it fine.


My guess is that the high-traffic parts correspond to times when your address was returned by DNS and the low-traffic parts are clients that remember the address (like NTP clients are supposed do). There is a small number of servers in the zone, so the duty cycle is large.

What sampling interval do you use? I use collectd with the iptables plugin using 1-second interval, which shows all spikes very clearly.

One difference is that rsntp may not respond from the same address as the request was received on. It relies on system routing configuration. Is it possible that the default route used a different address in the “floating” setup? I think a new option to bind the rsntp’s sockets to specified addresses would help with that.


My guess is that the high-traffic parts correspond to times when your address was returned by DNS and the low-traffic parts are clients that remember the address (like NTP clients are supposed do). There is a small number of servers in the zone, so the duty cycle is large.

Probably true, I’m guessing with the Bangalore server I’m in the cycle pretty much 100% the time which is why it look more even. Those grabs are screen grabs from the digital ocean console - not sure what the sampling is, if I had to guess I’d say 1 min. Putting real monitoring on the boxes is one of my tasks for this weekend.

Regarding rsntp yeah I think that’s it, the wrong IP in the reply. I don’t think binding a specific address will help this, the address in question isn’t aliased to an interface. I’m not sure what legacy ntp and chrony are doing that’s different, rust isn’t once of my languages so I’ll probably punt for now.


In order to respond with a correct source address, ntpd binds a socket to all local addresses and chronyd sets the address for each packet using the PKTINFO control message. I’m not sure how would I do the latter in Rust, so I added an option to rsntp to bind its sockets to a specified address if you want to try it. I think it should help.