<div dir="ltr">Hi Matthew,<div><br></div><div>I'll add just 2c:</div><div><br></div><div>We've tried to move from repeatable-read to read committed in Neutron project.</div><div>This change actually has caused multiple deadlocks during regular tempest test run.</div><div>That is a known problem (the issue with eventlet and currect mysql client library),</div><div>but anyway, at least one major openstack project is not ready to move to read-committed.</div><div><br></div><div>Also, particular transaction isolation level's performance is highly affected by DB usage pattern.</div><div>Is there any research of how read-committed affects performance of openstack projects?</div><div><br></div><div>Thanks,</div><div>Eugene.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 6, 2015 at 7:59 PM, Matthew Booth <span dir="ltr"><<a href="mailto:mbooth@redhat.com" target="_blank">mbooth@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I was surprised recently to discover that MySQL uses repeatable read for<br>
transactions by default. Postgres uses read committed by default, and<br>
SQLite uses serializable. We don't set the isolation level explicitly<br>
anywhere, so our applications are running under different isolation<br>
levels depending on backend. This doesn't sound like a good idea to me.<br>
It's one thing to support multiple sql syntaxes, but different isolation<br>
levels have different semantics. Supporting that is much harder, and<br>
currently we're not even trying.<br>
<br>
I'm aware that the same isolation level on different databases will<br>
still have subtly different semantics, but at least they should agree on<br>
the big things. I think we should pick one, and it should be read committed.<br>
<br>
Also note that 'repeatable read' on both MySQL and Postgres is actually<br>
snapshot isolation, which isn't quite the same thing. For example, it<br>
doesn't get phantom reads.<br>
<br>
The most important reason I think we need read committed is recovery<br>
from concurrent changes within the scope of a single transaction. To<br>
date, in Nova at least, this hasn't been an issue as transactions have<br>
had an extremely small scope. However, we're trying to expand that scope<br>
with the new enginefacade in oslo.db:<br>
<a href="https://review.openstack.org/#/c/138215/" target="_blank">https://review.openstack.org/#/c/138215/</a> . With this expanded scope,<br>
transaction failure in a library function can't simply be replayed<br>
because the transaction scope is larger than the function.<br>
<br>
So, 3 concrete examples of how repeatable read will make Nova worse:<br>
<br>
* <a href="https://review.openstack.org/#/c/140622/" target="_blank">https://review.openstack.org/#/c/140622/</a><br>
<br>
This was committed to Nova recently. Note how it involves a retry in the<br>
case of concurrent change. This works fine, because the retry is creates<br>
a new transaction. However, if the transaction was larger than the scope<br>
of this function this would not work, because each iteration would<br>
continue to read the old data. The solution to this is to create a new<br>
transaction. However, because the transaction is outside of the scope of<br>
this function, the only thing we can do locally is fail. The caller then<br>
has to re-execute the whole transaction, or fail itself.<br>
<br>
This is a local concurrency problem which can be very easily handled<br>
locally, but not if we're using repeatable read.<br>
<br>
*<br>
<a href="https://github.com/openstack/nova/blob/master/nova/db/sqlalchemy/api.py#L4749" target="_blank">https://github.com/openstack/nova/blob/master/nova/db/sqlalchemy/api.py#L4749</a><br>
<br>
Nova has multiple functions of this type which attempt to update a<br>
key/value metadata table. I'd expect to find multiple concurrency issues<br>
with this if I stopped to give it enough thought, but concentrating just<br>
on what's there, notice how the retry loop starts a new transaction. If<br>
we want to get to a place where we don't do that, with repeatable read<br>
we're left failing the whole transaction.<br>
<br>
* <a href="https://review.openstack.org/#/c/136409/" target="_blank">https://review.openstack.org/#/c/136409/</a><br>
<br>
This one isn't upstream, yet. It's broken, and I can't currently think<br>
of a solution if we're using repeatable read.<br>
<br>
The issue is atomic creation of a shared resource. We want to handle a<br>
creation race safely. This patch:<br>
<br>
* Attempts to reads the default (it will normally exist)<br>
* Creates a new one if it doesn't exist<br>
* Goes back to the start if creation failed due to a duplicate<br>
<br>
Seems fine, but it will fail because the re-read will continue to not<br>
return the new value under repeatable read (no phantom reads). The only<br>
way to see the new row is a new transaction. Is this will no longer be<br>
in the scope of this function, the only solution will be to fail. Read<br>
committed could continue without failing.<br>
<br>
Incidentally, this currently works by using multiple transactions, which<br>
we are trying to avoid. It has also been suggested that in this specific<br>
instance the default security group could be created with the project.<br>
However, that would both be more complicated, because it would require<br>
putting a hook into another piece of code, and less robust, because it<br>
wouldn't recover if somebody deleted the default security group.<br>
<br>
<br>
To summarise, with repeatable read we're forced to abort the current<br>
transaction to deal with certain relatively common classes of<br>
concurrency issue, whereas with read committed we can safely recover. If<br>
we want to reduce the number of transactions we're using, which we do,<br>
the impact of this is going to dramatically increase. We should<br>
standardise on read committed.<br>
<br>
Matt<br>
<span class="HOEnZb"><font color="#888888">--<br>
Matthew Booth<br>
Red Hat Engineering, Virtualisation Team<br>
<br>
Phone: +442070094448 (UK)<br>
GPG ID:  D33C3490<br>
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490<br>
<br>
__________________________________________________________________________<br>
OpenStack Development Mailing List (not for usage questions)<br>
Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a><br>
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br>
</font></span></blockquote></div><br></div>