Francesco Romani has uploaded a new change for review.

Change subject: periodic: explicitely track domain availability
......................................................................

periodic: explicitely track domain availability

The periodic sampling code knows that libvirt can become clogged
(most common case: unresponsive storage) and tries to not make
things worse, avoiding to schedule work on unresponding domain.

To do so, the code needs a way to know or at least guesstimate
the libvirt responsiveness.

The initial implementation relied on virDomainGetControlInfo,
which reports if there is any monitor job currently running, or not.

This approach has the plus to have one single source of information,
which is also the most reliable - libvirt. But it also creates a
a dangerous short circuit, because the controller relies on the
controlled itself to assess its health.

Furthermore, we experienced firsthand a bad failure of the
aforementioned control code under high scale, and this was the
final blow to the initial approach.
We need to try another way to solve this problem, without
depend on libvirt so much.

Now VDSM counts explicitely the uses of a given domain, using
a ExpiringCache per operation,  in order to minimize the
inter-operation interference. We want to avoid false negative
as top-priority, but once this is granted, we also want to minimize
the false positive!

The rational for this change is
- isDomainReadyForCommands, which we used previously, needs
  o access libvirt, thus can actually make things worse on extreme
  load conditions.
- under normal load, reduce the interference and false positives
  between operations

Change-Id: Idd90750ab36cb90bad401fab0ff7ff98429e78a5
Bug-Url: https://bugzilla.redhat.com/1250839
Signed-off-by: Francesco Romani <from...@redhat.com>
---
M tests/periodicTests.py
M vdsm/virt/periodic.py
M vdsm/virt/sampling.py
3 files changed, 23 insertions(+), 31 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/46/47246/1

diff --git a/tests/periodicTests.py b/tests/periodicTests.py
index ce4d592..1d730b7 100644
--- a/tests/periodicTests.py
+++ b/tests/periodicTests.py
@@ -241,8 +241,9 @@
 
     VMS = defaultdict(int)
 
-    def __init__(self, vm):
+    def __init__(self, vm, skip_doms):
         self._vm = vm
+        self._skip_doms = skip_doms
 
     @property
     def required(self):
@@ -250,26 +251,19 @@
             raise ValueError('required failed')
         return True
 
-    @property
-    def runnable(self):
-        if getattr(self._vm, 'fail_runnable', False):
-            raise ValueError('runnable failed')
-        return True
-
     def __call__(self):
-        _Visitor.VMS[self._vm.id] += 1
+        vm_id = self._vm.id
+        self._skip_doms[vm_id] = True
+        _Visitor.VMS[vm_id] += 1
+        del self._skip_doms[vm_id]
 
 
 class _Nop(object):
-    def __init__(self, _):
+    def __init__(self, *args):
         pass
 
     @property
     def required(self):
-        return True
-
-    @property
-    def runnable(self):
         return True
 
     def __call__(self):
diff --git a/vdsm/virt/periodic.py b/vdsm/virt/periodic.py
index 13d7632..9c05f30 100644
--- a/vdsm/virt/periodic.py
+++ b/vdsm/virt/periodic.py
@@ -31,6 +31,7 @@
 
 from . import sampling
 from . import virdomain
+from .utils import ExpiringCache
 
 
 # just a made up number. Maybe should be equal to number of cores?
@@ -215,6 +216,7 @@
         self._executor = executor
         self._create = create
         self._timeout = timeout
+        self._skip_doms = ExpiringCache(ttl=sampling.TIMEOUT)
 
     def __call__(self):
         vms = self._get_vms()
@@ -222,7 +224,11 @@
 
         for vm_id, vm_obj in vms.iteritems():
             try:
-                op = self._create(vm_obj)
+                to_skip = self._skip_doms.get(vm_id, False)
+                if to_skip:
+                    continue
+
+                op = self._create(vm_obj, self._skip_doms)
 
                 if not op.required:
                     continue
@@ -233,9 +239,6 @@
                 # still OK if occasional misdetection occours, but we
                 # definitely want to avoid known-bad situation and to
                 # needlessly overload libvirt.
-                if not op.runnable:
-                    skipped.append(vm_id)
-                    continue
 
             except Exception:
                 # we want to make sure to have VM UUID logged
@@ -257,14 +260,13 @@
 
 
 class _RunnableOnVm(object):
-    def __init__(self, vm):
+    def __init__(self, vm, skip_doms):
         self._vm = vm
-
-    @property
-    def runnable(self):
-        return self._vm.isDomainReadyForCommands()
+        self._skip_doms = skip_doms
 
     def __call__(self):
+        vm_id = self._vm.id  # keep reference for safety
+        self._skip_doms[vm_id] = True
         try:
             self._execute()
         except virdomain.NotConnectedError:
@@ -272,7 +274,9 @@
             # race on shutdown: next cycle won't pick up this VM.
             # both cases: let's reduce the log spam.
             self._vm.log.warning('could not run on %s: domain not connected',
-                                 self._vm.id)
+                                 vm_id)
+        finally:
+            del self._skip_doms[vm_id]
 
     def _execute(self):
         raise NotImplementedError
@@ -298,12 +302,6 @@
     @property
     def required(self):
         return self._vm.hasGuestNumaNode
-
-    @property
-    def runnable(self):
-        # NUMA operations don't require QEMU monitor access
-        # (inspected libvirt sources v1.2.17)
-        return True
 
     def _execute(self):
         self._vm.updateNumaInfo()
diff --git a/vdsm/virt/sampling.py b/vdsm/virt/sampling.py
index 1ad9d46..6f8ecce 100644
--- a/vdsm/virt/sampling.py
+++ b/vdsm/virt/sampling.py
@@ -501,12 +501,12 @@
 # a multiple of known timeout and period:
 # - vm sampling period is 15s (we control that)
 # - libvirt (default) qemu monitor timeout is 30s (we DON'T contol this)
-_TIMEOUT = 40.0
+TIMEOUT = 40.0
 
 
 class VMBulkSampler(object):
     def __init__(self, conn, get_vms, stats_cache,
-                 stats_flags=0, timeout=_TIMEOUT):
+                 stats_flags=0, timeout=TIMEOUT):
         self._conn = conn
         self._get_vms = get_vms
         self._stats_cache = stats_cache


-- 
To view, visit https://gerrit.ovirt.org/47246
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idd90750ab36cb90bad401fab0ff7ff98429e78a5
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <from...@redhat.com>
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to