[openstack-dev] In memory joins in Nova
Mike Bayer
mbayer at redhat.com
Wed Aug 12 14:55:48 UTC 2015
On 8/11/15 7:14 PM, Sachin Manpathak wrote:
> I am struggling with python code profiling in general. It has its own
> caveats like 100% plus overhead.
> However, on a host with only nova services (DB on a different host), I
> see cpu utilization spike up quickly with scale. The DB server is
> relatively calm and never goes over 20%. On a system which relies on
> DB to fetch all the data, this should not happen.
The DB's resources are intended to scale up in response to wide degree
of concurrency, that is, lots and lots of API services all hitting it
from many concurrent API calls. "with scale" here is a slippery
term. What kind of concurrency are you testing with ? How many CPUs
serving API calls are utilized simultaneously? To saturate the
database you need many dozens, and even then you don't want your
database CPU going very high. 20% does not seem that low to me,
actually. I disagree with the concept that high database CPU refers
to a performant application, or that DB saturation is a requirement in
order for a database-delivered application to be performant; I think the
opposite is true. In web application development, when I worked with
production sites at high volume, the goal was to use enough caching so
that major site pages being viewed constantly could be delivered with
*no* database access whatsoever. We wanted to see the majority of the
site being sent to customers with the database at essentially zero; this
is how you get page response times down from 200-300 ms down to 20 or
30. If you want to measure performance, looking at API response
time is probably better than looking at CPU utilization first.
That said, Python is a very CPU intensive language, because it is an
interpreted scripting language. Operations that in a language like
compiled C would be hardly a whisper of CPU end up being major
operations in Python. Openstack suffers from a large amount of
function call overhead even for simple API operations, as it is an
extremely layered system with very little use of caching. Until it
moves to a JIT-based interpreter like Pypy that can flatten out
call-chains, the amount of overhead just for an API call to come in and
go back out with a response will remain significant. As for caching,
making use of a technique such as memcached caching of data structures
can also greatly improve performance because we can cache pre-assembled
data, removing the need to repeatedly extract it from multiple tables to
be pieced together in Python, which is also a very CPU intensive
activity. This is something that will be happening more in the future,
but as it improves the performance of Openstack, it will be removing
even more load from the database. Again, I'd look at API response times
as the first thing to measure.
That said, certainly the joining of data in Python may be unnecessary
and I'm not sure if we can't revisit the history Dan refers to when he
says there were "very large result sets", if we are referring to number
of rows, joining in SQL or in Python will still involve the same number
of "rows", and SQLAlchemy also offers many techniques of optimizing the
overhead of fetching lots of rows which Nova currently doesn't make use
of (see
https://wiki.openstack.org/wiki/OpenStack_and_SQLAlchemy#Eager_load_and_Column_load_tuning
for a primer on this).
If OTOH we are referring to the width of the columns and the join is
such that you're going to get the same A identity over and over again,
if you join A and B you get a "wide" row with all of A and B with a very
large amount of redundant data sent over the wire again and again (note
that the database drivers available to us in Python always send all rows
and columns over the wire unconditionally, whether or not we fetch them
in application code). In this case you *do* want to do the join in
Python to some extent, though you use the database to deliver the
simplest information possible to work with first; you get the full row
for all of the A entries, then a second query for all of B plus A's
primary key that can be quickly matched to that of A. SQLAlchemy
offers this as "subquery eager loading" and it is definitely much more
performant than a single full join when you have wide rows for
individual entities. The database is doing the join to the extent
that it can deliver the primary key information for A and B which can be
operated upon very quickly in memory, as we already have all the A
identities in a hash lookup in any case.
Overall if you're looking to make Openstack faster, where you want to be
is 1. what is the response time of an API call and 2. what do the Python
profiles look like for those API calls? For a primer on Python
profiling see for example my own FAQ entry here:
http://docs.sqlalchemy.org/en/rel_1_0/faq/performance.html#code-profiling.
This kind of profiling is a lot of work and is very tedious, compared to
just running a big rally job and looking at the CPU overhead.
Unfortunately this is the only way one can get actual meaningful
information as to why a Python application is slow. All other
techniques offer us basically nothing as to explaining *why* something
is slow.
>
> I could not find any analysis of nova performance either. Appreciate
> if someone can point me to one.
>
> Thanks,
>
>
>
>
>
> On Tue, Aug 11, 2015 at 3:57 PM, Chris Friesen
> <chris.friesen at windriver.com <mailto:chris.friesen at windriver.com>> wrote:
>
> Just curious...have you measured this consuming a significant
> amount of CPU time? Or is it more a gut feel of "this looks like
> it might be expensive"?
>
> Chris
>
>
> On 08/11/2015 04:51 PM, Sachin Manpathak wrote:
>
> Here are a few --
> instance_get_all_by_filters joins manually with
> instances_fill_metadata --
> https://github.com/openstack/nova/blob/master/nova/db/sqlalchemy/api.py#L1890
> https://github.com/openstack/nova/blob/master/nova/db/sqlalchemy/api.py#L1782
>
> Almost all instance query functions manually join with
> instance_metadata.
>
> Another example was compute_node_get_all function which joined
> compute_node,
> services and ip tables. But it is simplified in current
> codebase (I am working
> on Juno)
>
>
>
>
> On Tue, Aug 11, 2015 at 3:09 PM, Clint Byrum <clint at fewbar.com
> <mailto:clint at fewbar.com>
> <mailto:clint at fewbar.com <mailto:clint at fewbar.com>>> wrote:
>
> Excerpts from Sachin Manpathak's message of 2015-08-12
> 05:40:36 +0800:
> > Hi folks,
> > Nova codebase seems to follow manual joins model where
> all data required by
> > an API is fetched from multiple tables and then joined
> manually by using
> > (in most cases) python dictionary lookups.
> >
> > I was wondering about the basis reasoning for doing so.
> I usually find
> > openstack services to be CPU bound in a medium sized
> environment and
> > non-trivial utilization seems to be from parts of code
> which do manual
> > joins.
>
> Could you please cite specific examples so we can follow
> along with your
> thinking without having to repeat your analysis?
>
> Thanks!
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe:
> OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> <http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe>
>
> <http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe>
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
>
>
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe:
> OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> <http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe>
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
>
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe:
> OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> <http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe>
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
>
>
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe: OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20150812/3e44dc75/attachment.html>
More information about the OpenStack-dev
mailing list