]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: support osd_numa_node, osd_numa_auto_affinity, osd_numa_prefer_iface
authorSage Weil <sage@redhat.com>
Fri, 4 Jan 2019 18:11:04 +0000 (12:11 -0600)
committerSage Weil <sage@redhat.com>
Tue, 8 Jan 2019 18:57:00 +0000 (12:57 -0600)
- osd_numa_node manually specifies a numa node.
- osd_numa_prefer_iface makes us prefer IPs in public_network that are
  on the same numa node as the storage
- osd_numa_auto_affinity will set affinity to a numa node when both the
  store and network(s) are on the same numa node.

These options are all flagged as 'startup', although osd_numa_node and
osd_numa_auto_affinity takes effect when the OSD is marked up, so doing
'ceph osd down ...' is sufficient to induce an update.

Signed-off-by: Sage Weil <sage@redhat.com>
src/ceph_osd.cc
src/common/options.cc
src/osd/OSD.cc
src/osd/OSD.h

index 7a00a81730720785dfee0c06fc725daee0af0183..0a4814cf5413701f0ecbb1659de5c4cec0682fb8 100644 (file)
@@ -35,6 +35,7 @@
 #include "common/Timer.h"
 #include "common/TracepointProvider.h"
 #include "common/ceph_argparse.h"
+#include "common/numa.h"
 
 #include "global/global_init.h"
 #include "global/signal_handler.h"
@@ -471,6 +472,18 @@ flushjournal_out:
     forker.exit(0);
   }
 
+  // consider objectstore numa node
+  int os_numa_node = -1;
+  r = store->get_numa_node(&os_numa_node, nullptr, nullptr);
+  if (r >= 0 && os_numa_node >= 0) {
+    dout(1) << " objectstore numa_node " << os_numa_node << dendl;
+  }
+  int iface_preferred_numa_node = -1;
+  if (g_conf().get_val<bool>("osd_numa_prefer_iface")) {
+    iface_preferred_numa_node = os_numa_node;
+  }
+
+  // messengers
   std::string msg_type = g_conf().get_val<std::string>("ms_type");
   std::string public_msg_type =
     g_conf().get_val<std::string>("ms_public_type");
@@ -561,12 +574,14 @@ flushjournal_out:
   ms_objecter->set_default_policy(Messenger::Policy::lossy_client(CEPH_FEATURE_OSDREPLYMUX));
 
   entity_addrvec_t public_addrs, cluster_addrs;
-  r = pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC, &public_addrs);
+  r = pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC, &public_addrs,
+                    iface_preferred_numa_node);
   if (r < 0) {
     derr << "Failed to pick public address." << dendl;
     forker.exit(1);
   }
