Skip to content

Commit

Permalink
controller: Avoid unnecessary load balancer flow processing.
Browse files Browse the repository at this point in the history
Whenever a Load_Balancer is updated, e.g., a VIP is added, the following
sequence of events happens:

1. The Southbound Load_Balancer record is updated.
2. The Southbound Datapath_Binding records on which the Load_Balancer is
   applied are updated.
3. Southbound ovsdb-server sends updates about the Load_Balancer and
   Datapath_Binding records to ovn-controller.
4. The IDL layer in ovn-controller processes the updates at #3, but
   because of the SB schema references between tables [0] all logical
   flows referencing the updated Datapath_Binding are marked as
   "updated".  The same is true for Logical_DP_Group records
   referencing the Datapath_Binding, and also for all logical flows
   pointing to the new "updated" datapath groups.
5. ovn-controller ends up recomputing (removing/readding) all flows for
   all these tracked updates.

From the SB Schema:
        "Datapath_Binding": {
            "columns": {
                [...]
                "load_balancers": {"type": {"key": {"type": "uuid",
                                                   "refTable": "Load_Balancer",
                                                   "refType": "weak"},
                                            "min": 0,
                                            "max": "unlimited"}},
        [...]
        "Load_Balancer": {
            "columns": {
                "datapaths": {
                [...]
                    "type": {"key": {"type": "uuid",
                                     "refTable": "Datapath_Binding"},
                             "min": 0, "max": "unlimited"}},
        [...]
        "Logical_DP_Group": {
            "columns": {
                "datapaths":
                    {"type": {"key": {"type": "uuid",
                                      "refTable": "Datapath_Binding",
                                      "refType": "weak"},
                              "min": 0, "max": "unlimited"}}},
        [...]
        "Logical_Flow": {
            "columns": {
                "logical_datapath":
                    {"type": {"key": {"type": "uuid",
                                      "refTable": "Datapath_Binding"},
                              "min": 0, "max": 1}},
                "logical_dp_group":
                    {"type": {"key": {"type": "uuid",
                                      "refTable": "Logical_DP_Group"},

In order to avoid this unnecessary Logical_Flow notification storm we
now remove the explicit reference from Datapath_Binding to
Load_Balancer and instead store raw UUIDs.

This means that on the ovn-controller side we need to perform a
Load_Balancer table lookup by UUID whenever a new datapath is added,
but that doesn't happen too often and the cost of the lookup is
negligible compared to the huge cost of processing the unnecessary
logical flow updates.

This change is backwards compatible because the contents stored in the
database are not changed, just that the schema constraints are relaxed a
bit.

Some performance measurements, on a scale test deployment simulating an
ovn-kubernetes deployment with 120 nodes and a large load balancer
with 16K VIPs associated to each node's logical switch, the event
processing loop time in ovn-controller, when adding a new VIP, is
reduced from ~39 seconds to ~8 seconds.

There's no need to change the northd DDlog implementation.

Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1978605
Acked-by: Mark Michelson <[email protected]>
Signed-off-by: Dumitru Ceara <[email protected]>
  • Loading branch information
dceara authored and putnopvut committed Jul 12, 2021
1 parent 8469d5e commit 6aab704
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 15 deletions.
6 changes: 4 additions & 2 deletions controller/lflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -1744,8 +1744,10 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp,
/* Add load balancer hairpin flows if the datapath has any load balancers
* associated. */
for (size_t i = 0; i < dp->n_load_balancers; i++) {
consider_lb_hairpin_flows(dp->load_balancers[i],
l_ctx_in->local_datapaths,
const struct sbrec_load_balancer *lb =
sbrec_load_balancer_table_get_for_uuid(l_ctx_in->lb_table,
&dp->load_balancers[i]);
consider_lb_hairpin_flows(lb, l_ctx_in->local_datapaths,
l_ctx_out->flow_table);
}

Expand Down
14 changes: 6 additions & 8 deletions northd/ovn-northd.c
Original file line number Diff line number Diff line change
Expand Up @@ -3635,19 +3635,17 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths,
continue;
}

const struct sbrec_load_balancer **sbrec_lbs =
xmalloc(od->nbs->n_load_balancer * sizeof *sbrec_lbs);
struct uuid *lb_uuids =
xmalloc(od->nbs->n_load_balancer * sizeof *lb_uuids);
for (size_t i = 0; i < od->nbs->n_load_balancer; i++) {
const struct uuid *lb_uuid =
&od->nbs->load_balancer[i]->header_.uuid;
lb = ovn_northd_lb_find(lbs, lb_uuid);
sbrec_lbs[i] = lb->slb;
lb_uuids[i] = lb->slb->header_.uuid;
}

sbrec_datapath_binding_set_load_balancers(
od->sb, (struct sbrec_load_balancer **)sbrec_lbs,
od->nbs->n_load_balancer);
free(sbrec_lbs);
sbrec_datapath_binding_set_load_balancers(od->sb, lb_uuids,
od->nbs->n_load_balancer);
free(lb_uuids);
}
}

Expand Down
8 changes: 3 additions & 5 deletions ovn-sb.ovsschema
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
"version": "20.18.0",
"cksum": "1816525029 26536",
"version": "20.19.0",
"cksum": "4027775051 26386",
"tables": {
"SB_Global": {
"columns": {
Expand Down Expand Up @@ -166,9 +166,7 @@
"type": {"key": {"type": "integer",
"minInteger": 1,
"maxInteger": 16777215}}},
"load_balancers": {"type": {"key": {"type": "uuid",
"refTable": "Load_Balancer",
"refType": "weak"},
"load_balancers": {"type": {"key": {"type": "uuid"},
"min": 0,
"max": "unlimited"}},
"external_ids": {
Expand Down

0 comments on commit 6aab704

Please sign in to comment.