irrdnet / irrd

IRRd version 4
http://irrd.readthedocs.io/en/stable/
Other
154 stars 50 forks source link

performance decrease from 4.0.8 to 4.1.0b4 #338

Closed ccaputo closed 4 years ago

ccaputo commented 4 years ago

In https://github.com/irrdnet/irrd/issues/323 I mentioned a performance decrease going from 4.0.8 to 4.1.0b4:

NOTE: I have tested the quality of the results, with respect to the many thousands of queries we perform to inform our route servers. While the data with 4.1.0b4 is good as compared to 4.0.8, I am finding 4.1.0b4 to be considerably slower. As an example, we perform about 12k !gas## and 9.6k !6as### queries every hour. With 4.0.8 this process takes under 4 minutes, but with 4.1.0b4 it is taking over 14 minutes. Any idea as to why the slowdown?

Roughly: !! has gone from as low as 0.0002 secs to as low as 0.0243 secs, or about a 121x slowdown. Since bgpq4 performs a !! upon each connection, this performance decrease appears to account for about 8.7 minutes of the change from <4 minutes to >14 minutes, since it is performed some ~21.6k times.

Roughly: !gas6456 has gone from as low as 0.0002 secs to as low as 0.0044 secs, or about a 22x slowdown.

Roughly: !a4AS-PCH has gone from as low as 0.0114 secs to as low as 0.0210 secs, or about a 1.8x slowdown.

Details below...

4.0.8:

2020-06-28 03:43:01,263 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54878: sent answer to query, elapsed 0.00028738006949424744s, 0 bytes: !!
2020-06-28 03:43:01,268 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54880: sent answer to query, elapsed 0.0002026669681072235s, 0 bytes: !!
2020-06-28 03:43:01,300 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54882: sent answer to query, elapsed 0.0002654418349266052s, 0 bytes: !!
2020-06-28 03:43:01,313 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54884: sent answer to query, elapsed 0.0002828110009431839s, 0 bytes: !!
2020-06-28 03:43:01,330 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54886: sent answer to query, elapsed 0.00021976418793201447s, 0 bytes: !!
2020-06-28 03:43:01,367 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54888: sent answer to query, elapsed 0.00023167207837104797s, 0 bytes: !!
2020-06-28 03:43:01,368 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54890: sent answer to query, elapsed 0.0003458317369222641s, 0 bytes: !!
2020-06-28 03:43:01,377 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54892: sent answer to query, elapsed 0.00022383593022823334s, 0 bytes: !!
2020-06-28 03:43:01,419 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54894: sent answer to query, elapsed 0.0003698691725730896s, 0 bytes: !!
2020-06-28 03:43:01,419 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54896: sent answer to query, elapsed 0.0005960073322057724s, 0 bytes: !!

4.1.0b4:

