]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/pg_autoscaler: treat target ratios as weights
authorJosh Durgin <jdurgin@redhat.com>
Sat, 1 Feb 2020 04:31:40 +0000 (23:31 -0500)
committerKefu Chai <kchai@redhat.com>
Mon, 10 Feb 2020 02:08:36 +0000 (10:08 +0800)
Normalize across pools so that it's simpler to use - this way you
don't have to adjust every other pool when you add one.

Handle pools with target_bytes by taking their capacity off the top,
and dividing the rest into the pools with a target_ratio.

If both target bytes and ratio are specified, ignore bytes. This
matches the docs and makes accounting simpler.

Fixes: https://tracker.ceph.com/issues/43947
Signed-off-by: Josh Durgin <jdurgin@redhat.com>
qa/workunits/mon/pg_autoscaler.sh
src/pybind/mgr/pg_autoscaler/module.py

index 705a66604de15027045503dd2bebfa22f75aa340..e5bcb0b2d8a4de8edda6ed7e837970cb6e77e04d 100755 (executable)
@@ -70,9 +70,9 @@ ceph osd pool set b target_size_ratio 0
 # target_size
 ceph osd pool set a target_size_bytes 1000000000000000
 ceph osd pool set b target_size_bytes 1000000000000000
-wait_for 60 "ceph health detail | grep POOL_TARGET_SIZE_BYTES_OVERCOMMITTED"
-ceph osd pool set a target_size_bytes 0
+ceph osd pool set a target_size_ratio 0
 ceph osd pool set b target_size_ratio 0
+wait_for 60 "ceph health detail | grep POOL_TARGET_SIZE_BYTES_OVERCOMMITTED"
 
 ceph osd pool rm a a --yes-i-really-really-mean-it
 ceph osd pool rm b b --yes-i-really-really-mean-it
index 5cc5ee3e8ac48faba4c71c0cedb8f30bb0aaeb29..5ebc672f05532c19defc46abb30a56ad0a8884ec 100644 (file)
@@ -44,6 +44,22 @@ def nearest_power_of_two(n):
 
     return x if (v - n) > (n - x) else v
 
+def effective_target_ratio(target_ratio, total_target_ratio, total_target_bytes, capacity):
+    """
+    Returns the target ratio after normalizing for ratios across pools and
+    adjusting for capacity reserved by pools that have target_size_bytes set.
+    """
+    target_ratio = float(target_ratio)
+    if total_target_ratio:
+        target_ratio = target_ratio / total_target_ratio
+
+    if total_target_bytes and capacity:
+        fraction_available = 1.0 - min(1.0, float(total_target_bytes) / capacity)
+        target_ratio *= fraction_available
+
+    return target_ratio
+
+
 class PgAdjustmentProgress(object):
     """
     Keeps the initial and target pg_num values
@@ -200,6 +216,8 @@ class PgAutoscaler(MgrModule):
                 self.capacity = None  # Total capacity of OSDs in subtree
                 self.pool_ids = []
                 self.pool_names = []
+                self.total_target_ratio = 0.0
+                self.total_target_bytes = 0 # including replication / EC overhead
 
         # identify subtrees (note that they may overlap!)
         for pool_id, pool in osdmap.get_pools().items():
@@ -223,7 +241,13 @@ class PgAutoscaler(MgrModule):
             s.pool_ids.append(int(pool_id))
             s.pool_names.append(pool['pool_name'])
             s.pg_current += pool['pg_num_target'] * pool['size']
-
+            target_ratio = pool['options'].get('target_size_ratio', 0.0)
+            if target_ratio:
+                s.total_target_ratio += target_ratio
+            else:
+                target_bytes = pool['options'].get('target_size_bytes', 0)
+                if target_bytes:
+                    s.total_target_bytes += target_bytes * osdmap.pool_raw_used_rate(pool_id)
 
         # finish subtrees
         all_stats = self.get('osd_stats')
@@ -250,7 +274,6 @@ class PgAutoscaler(MgrModule):
 
         return result, pool_root
 
-
     def _get_pool_status(
             self,
             osdmap,
@@ -290,7 +313,10 @@ class PgAutoscaler(MgrModule):
 
             pool_logical_used = pool_stats[pool_id]['stored']
             bias = p['options'].get('pg_autoscale_bias', 1.0)
-            target_bytes = p['options'].get('target_size_bytes', 0)
+            target_bytes = 0
+            # ratio takes precedence if both are set
+            if p['options'].get('target_size_ratio', 0.0) == 0.0:
+                target_bytes = p['options'].get('target_size_bytes', 0)
 
             # What proportion of space are we using?
             actual_raw_used = pool_logical_used * raw_used_rate
@@ -299,7 +325,16 @@ class PgAutoscaler(MgrModule):
             pool_raw_used = max(pool_logical_used, target_bytes) * raw_used_rate
             capacity_ratio = float(pool_raw_used) / capacity
 
-            target_ratio = p['options'].get('target_size_ratio', 0.0)
+            self.log.info("effective_target_ratio {0} {1} {2} {3}".format(
+                p['options'].get('target_size_ratio', 0.0),
+                root_map[root_id].total_target_ratio,
+                root_map[root_id].total_target_bytes,
+                capacity))
+            target_ratio = effective_target_ratio(p['options'].get('target_size_ratio', 0.0),
+                                                  root_map[root_id].total_target_ratio,
+                                                  root_map[root_id].total_target_bytes,
+                                                  capacity)
+
             final_ratio = max(capacity_ratio, target_ratio)
 
             # So what proportion of pg allowance should we be using?
@@ -340,7 +375,7 @@ class PgAutoscaler(MgrModule):
                 'raw_used': pool_raw_used,
                 'actual_capacity_ratio': actual_capacity_ratio,
                 'capacity_ratio': capacity_ratio,
-                'target_ratio': target_ratio,
+                'target_ratio': p['options'].get('target_size_ratio', 0.0),
                 'pg_num_ideal': int(pool_pg_target),
                 'pg_num_final': final_pg_target,
                 'would_adjust': adjust,