Skip to content

crdb memory budget exceeded error when creating a large number of instances concurrently #5904

@askfongjojo

Description

@askfongjojo

While creating 70 instances concurrently using the same Terraform plan I used many times before without any problem, I'm now hitting a number of 500 errors in every run consistently. The errors in nexus log all look like the one below:

02:12:24.115Z INFO 65a11c18-7f59-41ac-b9e7-680627f996e7 (dropshot_external): request completed
    error_message_external = Internal Server Error
    error_message_internal = saga ACTION error at node "output": unexpected database error: root: memory budget exceeded: 7854088 bytes requested, 127439909 currently allocated, 134217728 bytes in budget
    file = /home/build/.cargo/git/checkouts/dropshot-a4a923d29dccc492/0cd0e82/dropshot/src/server.rs:866
    latency_us = 1918719
    local_addr = 172.30.2.5:443
    method = POST
    remote_addr = 172.20.17.42:54427
    req_id = 9c1272f5-2184-4f5b-b7c9-5b6b43adad1c
    response_code = 500
    uri = https://oxide.sys.rack2.eng.oxide.computer/v1/instances?project=fe0da422-5c48-4b52-8010-f2fc401f090f

Using this D script against the nexus process running in sled 8, I was able to capture the database error in question:

conn_id: f2bdf557-5a71-4a0f-9a98-83a50a11f1cd, latency: 2329 us, query: 'INSERT INTO "saga_node_event" ("saga_id", "node_id", "event_type", "data", "event_time", "creator") VALUES ($1, $2, $3, $4, $5, $6) -- binds: [SagaId(9225d6c7-6369-40fa-b9cf-e3b698434a66), SagaNodeId(5), "failed", Object {"ActionFailed": Object {"source_error": Object {"InternalError": Object {"internal_message": String("unexpected database error: root: memory budget exceeded: 7854088 bytes requested, 133920542 currently allocated, 134217728 bytes in budget")}}}}, 2024-06-15T04:17:54.044368305Z, 65a11c18-7f59-41ac-b9e7-680627f996e7]'

It is however an insert statement and didn't appear to be the culprit. I had a look at 3 different occurrences of the 500 errors and tried to pinpoint the more expensive queries running around the same time. Here is one of those (latency = 346542 us):

WITH found_row AS MATERIALIZED (
  SELECT 
    "vpc_subnet"."id", 
    "vpc_subnet"."name", 
    "vpc_subnet"."description", 
    "vpc_subnet"."time_created", 
    "vpc_subnet"."time_modified", 
    "vpc_subnet"."time_deleted", 
    "vpc_subnet"."vpc_id", 
    "vpc_subnet"."rcgen", 
    "vpc_subnet"."ipv4_block", 
    "vpc_subnet"."ipv6_block" 
  FROM 
    "vpc_subnet" 
  WHERE 
    (
      ("vpc_subnet"."id" = $1) 
      AND (
        "vpc_subnet"."time_deleted" IS NULL
      )
    ) FOR 
  UPDATE 
    ), 