2020-06-29 01:56:53,227 irrd[20546]: [irrd.server.whois.server#INFO] 2001:db8::2:34408: sent answer to query, elapsed 0.02433917112648487s, 0 bytes: !!
2020-06-29 01:56:53,264 irrd[20552]: [irrd.server.whois.server#INFO] 2001:db8::2:34410: sent answer to query, elapsed 0.02430717647075653s, 0 bytes: !!
2020-06-29 01:56:53,301 irrd[20558]: [irrd.server.whois.server#INFO] 2001:db8::2:34412: sent answer to query, elapsed 0.02486383728682995s, 0 bytes: !!
2020-06-29 01:56:53,338 irrd[20564]: [irrd.server.whois.server#INFO] 2001:db8::2:34414: sent answer to query, elapsed 0.02445606142282486s, 0 bytes: !!
2020-06-29 01:56:53,375 irrd[20570]: [irrd.server.whois.server#INFO] 2001:db8::2:34416: sent answer to query, elapsed 0.02446768432855606s, 0 bytes: !!
2020-06-29 01:56:53,412 irrd[20576]: [irrd.server.whois.server#INFO] 2001:db8::2:34418: sent answer to query, elapsed 0.024382468312978745s, 0 bytes: !!
2020-06-29 01:56:53,449 irrd[20582]: [irrd.server.whois.server#INFO] 2001:db8::2:34420: sent answer to query, elapsed 0.024394378066062927s, 0 bytes: !!
2020-06-29 01:56:53,489 irrd[20588]: [irrd.server.whois.server#INFO] 2001:db8::2:34422: sent answer to query, elapsed 0.026896363124251366s, 0 bytes: !!
2020-06-29 01:56:53,526 irrd[20594]: [irrd.server.whois.server#INFO] 2001:db8::2:34424: sent answer to query, elapsed 0.02438173070549965s, 0 bytes: !!
2020-06-29 01:56:53,563 irrd[20600]: [irrd.server.whois.server#INFO] 2001:db8::2:34426: sent answer to query, elapsed 0.024390466511249542s, 0 bytes: !!

4.0.8:

2020-06-28 03:43:07,207 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:55310: sent answer to query, elapsed 0.02729269489645958s, 70 bytes: !gas6456
2020-06-28 03:43:19,216 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:56494: sent answer to query, elapsed 0.001042388379573822s, 70 bytes: !gas6456
2020-06-28 04:43:07,830 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:52356: sent answer to query, elapsed 0.027271945029497147s, 70 bytes: !gas6456
2020-06-28 04:43:19,009 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:53544: sent answer to query, elapsed 0.00019405968487262726s, 70 bytes: !gas6456
2020-06-28 05:43:07,979 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:49452: sent answer to query, elapsed 0.0004536546766757965s, 70 bytes: !gas6456
2020-06-28 05:43:18,895 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:50624: sent answer to query, elapsed 0.00019918940961360931s, 70 bytes: !gas6456
2020-06-28 06:43:07,383 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:46568: sent answer to query, elapsed 0.00024922750890254974s, 70 bytes: !gas6456
2020-06-28 06:43:19,317 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:47748: sent answer to query, elapsed 0.00019770488142967224s, 70 bytes: !gas6456
2020-06-28 07:43:08,438 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:43710: sent answer to query, elapsed 0.010762613266706467s, 70 bytes: !gas6456
2020-06-28 07:43:18,948 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:44836: sent answer to query, elapsed 0.00019381940364837646s, 70 bytes: !gas6456

4.1.0b4:

2020-06-29 00:43:07,654 irrd[9102]: [irrd.server.whois.server#INFO] 2001:db8::2:46894: sent answer to query, elapsed 0.005093555897474289s, 70 bytes: !gas6456
2020-06-29 00:43:22,735 irrd[14720]: [irrd.server.whois.server#INFO] 2001:db8::2:48390: sent answer to query, elapsed 0.004684131592512131s, 70 bytes: !gas6456
2020-06-29 01:43:07,671 irrd[12836]: [irrd.server.whois.server#INFO] 2001:db8::2:43948: sent answer to query, elapsed 0.00542367622256279s, 70 bytes: !gas6456
2020-06-29 01:43:24,523 irrd[21831]: [irrd.server.whois.server#INFO] 2001:db8::2:45472: sent answer to query, elapsed 0.007576672360301018s, 70 bytes: !gas6456

4.0.8:

2020-06-28 03:43:01,282 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54878: sent answer to query, elapsed 0.017773814499378204s, 8985 bytes: !a4AS-PCH
2020-06-28 03:43:26,488 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:57658: sent answer to query, elapsed 0.04186972416937351s, 8985 bytes: !a4AS-PCH
2020-06-28 04:43:01,500 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:51946: sent answer to query, elapsed 0.0122409388422966s, 8985 bytes: !a4AS-PCH
2020-06-28 04:43:26,435 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:54760: sent answer to query, elapsed 0.012211363762617111s, 8985 bytes: !a4AS-PCH
2020-06-28 05:43:01,686 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:49024: sent answer to query, elapsed 0.023198403418064117s, 8985 bytes: !a4AS-PCH
2020-06-28 05:43:26,217 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:51824: sent answer to query, elapsed 0.013118261471390724s, 8985 bytes: !a4AS-PCH
2020-06-28 06:43:01,152 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:46140: sent answer to query, elapsed 0.01144973374903202s, 8985 bytes: !a4AS-PCH
2020-06-28 06:43:25,543 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:48732: sent answer to query, elapsed 0.011795494705438614s, 8985 bytes: !a4AS-PCH
2020-06-28 07:43:01,968 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:43244: sent answer to query, elapsed 0.014664269983768463s, 8985 bytes: !a4AS-PCH
2020-06-28 07:43:26,750 irrd[30148]: [irrd.server.whois.query_pipeline#INFO] [2001:db8::2]:46268: sent answer to query, elapsed 0.013527363538742065s, 8985 bytes: !a4AS-PCH

4.1.0b4:

2020-06-28 23:06:03,210 irrd[30485]: [irrd.server.whois.server#INFO] 2001:db8::2:59472: sent answer to query, elapsed 0.021601224318146706s, 8985 bytes: !a4AS-PCH
2020-06-28 23:06:25,620 irrd[5463]: [irrd.server.whois.server#INFO] 2001:db8::2:59602: sent answer to query, elapsed 0.021016258746385574s, 8985 bytes: !a4AS-PCH
2020-06-29 00:43:01,499 irrd[7768]: [irrd.server.whois.server#INFO] 2001:db8::2:46466: sent answer to query, elapsed 0.028586994856595993s, 8985 bytes: !a4AS-PCH
2020-06-29 00:43:27,047 irrd[16825]: [irrd.server.whois.server#INFO] 2001:db8::2:48896: sent answer to query, elapsed 0.026688432320952415s, 8985 bytes: !a4AS-PCH
2020-06-29 01:43:01,489 irrd[9097]: [irrd.server.whois.server#INFO] 2001:db8::2:43534: sent answer to query, elapsed 0.023557476699352264s, 8985 bytes: !a4AS-PCH
2020-06-29 01:43:28,763 irrd[23279]: [irrd.server.whois.server#INFO] 2001:db8::2:45952: sent answer to query, elapsed 0.02309502847492695s, 8985 bytes: !a4AS-PCH
mxsasha commented 4 years ago

Thanks for sharing this data. Sounds like the focus should first be on the !! queries, as they are the bulk of the performance impact.

Background on this: 4.0 was multi-threaded. Threads are cheap, and share their memory. IRRd has a preload store which contains the data to answer !g/6 queries, and therefore the second half of !a queries, as they are a combination of !i and !g/6. The preload store was an in-memory dictionary, which is really fast and allowed when using threads.

However, in a single Python process only a single thread can be active at the same time, i.e. all of IRRd 4.0 is capped to a single CPU core. Especially with adding RPKI support, the concurrent CPU usage is just too high for that, so 4.1 is multiprocess. This means concurrent processes in IRRd don't fight over CPU time anymore.

Multiprocessing makes sharing a dict in memory quite painful, so this data is now stored in Redis. This has a slightly higher latency, and this is some of the impact you're seeing. There is a mitigation for this: once a query handler has seen more than 5 queries that benefit from preloading on the same connection, it'll load the entire Redis store into local memory, which is much faster, with the expectation that more will follow and it's worth to spend time loading the data.

So performance with concurrent processes (including mirroring) is improved, but with a small latency cost.

Are you already using a unix socket to connect to Redis? TCP connections to Redis are supported, but have a much higher latency.

On why the !! queries are slower, which is the most significant issue in your use case, I'm puzzled. My first thought was a delay caused by process management, but the elapsed time that is logged purely concerns the handling of that specific query - not the initialisation of the query parser or anything that precedes it. I will dig deeper.

mxsasha commented 4 years ago

@ccaputo follow up question: are you using a unix socket for PostgreSQL, or TCP?

It looks like part of the delay may be connecting to the SQL database, which 4.1 does upon processing the first query, hence it affecting the !! response time. Previously we used connection pooling, but those pools can not be shared across processes.

ccaputo commented 4 years ago

Are you already using a unix socket to connect to Redis? TCP connections to Redis are supported, but have a much higher latency.

@ccaputo follow up question: are you using a unix socket for PostgreSQL, or TCP?

I am using a unix socket for both:

irrd:
    database_url: 'postgresql://[...]@/irrd'
    redis_url: 'unix:///tmp/redis.sock'

It looks like part of the delay may be connecting to the SQL database, which 4.1 does upon processing the first query, hence it affecting the !! response time. Previously we used connection pooling, but those pools can not be shared across processes.

Since !! along with the client version command !n are common startup commands that don't involve database lookups, could they along with any other unsophisticated immediately processable commands, be handled in the main TCP handler while for !! concurrently/asynchronously triggering any needed redis/postgres connections due to the expectation of subsequent commands?

In case useful, this is what multiple unsophisticated commands in a row in a single TCP session look like:

2020-06-30 15:09:15,152 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.02561289630830288s, 0 bytes: !!
2020-06-30 15:09:16,165 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.004909427836537361s, 0 bytes: !!
2020-06-30 15:09:17,311 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.004914136603474617s, 0 bytes: !!
2020-06-30 15:09:18,246 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.005097845569252968s, 0 bytes: !!
2020-06-30 15:09:37,438 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.004980882629752159s, 2 bytes: !nfoo
2020-06-30 15:09:45,628 irrd[11379]: [irrd.server.whois.server#INFO] 2001:db8::2:41728: sent answer to query, elapsed 0.005041765049099922s, 2 bytes: !nfoo

Note that the !! after the first one takes around 0.0049 seconds, which is still 25 times slower than the 0.0002 seconds it takes with 4.0.8, thus it would still add 1.8 minutes to the ~21.6k bgpq4 connections mentioned above, but maybe if short-circuit handled in the TCP handler, that would go away.

Thank you.

mxsasha commented 4 years ago

Since !! along with the client version command !n are common startup commands that don't involve database lookups, could they along with any other unsophisticated immediately processable commands, be handled in the main TCP handler while for !! concurrently/asynchronously triggering any needed redis/postgres connections due to the expectation of subsequent commands?

I think for most use cases this would not have a significant effect. Right after someone does !! they'll likely send a query that uses the database, which means the delay will just move to that next query.

The approach I'm thinking of now is to use a pool of worker processes instead. These can keep a local cache of the preload data in-memory, and will already have a database connection. So this eliminates almost all of the forking, database connection, and Redis latency. It will increase the idle load a bit, but I don't expect that to have any negative impact. The upside of this approach is that it will also be useful for the HTTP API. However, it's somewhat complex, so I'm going to do some experimentation and see what the options are.

ccaputo commented 4 years ago

Since !! along with the client version command !n are common startup commands that don't involve database lookups, could they along with any other unsophisticated immediately processable commands, be handled in the main TCP handler while for !! concurrently/asynchronously triggering any needed redis/postgres connections due to the expectation of subsequent commands?

I think for most use cases this would not have a significant effect. Right after someone does !! they'll likely send a query that uses the database, which means the delay will just move to that next query.

The approach I'm thinking of now is to use a pool of worker processes instead. These can keep a local cache of the preload data in-memory, and will already have a database connection. So this eliminates almost all of the forking, database connection, and Redis latency. It will increase the idle load a bit, but I don't expect that to have any negative impact. The upside of this approach is that it will also be useful for the HTTP API. However, it's somewhat complex, so I'm going to do some experimentation and see what the options are.

Sounds good!

mirceaulinic commented 4 years ago

Just wanted to share some thoughts, not sure that's what you had in mind already... Re:

The approach I'm thinking of now is to use a pool of worker processes instead. These can keep a local cache of the preload data in-memory, and will already have a database connection.

A typical good approach for this would be using a pool of worker processes, as you mentioned, where 1 (or more) are specifically designated to keep the cache data in-memory and the database connection, while the rest handle the queries. The query serving processes communicate via a bi-drectional multi-processing queue with the cache worker(s) (or even a ZMQ IPC bus, which I personally like very much, but would add another dependency) to exchange data. This would avoid having many database connections.

Whatever the architecture you decide on, I'd give a big 👍 to anything that avoids Redis for this particular use case (although a big fan otherwise). Cheers!

mxsasha commented 4 years ago

A typical good approach for this would be using a pool of worker processes, as you mentioned, where 1 (or more) are specifically designated to keep the cache data in-memory and the database connection, while the rest handle the queries. The query serving processes communicate via a bi-drectional multi-processing queue with the cache worker(s) (or even a ZMQ IPC bus, which I personally like very much, but would add another dependency) to exchange data. This would avoid having many database connections.

I am reluctant about this, because I'm concerned every kind of intermediary will actually add latency. Even something as basic as multiprocessing Pipe seems to easily add 100-200 microseconds, which is just too long.

343 is ongoing work for this. The new implementation has a long-running worker per client connection. The worker retains the database connection, so no connection latency. It also keeps an in-memory cache of all preload data, i.e. the lowest possible access latency. The data is stored in dicts which allow fast lookups, but aren't shareable between processes.

This works and it's fast. The downside is that the part of in-memory preloading to avoid Redis uses a lot of memory, around 400 MB per long-running worker. So if you use the default of 50 simultaneous connections, you're looking at 20 GB memory use just for the whois server.

Thoughts on moving forward:

mirceaulinic commented 4 years ago

Even something as basic as multiprocessing Pipe seems to easily add 100-200 microseconds, which is just too long.

I don't find it that long. If that's the price paid for not having to allocate a huge amount of resources just for running a whois server (yes, I do find 20GB huge, no exaggeration, honestly), I'll take that: I prefer to have my server running at a decent 1-2GB (as it's currently running requiring in my setup) and return my queries in 0.102s instead of 0.100s - and save the rest 18GB for other apps. 🙂

job commented 4 years ago

Dear Mircea, can you describe your deployment and purpose for the software a bit more? Which organization is this for? It is possible you are using irrd for a different objective than what others in this thread are using irrd for. Irrd v4 is pretty young software and we don't know the user base well yet.

In some deployments (such as NTT's) it is considered acceptable to burn memory like there is no tomorrow. We have to turn it all up to eleven because RR.NTT.NET is one of the worlds largest and busiest irrd servers.

Perhaps in the future we can add a button to make it easier for the operator to choose whether to optimise for speed or memory.

mirceaulinic commented 4 years ago

Hi @job. We (DigitalOcean) are using IRRd for our internal whois server, currently only mirroring several sources (so no export at the moment). We're using the local whois server mostly for !g, !6 or !i queries (for generating IRR-based prefix lists), which I understand is also the use-case reported in this thread.

I've noticed that the memory usage was around 14GB during the initial full import, afterwards settled to around 1.5GB which I'm very happy with. That said, if I were to upgrade to IRRd 4.1.0, jumping to over 20GB for the same functionality would be a little bit difficult to justify. (That is, without having to reduce the performances by decreasing the number of workers -- which, based on @mxsasha's clarification above, would need to be reduced to 4 workers for the equivalent resource allocation as of now).

Perhaps in the future we can add a button to make it easier for the operator to choose whether to optimise for speed or memory.

Could be an alternative, for sure, although I worry that might overly complicate the implementation... either way totally your call, just wanted to share my perspective as an user, that I'd easily sacrifice a total of 2 seconds for every 10000 queries, rather than having to allocate several times more resources.

job commented 4 years ago

You may want to look at the !a query (this is what bgpq4 uses) to speed things up a bit.

mxsasha commented 4 years ago

I was actually able to save more memory than initially expected. The workers are now at 162MB in my test setup. That's low enough that we don't need to support separate modes for different priorities. If you want to run IRRd with less memory consumption, you can set a lower server.whois.max_connections. I have also updated the default for this setting to 10, so that by default, the whois workers will use around 1.6 GB (with the current codebase).

I think this is a reasonable balance - if you want to run IRRd in low memory setups, a maximum of 10 connections seems reasonable. Because that usually pairs with having limited CPU cores available, which means you won't be able to benefit from many simultaneous queries anyways.

mxsasha commented 4 years ago

I believe this is fixed in https://github.com/irrdnet/irrd/commit/027f7806d47e084dc799d413c55bc980cac181b2 - it will be included in the next beta release.

ccaputo commented 4 years ago

Initial speed tests post 027f7806d47e084dc799d413c55bc980cac181b2 are very promising!:

2020-07-06 16:40:58,178 irrd[8652]: [irrd.server.whois.server#INFO] 2001:db8::2:37942: sent answer to query, elapsed 0.00015023350715637207s, 0 bytes: !!
2020-07-06 16:51:42,169 irrd[8700]: [irrd.server.whois.server#INFO] 2001:db8::2:39024: sent answer to query, elapsed 0.00012947618961334229s, 0 bytes: !!
2020-07-06 16:56:36,800 irrd[8612]: [irrd.server.whois.server#INFO] 2001:db8::2:39440: sent answer to query, elapsed 0.00010169669985771179s, 0 bytes: !!
2020-07-06 16:57:20,684 irrd[8624]: [irrd.server.whois.server#INFO] 2001:db8::2:39524: sent answer to query, elapsed 0.00015059858560562134s, 0 bytes: !!
2020-07-06 16:57:29,200 irrd[8626]: [irrd.server.whois.server#INFO] 2001:db8::2:39530: sent answer to query, elapsed 0.0001093689352273941s, 0 bytes: !!
2020-07-06 16:59:46,723 irrd[8645]: [irrd.server.whois.server#INFO] 2001:db8::2:39744: sent answer to query, elapsed 0.00014530867338180542s, 0 bytes: !!
2020-07-06 17:00:57,210 irrd[8656]: [irrd.server.whois.server#INFO] 2001:db8::2:39840: sent answer to query, elapsed 0.00014537200331687927s, 0 bytes: !!
2020-07-06 17:07:01,912 irrd[8682]: [irrd.server.whois.server#INFO] 2001:db8::2:40408: sent answer to query, elapsed 0.00020211189985275269s, 0 bytes: !!

Currently blocked by https://github.com/irrdnet/irrd/issues/347.

ccaputo commented 4 years ago

I am seeing some lovely performance improvement with feb2cc7da759d7289ac04f71b3af060347411a5e.

In #323 I mentioned a performance decrease going from 4.0.8 to 4.1.0b4:

NOTE: I have tested the quality of the results, with respect to the many thousands of queries we perform to inform our route servers. While the data with 4.1.0b4 is good as compared to 4.0.8, I am finding 4.1.0b4 to be considerably slower. As an example, we perform about 12k !gas## and 9.6k !6as### queries every hour. With 4.0.8 this process takes under 4 minutes, but with 4.1.0b4 it is taking over 14 minutes. Any idea as to why the slowdown?

That same task now takes about 3 minutes. Excellent!

Curious about and wanting to bang on server.whois.max_connections, as a test I set it to 1 and ran four of our route server scripts at once, resulting in many bgpq4 queries contending for a single TCP port. It all worked great. I also tested with settings of 2, 3, 4, and 8. All good.

Amazing work and thanks.