[openstack-dev] [all] Replace mysql-python with mysqlclient

Mike Bayer mbayer at redhat.com
Mon May 11 22:44:30 UTC 2015



On 5/11/15 5:25 PM, Robert Collins wrote:
>
> Details: Skip over this bit if you know it all already.
>
> The GIL plays a big factor here: if you want to scale the amount of
> CPU available to a Python service, you have two routes:
> A) move work to a different process through some RPC - be that DB's
> using SQL, other services using oslo.messaging or HTTP - whatever.
> B) use C extensions to perform work in threads - e.g. openssl context
> processing.
>
> To increase concurrency you can use threads, eventlet, asyncio,
> twisted etc - because within a single process *all* Python bytecode
> execution happens inside the GIL lock, so you get at most one CPU for
> a CPU bound workload. For an IO bound workload, you can fit more work
> in by context switching within that one CPU capacity. And - the GIL is
> a poor scheduler, so at the limit - an IO bound workload where the IO
> backend has more capacity than we have CPU to consume it within our
> process, you will run into priority inversion and other problems.
> [This varies by Python release too].
>
> request_duration = time_in_cpu + time_blocked
> request_cpu_utilisation = time_in_cpu/request_duration
> cpu_utilisation = concurrency * request_cpu_utilisation
>
> Assuming that we don't want any one process to spend a lot of time at
> 100% - to avoid such at-the-limit issues, lets pick say 80%
> utilisation, or a safety factor of 0.2. If a single request consumes
> 50% of its duration waiting on IO, and 50% of its duration executing
> bytecode, we can only run one such request concurrently without
> hitting 100% utilisations. (2*0.5 CPU == 1). For a request that spends
> 75% of its duration waiting on IO and 25% on CPU, we can run 3 such
> requests concurrently without exceeding our target of 80% utilisation:
> (3*0.25=0.75).
>
> What we have today in our standard architecture for OpenStack is
> optimised for IO bound workloads: waiting on the
> network/subprocesses/disk/libvirt etc. Running high numbers of
> eventlet handlers in a single process only works when the majority of
> the work being done by a handler is IO.

Everything stated here is great, however in our situation there is one 
unfortunate fact which renders it completely incorrect at the moment.   
I'm still puzzled why we are getting into deep think sessions about the 
vagaries of the GIL and async when there is essentially a full-on 
red-alert performance blocker rendering all of this discussion useless, 
so I must again remind us: what we have *today* in Openstack is *as 
completely un-optimized as you can possibly be*.

The most GIL-heavy nightmare CPU bound task you can imagine running on 
25 threads on a ten year old Pentium will run better than the Openstack 
we have today, because we are running a C-based, non-eventlet patched DB 
library within a single OS thread that happens to use eventlet, but the 
use of eventlet is totally pointless because right now it blocks 
completely on all database IO.   All production Openstack applications 
today are fully serialized to only be able to emit a single query to the 
database at a time; for each message sent, the entire application blocks 
an order of magnitude more than it would under the GIL waiting for the 
database library to send a message to MySQL, waiting for MySQL to send a 
response including the full results, waiting for the database to unwrap 
the response into Python structures, and finally back to the Python 
space, where we can send another database message and block the entire 
application and all greenlets while this single message proceeds.

To share a link I've already shared about a dozen times here, here's 
some tests under similar conditions which illustrate what that 
concurrency looks like: 
http://www.diamondtin.com/2014/sqlalchemy-gevent-mysql-python-drivers-comparison/. 
MySQLdb takes *20 times longer* to handle the work of 100 sessions than 
PyMySQL when it's inappropriately run under gevent, when there is 
modestly high concurrency happening.   When I talk about moving to 
threads, this is not a "won't help or hurt" kind of issue, at the moment 
it's a change that will immediately allow massive improvement to the 
performance of all Openstack applications instantly.  We need to change 
the DB library or dump eventlet.

As far as if we should dump eventlet or use a pure-Python DB library, my 
contention is that a thread based + C database library will outperform 
an eventlet + Python-based database library. Additionally, if we make 
either change, when we do so we may very well see all kinds of new 
database-concurrency related bugs in our apps too, because we will be 
talking to the database much more intensively all the sudden; it is my 
opinion that a traditional threading model will be an easier environment 
to handle working out the approach to these issues; we have to assume 
"concurrency at any time" in any case because we run multiple instances 
of Nova etc. at the same time.  At the end of the day, we aren't going 
to see wildly better performance with one approach over the other in any 
case, so we should pick the one that is easier to develop, maintain, and 
keep stable.

Robert's analysis talks about various "at the limit" issues,  but I was 
unable to reproduce these in my own testing, and we should be relying 
upon working tests to illustrate what performance characteristics 
actually pan out.    My tests only dealt with psycopg2 and Postgresql 
for example; won't someone work with my tests and try to replicate with 
PyMySQL/eventlet vs. MySQL-Python/threads?   We should be relying on 
testing to see what reality actually holds here.   But more than that, 
first we need to fix the obviously broken thing about our DB access 
before we can claim anything is optimized at all, and after we do that, 
I don't think splitting hairs into threads vs. eventlet is really going 
to make that much of a difference performance-wise.  We should go with 
what produces the most stable development and usage experience while 
allowing a high degree of concurrency.









More information about the OpenStack-dev mailing list