On Fri, Feb 16, 2018 at 12:12 PM, Daniel Alvarez Sanchez < dalva...@redhat.com> wrote:
> I've found out more about what is running slow in this scenario. > I've profiled the processing of the update2 messages and here you can > see the sequence of calls to __process_update2 (idl.py) when I'm > creating a new port via OpenStack on a system loaded with 800 ports > on the same Logical Switch: > > > 1. Logical_Switch_Port 'insert' > 2. Address_Set 'modify' (to add the new address, it takes ~ takes around > 0.2 seconds > 3. Logical_Switch_Port 'modify' (to add the new 8 ACLs) <- This takes > 2 > seconds > Sorry this is ^ Logical_Switch table. > 4. ACL 'insert' x8 (one per ACL) > 5. Logical_Switch_Port 'modify' ('up' = False) > 6. Logical_Switch_Port 'insert' (this is exactly the same as 1, so it'll > be skipped) > 7. Address_Set 'modify' (this is exactly the same as 2, so it'll be > skipped) still takes ~0.05-0.01 s > 8. Logical_Switch 'modify' (to add the new 8 ACLs, same as 3) still takes > ~0.5 seconds > This too ^ > 9. ACL 'insert' x8 (one per ACL, same as 4) > 10. Logical_Switch_Port 'modify' ('up' = False) same as 5 > 11. Port_Binding (SB) 'insert' > 12. Port_Binding (SB) 'insert' (same as 11) > > > Half of those are dups and even they are noop, they consume times. > The most expensive operation is adding the new 8 ACLs to the acls set in > LS table. > (800 ports with 8 ACLs each makes that set to have 6400 elements). > > NOTE: As you can see, we're trying to insert the address again into > Address_Sets so we should > bear this in mind if we go ahead with Lucas' suggestion about allowing > dups here. > > It's obvious that we'll gain a lot by using Ports Sets for ACLs but, we'll > also need > to invest some time in finding out why we're getting dups and also trying > to optimize > the process_update2 method and its callees to make it faster. With those > last > two things I guess we can improve the performance a lot. > Also, creating a python C binding for this module could also help but that > seems like > a lot of work and still we would need to convert to/from C structures to > Python > objects. However, inserting or identifying dups on large sets would be way > faster. > > I'm going to try out Ben's suggestions for optimizing the process_update* > methods, > and will also try to dig further about the dups. As process_update* seems > a bit > expensive, looks to me that calling it 26 times for a single port is a lot. > 26 calls = 2*(1 (LS insert) + 1 (AS modify) + 1(LSP modify) + 8 (ACL > insert) + 1(LSP modify) + 1(PB insert)) > 26 calls = 2*(1 (LS insert) + 1 (AS modify) + 1(LS modify) + 8 (ACL insert) + 1(LSP modify) + 1(PB insert)) > Thoughts? > Thanks! > Daniel > > > On Thu, Feb 15, 2018 at 10:56 PM, Daniel Alvarez Sanchez < > dalva...@redhat.com> wrote: > >> >> >> On Wed, Feb 14, 2018 at 9:34 PM, Han Zhou <zhou...@gmail.com> wrote: >> >>> >>> >>> On Wed, Feb 14, 2018 at 9:45 AM, Ben Pfaff <b...@ovn.org> wrote: >>> > >>> > On Wed, Feb 14, 2018 at 11:27:11AM +0100, Daniel Alvarez Sanchez wrote: >>> > > Thanks for your inputs. I need to look more carefully into the patch >>> you >>> > > submitted but it looks like, at least, we'll be reducing the number >>> of >>> > > calls to Datum.__cmp__ which should be good. >>> > >>> > Thanks. Please do take a look. It's a micro-optimization but maybe >>> > it'll help? >>> > >>> > > I probably didn't explain it very well. Right now we have N processes >>> > > for Neutron server (in every node). Each of those opens a connection >>> > > to NB db and they subscribe to updates from certain tables. Each time >>> > > a change happens, ovsdb-server will send N update2 messages that has >>> > > to be processed in this "expensive" way by each of those N >>> > > processes. My proposal (yet to be refined) would be to now open N+1 >>> > > connections to ovsdb-server and only subscribe to notifications from >>> 1 >>> > > of those. So every time a new change happens, ovsdb-server will send >>> 1 >>> > > update2 message. This message will be processed (using Py IDL as we >>> do >>> > > now) and once processed, send it (mcast maybe?) to the rest N >>> > > processes. This msg could be simply a Python object serialized and >>> > > we'd be saving all this Datum, Atom, etc. processing by doing it just >>> > > once. >>> > >>> Daniel, I understand that the update2 messages sending would consume NB >>> ovsdb-server CPU and processing those update would consume neutron server >>> process CPU. However, are we sure it is the bottleneck for port creation? >>> >>> From ovsdb-server point of view, sending updates to tens of clients >>> should not be the bottleneck, considering that we have a lot more clients >>> on HVs for SB ovsdb-server. >>> >>> From clients point of view, I think it is more of memory overhead than >>> CPU, and it also depends on how many neutron processes are running on the >>> same node. I didn't find neutron process CPU in your charts. I am hesitate >>> for such big change before we are clear about the bottleneck. The chart of >>> port creation time is very nice, but do we know which part of code >>> contributed to the linear growth? Do we have profiling for the time spent >>> in ovn_client.add_acls()? >>> >> >> Here we are [0]. We see some spikes which are larger as the amount of >> ports increases >> but looks like the actual bottleneck is going to be when we're actually >> commiting the >> transaction [1]. I'll dig further though. >> >> [0 https://imgur.com/a/TmwbC >> [1] https://github.com/openvswitch/ovs/blob/master/python/ovs/ >> db/idl.py#L1158 >> >>> >>> > OK. It's an optimization that does the work in one place rather than N >>> > places, so definitely a win from a CPU cost point of view, but it >>> trades >>> > performance for increased complexity. It sounds like performance is >>> > really important so maybe the increased complexity is a fair trade. >>> > >>> > We might also be able to improve performance by using native code for >>> > some of the work. Were these tests done with the native code JSON >>> > parser that comes with OVS? It is dramatically faster than the Python >>> > code. >>> > >>> > > On Tue, Feb 13, 2018 at 8:32 PM, Ben Pfaff <b...@ovn.org> wrote: >>> > > >>> > > > Can you sketch the rows that are being inserted or modified when a >>> port >>> > > > is added? I would expect something like this as a minimum: >>> > > > >>> > > > * Insert one Logical_Switch_Port row. >>> > > > >>> > > > * Add pointer to Logical_Switch_Port to ports column in >>> one row >>> > > > in Logical_Switch. >>> > > > >>> > > > In addition it sounds like currently we're seeing: >>> > > > >>> > > > * Add one ACL row per security group rule. >>> > > > >>> > > > * Add pointers to ACL rows to acls column in one row in >>> > > > Logical_Switch. >>> > > > >>> > > This is what happens when we create a port in OpenStack (without >>> > > binding it) which belongs to a SG which allows ICMP and SSH traffic >>> > > and drops the rest [0] >>> > > >>> > > Basically, you were right and only thing missing was adding the new >>> > > address to the Address_Set table. >>> > >>> > OK. >>> > >>> > It sounds like the real scaling problem here is that for R security >>> > group rules and P ports, we have R*P rows in the ACL table. Is that >>> > correct? Should we aim to solve that problem? >>> >>> I think this might be the most valuable point to optimize for the >>> create_port scenario from Neutron. >>> I remember there was a patch for ACL group in OVN, so that instead of >>> R*P rows we will have only R + P rows, but didn't see it went through. >>> Is this also a good use case of conjuncture? >>> >>> > _______________________________________________ >>> > discuss mailing list >>> > disc...@openvswitch.org >>> > https://mail.openvswitch.org/mailman/listinfo/ovs-discuss >>> >>> >> >
_______________________________________________ discuss mailing list disc...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-discuss