-  r = pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_CLUSTER, &cluster_addrs);
+  r = pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_CLUSTER, &cluster_addrs,
+                    iface_preferred_numa_node);
   if (r < 0) {
     derr << "Failed to pick cluster address." << dendl;
     forker.exit(1);
index d54da1e8adf5114f882d26341530540dbfa265ff..0b1038100a406b5cd70dace9456edc29072b9043 100644 (file)
@@ -2173,6 +2173,23 @@ std::vector<Option> get_global_options() {
     .set_description("Number of striping periods to zero head of MDS journal write position"),
 
     // -- OSD --
+    Option("osd_numa_prefer_iface", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+    .set_default(true)
+    .set_flag(Option::FLAG_STARTUP)
+    .set_description("prefer IP on network interface on same numa node as storage")
+    .add_see_also("osd_numa_auto_affinity"),
+
+    Option("osd_numa_auto_affinity", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+    .set_default(true)
+    .set_flag(Option::FLAG_STARTUP)
+    .set_description("automatically set affinity to numa node when storage and network match"),
+
+    Option("osd_numa_node", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+    .set_default(-1)
+    .set_flag(Option::FLAG_STARTUP)
+    .set_description("set affinity to a numa node (-1 for none)")
+    .add_see_also("osd_numa_auto_affinity"),
+
     Option("osd_smart_report_timeout", Option::TYPE_UINT, Option::LEVEL_ADVANCED)
     .set_default(5)
     .set_description("Timeout (in seconds) for smarctl to run, default is set to 5"),
index ab1a7db4d5a06fb8fff1360aaefa1b2d44c718ba..f24e25fe2bd7db1133f297183db1a0f283346810 100644 (file)
@@ -2237,6 +2237,75 @@ int OSD::pre_init()
   return 0;
 }
 
+int OSD::set_numa_affinity()
+{
+  // storage numa node
+  int store_node = -1;
+  store->get_numa_node(&store_node, nullptr, nullptr);
+  if (store_node >= 0) {
+    dout(1) << __func__ << " storage numa node " << store_node << dendl;
+  }
+
+  // check network numa node(s)
+  int front_node = -1, back_node = -1;
+  string front_iface = pick_iface(
+    cct,
+    client_messenger->get_myaddrs().front().get_sockaddr_storage());
+  string back_iface = pick_iface(
+    cct,
+    cluster_messenger->get_myaddrs().front().get_sockaddr_storage());
+  int r = get_iface_numa_node(front_iface, &front_node);
+  if (r >= 0) {
+    dout(1) << __func__ << " public network " << front_iface << " numa node "
+             << front_node << dendl;
+    r = get_iface_numa_node(back_iface, &back_node);
+    if (r >= 0) {
+      dout(1) << __func__ << " cluster network " << back_iface << " numa node "
+             << back_node << dendl;
+      if (front_node == back_node &&
+         front_node == store_node) {
+       dout(1) << " objectstore and network numa nodes all match" << dendl;
+       if (g_conf().get_val<bool>("osd_numa_auto_affinity")) {
+         numa_node = front_node;
+       }
+      } else {
+       derr << __func__ << " objectstore and network numa nodes to not match"
+            << dendl;
+      }
+    }
+  } else {
+    derr << __func__ << " unable to identify public interface '" << front_iface
+        << "' numa node: " << cpp_strerror(r) << dendl;
+  }
+  if (int node = g_conf().get_val<int64_t>("osd_numa_node"); node >= 0) {
+    // this takes precedence over the automagic logic above
+    numa_node = node;
+  }
+  if (numa_node >= 0) {
+    int r = get_numa_node_cpu_set(numa_node, &numa_cpu_set_size, &numa_cpu_set);
+    if (r < 0) {
+      dout(1) << __func__ << " unable to determine numa node " << numa_node
+             << " CPUs" << dendl;
+      numa_node = -1;
+    } else {
+      dout(1) << __func__ << " setting numa affinity to node " << numa_node
+             << " cpus "
+             << cpu_set_to_str_list(numa_cpu_set_size, &numa_cpu_set)
+             << dendl;
+      r = sched_setaffinity(getpid(), numa_cpu_set_size, &numa_cpu_set);
+      if (r < 0) {
+       r = -errno;
+       derr << __func__ << " failed to set numa affinity: " << cpp_strerror(r)
+            << dendl;
+       numa_node = -1;
+      }
+    }
+  } else {
+    dout(1) << __func__ << " not setting numa affinity" << dendl;
+  }
+  return 0;
+}
+
 // asok
 
 class OSDSocketHook : public AdminSocketHook {
@@ -5743,6 +5812,11 @@ void OSD::_send_boot()
     hb_front_server_messenger->ms_deliver_handle_fast_connect(local_connection);
   }
 
+  // we now know what our front and back addrs will be, and we are
+  // about to tell the mon what our metadata (including numa bindings)
+  // are, so now is a good time!
+  set_numa_affinity();
+
   MOSDBoot *mboot = new MOSDBoot(
     superblock, get_osdmap_epoch(), service.get_boot_epoch(),
     hb_back_addrs, hb_front_addrs, cluster_addrs,
@@ -5790,17 +5864,14 @@ void OSD::_collect_metadata(map<string,string> *pm)
   {
     int node = -1;
     set<int> nodes;
-    string cpu_list;
     set<string> unknown;
     for (auto nm : { "front_iface", "back_iface" }) {
       if (!(*pm)[nm].size()) {
        unknown.insert(nm);
        continue;
       }
-      cpu_set_t cpu_set;
-      size_t cpu_set_size;
       int n = -1;
-      int r = get_iface_numa_node((*pm)[nm], &n, &cpu_set_size, &cpu_set);
+      int r = get_iface_numa_node((*pm)[nm], &n);
       if (r < 0) {
        unknown.insert((*pm)[nm]);
        continue;
@@ -5808,7 +5879,6 @@ void OSD::_collect_metadata(map<string,string> *pm)
       nodes.insert(n);
       if (node < 0) {
        node = n;
-       cpu_list = cpu_set_to_str_list(cpu_set_size, &cpu_set);
       }
     }
     if (unknown.size()) {
@@ -5819,10 +5889,15 @@ void OSD::_collect_metadata(map<string,string> *pm)
     }
     if (node >= 0 && nodes.size() == 1 && unknown.empty()) {
       (*pm)["network_numa_node"] = stringify(node);
-      (*pm)["network_numa_node_cpus"] = cpu_list;
     }
   }
-  
+
+  if (numa_node >= 0) {
+    (*pm)["numa_node"] = stringify(numa_node);
+    (*pm)["numa_node_cpus"] = cpu_set_to_str_list(numa_cpu_set_size,
+                                                 &numa_cpu_set);
+  }
+
   set<string> devnames;
   store->get_devices(&devnames);
   (*pm)["devices"] = stringify(devnames);
index d1c16d6bf332693008b0dbd765a0effda14620f5..b875200bc3b79f0a5accd72886f7249efb3a25e7 100644 (file)
@@ -1293,6 +1293,10 @@ protected:
   int whoami;
   std::string dev_path, journal_path;
 
+  int numa_node = -1;
+  size_t numa_cpu_set_size = 0;
+  cpu_set_t numa_cpu_set;
+
   bool store_is_rotational = true;
   bool journal_is_rotational = true;
 
@@ -2300,6 +2304,7 @@ public:
   void final_init();
 
   int enable_disable_fuse(bool stop);
+  int set_numa_affinity();
 
   void suicide(int exitcode);
   int shutdown();