[openstack-dev] [Neutron] Race condition between DB layer and plugin back-end implementation

Edgar Magana emagana at plumgrid.com
Mon Nov 18 20:25:10 UTC 2013


This topic has been discussed before but I do not remember if we have a good
solution or not.
Basically, if concurrent API calls are sent to Neutron, all of them are sent
to the plug-in level where two actions have to be made:

1. DB transaction ­ No just for data persistence but also to collect the
information needed for the next action
2. Plug-in back-end implementation ­ In our case is a call to the python
library than consequentially calls PLUMgrid REST GW (soon SAL)

For instance:

def create_port(self, context, port):
        with context.session.begin(subtransactions=True):
            # Plugin DB - Port Create and Return port
            port_db = super(NeutronPluginPLUMgridV2,
            device_id = port_db["device_id"]
            if port_db["device_owner"] == "network:router_gateway":
                router_db = self._get_router(context, device_id)
                router_db = None
                LOG.debug(_("PLUMgrid Library: create_port() called"))
# Back-end implementation
                self._plumlib.create_port(port_db, router_db)
            except Exception:

The way we have implemented at the plugin-level in Havana (even in Grizzly)
is that both action are wrapped in the same "transaction" which
automatically rolls back any operation done to its original state protecting
mostly the DB of having any inconsistency state or left over data if the
back-end part fails.=.
The problem that we are experiencing is when concurrent calls to the same
API are sent, the number of operation at the plug-in back-end are long
enough to make the next concurrent API call to get stuck at the DB
transaction level, which creates a hung state for the Neutron Server to the
point that all concurrent API calls will fail.

This can be fixed if we include some "locking" system such as calling:

from neutron.common import utile

@utils.synchronized('any-name', external=True)
def create_port(self, context, port):

Obviously, this will create a serialization of all concurrent calls which
will ends up in having a really bad performance. Does anyone has a better



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20131118/3baacb3b/attachment.html>

More information about the OpenStack-dev mailing list