Running concurrent backup restores results in OOM killing

Bug #1865011 reported by Gorka Eguileor
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Cinder
Fix Released
Undecided
Gorka Eguileor

Bug Description

When restoring many backups, for example 41, the backup service uses a lot of memory and end up getting killed becase we run out of memory.

The amount of memory required when the volumes are RBD, and the backups are not, is even worse.

Here's the explanation of the peak memory we will need for 1 restore:

- First we use as much as the size of the chunk we have stored, which in our case is compressed, so if we assume a 50% compression ratio, it would be 50% of the original chunk which can be 1999994880 bytes.
  So here we use 0.93GB when the ChunkedBackupDriver reads the object [1]

            with self._get_object_reader(
                    container, object_name,
                    extra_metadata=extra_metadata) as reader:
                body = reader.read()

- Then when we decompress the data [2] we will need an additional 1,86GB which is the full original chunk size:
                decompressed = decompressor.decompress(body)

- Then when the ChunkedBackupDriver writes the data [3]:
                volume_file.write(decompressed)

  What happens behind that call, because this is an RBD volume, is that we use the osb-brick connector which uses librbd Image object to do the writing [4]:
    def write(self, data):
        self._rbd_volume.image.write(data, self._offset)

  The write method in librbd calls the rbd_write2 method [5]
            ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)

  And the method will call the create_write_raw method with nullptr as the aio_completion parameter [6]:
       bl.push_back(create_write_raw(ictx, buf, len, nullptr));

  And because of this the create_write_raw method will copy the data in a different buffer [7]:
    if (ictx->disable_zero_copy || aio_completion == nullptr) {
      // must copy the buffer if writeback/writearound cache is in-use (or using
      // non-AIO)
      return buffer::copy(buf, len);

  And we end up using another 1.86GB of RAM

So we end up needing 0.93GB + 1.86GB + 1.86GB for a single restore operation. If we now do 41 simultaneous operations, we will end up using 190.65GB, hence the OOM kill.

I see 2 improvements that can be done in the Cinder code:

- Help Python free memory faster by setting to None the body variable as soon as we decompress it, and setting to None the decompressed variable as soon as we've written it.
- Introduce a max concurrent backup & restore operations feature that will queue operations that exceed them.

To mitigate the problem, deployments can do any of:

- Reduce the number of concurrent restore operations
- Disable compression
- Reduce the size of the chunks with the backup_file_size variable

[1]: https://opendev.org/openstack/cinder/src/commit/a154a1360be62eed0e2bf20937503b55659f4701/cinder/backup/chunkeddriver.py#L712
[2]: https://opendev.org/openstack/cinder/src/commit/a154a1360be62eed0e2bf20937503b55659f4701/cinder/backup/chunkeddriver.py#L719
[3]: https://opendev.org/openstack/cinder/src/commit/a154a1360be62eed0e2bf20937503b55659f4701/cinder/backup/chunkeddriver.py#L720
[4]: https://opendev.org/openstack/os-brick/src/commit/49d5616f86d637c846d54cd48c5ed4e17bd6695e/os_brick/initiator/linuxrbd.py#L195
[5]: https://github.com/ceph/ceph/blob/53febd478dfc7282f0948853c117061d96cda9b1/src/pybind/rbd/rbd.pyx#L4321
[6]: https://github.com/ceph/ceph/blob/b2e825debc4d47cede8df86b96af94893241ddf7/src/librbd/librbd.cc#L5826
[7]: https://github.com/ceph/ceph/blob/b2e825debc4d47cede8df86b96af94893241ddf7/src/librbd/librbd.cc#L91-L94

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix proposed to cinder (master)

Related fix proposed to branch: master
Review: https://review.opendev.org/710250

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix proposed to cinder (master)

Fix proposed to branch: master
Review: https://review.opendev.org/710297

Changed in cinder:
assignee: nobody → Gorka Eguileor (gorka)
status: New → In Progress
Changed in cinder:
assignee: Gorka Eguileor (gorka) → Rajat Dhasmana (whoami-rajat)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix merged to cinder (master)

Reviewed: https://review.opendev.org/710250
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=69462315bc8416bd02ebd6085f0cfc141cfd8877
Submitter: Zuul
Branch: master

commit 69462315bc8416bd02ebd6085f0cfc141cfd8877
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 14:04:13 2020 +0100

    ChunkedBackupDriver: Freeing memory on restore

    When restoring many backups, the backup service uses a lot of memory and
    when we do many concurrent restores the backup service ends up getting
    killed becase the system runs out of memory.

    This patch reduces the ref count to the data as soon as possible to let
    Python garbage collect it instead of hogging it for the whole chunk
    restore.

    Related-Bug: #1865011
    Change-Id: I942d9d8b3976232ae1cf82b698fb27285fbef13a

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix proposed to cinder (stable/queens)

Related fix proposed to branch: stable/queens
Review: https://review.opendev.org/711479

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix proposed to cinder (stable/rocky)

Related fix proposed to branch: stable/rocky
Review: https://review.opendev.org/711481

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix proposed to cinder (stable/stein)

Related fix proposed to branch: stable/stein
Review: https://review.opendev.org/711482

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix proposed to cinder (stable/train)

Related fix proposed to branch: stable/train
Review: https://review.opendev.org/711483

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix merged to cinder (stable/train)

Reviewed: https://review.opendev.org/711483
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=94db15dd3b86c7da92ceaa4b8c2d948b2b30c65b
Submitter: Zuul
Branch: stable/train

commit 94db15dd3b86c7da92ceaa4b8c2d948b2b30c65b
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 14:04:13 2020 +0100

    ChunkedBackupDriver: Freeing memory on restore

    When restoring many backups, the backup service uses a lot of memory and
    when we do many concurrent restores the backup service ends up getting
    killed becase the system runs out of memory.

    This patch reduces the ref count to the data as soon as possible to let
    Python garbage collect it instead of hogging it for the whole chunk
    restore.

    Related-Bug: #1865011
    Change-Id: I942d9d8b3976232ae1cf82b698fb27285fbef13a
    (cherry picked from commit 69462315bc8416bd02ebd6085f0cfc141cfd8877)

tags: added: in-stable-train
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix merged to cinder (stable/stein)

Reviewed: https://review.opendev.org/711482
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=f4aa81424fff8718bd432cc5a7aae357fe028023
Submitter: Zuul
Branch: stable/stein

commit f4aa81424fff8718bd432cc5a7aae357fe028023
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 14:04:13 2020 +0100

    ChunkedBackupDriver: Freeing memory on restore

    When restoring many backups, the backup service uses a lot of memory and
    when we do many concurrent restores the backup service ends up getting
    killed becase the system runs out of memory.

    This patch reduces the ref count to the data as soon as possible to let
    Python garbage collect it instead of hogging it for the whole chunk
    restore.

    Related-Bug: #1865011
    Change-Id: I942d9d8b3976232ae1cf82b698fb27285fbef13a
    (cherry picked from commit 69462315bc8416bd02ebd6085f0cfc141cfd8877)
    (cherry picked from commit 94db15dd3b86c7da92ceaa4b8c2d948b2b30c65b)

tags: added: in-stable-stein
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix merged to cinder (stable/rocky)

Reviewed: https://review.opendev.org/711481
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=20b6b7477daae43907f38337aef15a5f47a92283
Submitter: Zuul
Branch: stable/rocky

commit 20b6b7477daae43907f38337aef15a5f47a92283
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 14:04:13 2020 +0100

    ChunkedBackupDriver: Freeing memory on restore

    When restoring many backups, the backup service uses a lot of memory and
    when we do many concurrent restores the backup service ends up getting
    killed becase the system runs out of memory.

    This patch reduces the ref count to the data as soon as possible to let
    Python garbage collect it instead of hogging it for the whole chunk
    restore.

    Related-Bug: #1865011
    Change-Id: I942d9d8b3976232ae1cf82b698fb27285fbef13a
    (cherry picked from commit 69462315bc8416bd02ebd6085f0cfc141cfd8877)
    (cherry picked from commit 94db15dd3b86c7da92ceaa4b8c2d948b2b30c65b)
    (cherry picked from commit f4aa81424fff8718bd432cc5a7aae357fe028023)

tags: added: in-stable-rocky
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Related fix merged to cinder (stable/queens)

Reviewed: https://review.opendev.org/711479
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=614f48d61c8db10d7ee328ad92612fd15f0671d7
Submitter: Zuul
Branch: stable/queens

commit 614f48d61c8db10d7ee328ad92612fd15f0671d7
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 14:04:13 2020 +0100

    ChunkedBackupDriver: Freeing memory on restore

    When restoring many backups, the backup service uses a lot of memory and
    when we do many concurrent restores the backup service ends up getting
    killed becase the system runs out of memory.

    This patch reduces the ref count to the data as soon as possible to let
    Python garbage collect it instead of hogging it for the whole chunk
    restore.

    Related-Bug: #1865011
    Change-Id: I942d9d8b3976232ae1cf82b698fb27285fbef13a
    (cherry picked from commit 69462315bc8416bd02ebd6085f0cfc141cfd8877)
    (cherry picked from commit 94db15dd3b86c7da92ceaa4b8c2d948b2b30c65b)
    (cherry picked from commit f4aa81424fff8718bd432cc5a7aae357fe028023)
    (cherry picked from commit 20b6b7477daae43907f38337aef15a5f47a92283)

tags: added: in-stable-queens
Changed in cinder:
assignee: Rajat Dhasmana (whoami-rajat) → Gorka Eguileor (gorka)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to cinder (master)

Reviewed: https://review.opendev.org/710297
Committed: https://git.openstack.org/cgit/openstack/cinder/commit/?id=30c2289c9b0456d3783f01e3d65985ed1b09976a
Submitter: Zuul
Branch: master

commit 30c2289c9b0456d3783f01e3d65985ed1b09976a
Author: Gorka Eguileor <email address hidden>
Date: Thu Feb 27 16:24:09 2020 +0100

    Backup: Limit number of concurent operations

    This patch adds the backup_max_operations configuration option that
    limits the number of concurrent backup and restore operations.

    These operations can consume large amounts of RAM, so we should limit
    them according to our system resources to avoid processes being killed
    because we run out of memory.

    The default is 15 concurrent operations, which could use up to 85GB
    of RAM(in case of ceph which uses the maximum memory for this operation).
    More details are added in the document.

    Closes-Bug: #1865011
    Co-authored-by: Rajat Dhasmana <email address hidden>
    Change-Id: Ica4e0cea67bc894f61a57c7898977951ce3a3633

Changed in cinder:
status: In Progress → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.