dummy AS MATERIALIZED (
  SELECT 
    IF(
      EXISTS(
        SELECT 
          "id" 
        FROM 
          found_row
      ), 
      TRUE, 
      CAST(1 / 0 AS BOOL)
    )
), 
updated_row AS MATERIALIZED (
  UPDATE 
    "vpc_subnet" 
  SET 
    "rcgen" = "rcgen" + 1 
  WHERE 
    "id" IN (
      SELECT 
        "id" 
      FROM 
        found_row
    ) RETURNING 1
), 
inserted_row AS (
  INSERT INTO "network_interface" (
    "id", "name", "description", "time_created", 
    "time_modified", "time_deleted", 
    "kind", "parent_id", "vpc_id", "subnet_id", 
    "mac", "ip", "slot", "is_primary"
  ) WITH validated_interface(
    "vpc_id", "subnet_id", "parent_id", 
    "slot", "is_primary"
  ) AS (
    SELECT 
      CAST(
        IF(
          COALESCE(
            (
              SELECT 
                "vpc_id" 
              FROM 
                "network_interface" 
              WHERE 
                "time_deleted" IS NULL 
                AND "parent_id" = $2 
                AND "kind" = $3 
              LIMIT 
                1
            ), $4
          ) = $5, 
          $6, 
          'multiple-vpcs'
        ) AS UUID
      ) AS "vpc_id", 
      CAST(
        IF(
          EXISTS(
            SELECT 
              "subnet_id" 
            FROM 
              "network_interface" 
            WHERE 
              "id" != $7 
              AND "parent_id" = $8 
              AND "kind" = $9 
              AND "time_deleted" IS NULL 
              AND "subnet_id" = $10
          ), 
          'non-unique-subnets', 
          $11
        ) AS UUID
      ) AS "subnet_id", 
      (
        CAST(
          CASE COALESCE(
            (
              SELECT 
                CASE WHEN "active_propolis_id" IS NULL THEN "state" ELSE $12 END 
              FROM 
                "instance" 
              WHERE 
                "id" = $13 
                AND "time_deleted" IS NULL
            ), 
            $14
          ) WHEN $15 THEN $16 WHEN $17 THEN $18 WHEN $19 THEN $20 ELSE $21 END AS UUID
        )
      ), 
      (
        SELECT 
          COALESCE(
            (
              SELECT 
                $22 + "shift" AS "slot" 
              FROM 
                (
                  SELECT 
                    generate_series(0, $23) AS "index", 
                    generate_series(0, $24) AS "shift" 
                  UNION ALL 
                  SELECT 
                    generate_series($25, $26) AS "index", 
                    generate_series($27, -1) AS "shift"
                ) 
                LEFT OUTER JOIN "network_interface" ON (
                  "parent_id", "slot", "time_deleted" IS NULL
                ) = ($28, $29 + "shift", TRUE) 
              WHERE 
                "slot" IS NULL 
              ORDER BY 
                "index" 
              LIMIT 
                1
            ), 0
          )
      ), 
      (
        SELECT 
          NOT EXISTS(
            SELECT 
              1 
            FROM 
              "network_interface" 
            WHERE 
              "parent_id" = $30 
              AND "kind" = $31 
              AND "time_deleted" IS NULL 
            LIMIT 
              1
          )
      )
  ) 
  SELECT 
    $32 AS "id", 
    $33 AS "name", 
    $34 AS "description", 
    $35 AS "time_created", 
    $36 AS "time_modified", 
    $37 AS "time_deleted", 
    $38 AS "kind", 
    $39 AS "parent_id", 
    (
      SELECT 
        "vpc_id" 
      FROM 
        validated_interface
    ), 
    (
      SELECT 
        "subnet_id" 
      FROM 
        validated_interface
    ), 
    (
      SELECT 
        $40 + "shift" AS "mac" 
      FROM 
        (
          SELECT 
            generate_series(0, $41) AS "index", 
            generate_series(0, $42) AS "shift" 
          UNION ALL 
          SELECT 
            generate_series($43, $44) AS "index", 
            generate_series($45, -1) AS "shift"
        ) 
        LEFT OUTER JOIN "network_interface" ON (
          "vpc_id", "mac", "time_deleted" IS NULL
        ) = ($46, $47 + "shift", TRUE) 
      WHERE 
        "mac" IS NULL 
      ORDER BY 
        "index" 
      LIMIT 
        1
    ) AS "mac", 
    (
      SELECT 
        $48 + "shift" AS "ip" 
      FROM 
        (
          SELECT 
            generate_series(0, $49) AS "index", 
            generate_series(0, $50) AS "shift" 
          UNION ALL 
          SELECT 
            generate_series($51, $52) AS "index", 
            generate_series($53, -1) AS "shift"
        ) 
        LEFT OUTER JOIN "network_interface" ON (
          "subnet_id", "ip", "time_deleted" IS NULL
        ) = ($54, $55 + "shift", TRUE) 
      WHERE 
        "ip" IS NULL 
      ORDER BY 
        "index" 
      LIMIT 
        1
    ) AS "ip", 
    (
      SELECT 
        "slot" 
      FROM 
        validated_interface
    ), 
    (
      SELECT 
        "is_primary" 
      FROM 
        validated_interface
    ) RETURNING "network_interface"."id", 
    "network_interface"."name", 
    "network_interface"."description", 
    "network_interface"."time_created", 
    "network_interface"."time_modified", 
    "network_interface"."time_deleted", 
    "network_interface"."kind", 
    "network_interface"."parent_id", 
    "network_interface"."vpc_id", 
    "network_interface"."subnet_id", 
    "network_interface"."mac", 
    "network_interface"."ip", 
    "network_interface"."slot", 
    "network_interface"."is_primary"
) 
SELECT 
  * 
FROM 
  inserted_row -- binds: [7612ed87-eff5-433f-b781-cf4cbeb75def, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, Instance, 91a91cab-2fbd-4c1e-a91f-4f2bcae5705b, 91a91cab-2fbd-4c1e-a91f-4f2bcae5705b, "91a91cab-2fbd-4c1e-a91f-4f2bcae5705b", f0c3f7b4-3190-43d8-b695-3ac56b995077, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, Instance, 7612ed87-eff5-433f-b781-cf4cbeb75def, "7612ed87-eff5-433f-b781-cf4cbeb75def", Vmm, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, Destroyed, NoVmm, "aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b", Creating, "aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b", Destroyed, "no-instance", "bad-state", 0, 8, 8, 9, 8, 0, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, 0, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, Instance, f0c3f7b4-3190-43d8-b695-3ac56b995077, Name(Name("net0")), "net0", 2024-06-15T04:17:53.697381777Z, 2024-06-15T04:17:53.697381777Z, None, Instance, aa47bc6e-e1b9-4b3a-baa0-83f6e4b06c2b, MacAddr(MacAddr(MacAddr6([168, 64, 37, 248, 102, 112]))), 432527, 432527, 432528, 983039, -550512, 91a91cab-2fbd-4c1e-a91f-4f2bcae5705b, MacAddr(MacAddr(MacAddr6([168, 64, 37, 248, 102, 112]))), V4(Ipv4Network { addr: 192.168.128.5, prefix: 32 }), 249, 249, 250, 249, 0, 7612ed87-eff5-433f-b781-cf4cbeb75def, V4(Ipv4Network { addr: 192.168.128.5, prefix: 32 })]

(a grep of this query pattern shows the latency was as high as 1523657 us during the window when I was running terraform apply and tracing the database queries).

The complete nexus log and db query tracing output are located in catacomb:/staff/dogfood/omicron-5904.

Metadata

Metadata

Assignees

No one assigned

    Labels

    known issueTo include in customer documentation and training

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions