crimson-osd vs legacy-osd: should the perf difference be already noticeable?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




** resending to this list as well, since did not know that ceph-devel@
   is for kernel patches only

Hi folks,

I was curios to read some early performance benchmarks which compare
crimson-osd vs legacy-osd, but could not find any.  So eventually
decided to do my own micro benchmarks in order to test transport
together with PG layer, avoiding any storage costs completely
(no reason to test memcpy of memstore which is the only available
 objectstore for crimson).  At least recalling all these ad brochures
of seastar which should bring performance on another level by doing
preemption in userspace, the difference should be already there and
visible in numbers.

And yes I'm aware that crimson is in development, but if basic
functionality is already supported (like write path), then I can
squeeze some numbers.

For all testing loads I run original rbd.fio, taken from fio/examples/,
of course changing only block size.  Since this is a micro benchmark I
run only 1 osd cluster.

  [global]
  ioengine=rbd
  clientname=admin
  pool=rbd
  rbdname=fio_test
  rw=randwrite
  #bs=4k

  [rbd_iodepth32]
  iodepth=32


-- Part 1, turn MemStore and cyan_store into null block

Testing memcpy is not interesting so in order to run any memstore with
'memstore_debug_omit_block_device_write=true' option set and skip all
writes I have to do a small tweak in order to start osd, namely I still
need to pass small writes and omit big ones which are sent by the client,
something as the following:

- if (len > 0 && !local_conf()->memstore_debug_omit_block_device_write) {
+
+  if (len > 0 &&
+      (!local_conf()->memstore_debug_omit_block_device_write ||
+ // We still want cluster meta-data to be saved, so pass only small
+       // writes, expecting user writes will be >= 4k.
+       len < 4096)) {


*** BTW at the bottom you can find the whole patch with all debug
    modifications made to deliver these numbers.


# legacy-osd, MemStore

MON=1 MDS=0 OSD=1 MGR=1 ../src/vstart.sh  --memstore -n \
    -o 'memstore_debug_omit_block_device_write=true'

  4k  IOPS=42.7k,  BW=167MiB/s, Lat=749.18usec
  8k  IOPS=40.2k, BW=314MiB/s,  Lat=795.03usec
 16k  IOPS=37.6k, BW=588MiB/s,  Lat=849.12usec
 32k  IOPS=32.0k, BW=1000MiB/s, Lat=998.56usec
 64k  IOPS=25.5k, BW=1594MiB/s, Lat=1253.99usec
128k  IOPS=17.5k, BW=2188MiB/s, Lat=1826.54usec
256k  IOPS=10.1k, BW=2531MiB/s, Lat=3157.33usec
512k  IOPS=5252, BW=2626MiB/s,  Lat=6071.37usec
  1m  IOPS=2656, BW=2656MiB/s,  Lat=12029.65usec


# crimson-osd, cyan_store

MON=1 MDS=0 OSD=1 MGR=1 ../src/vstart.sh  --crimson --memstore -n \
    -o 'memstore_debug_omit_block_device_write=true'

  4k  IOPS=40.2k, BW=157MiB/s, Lat=796.07usec
  8k  IOPS=37.1k, BW=290MiB/s, Lat=861.51usec
 16k  IOPS=32.9k, BW=514MiB/s, Lat=970.99usec
 32k  IOPS=26.1k, BW=815MiB/s, Lat=1225.78usec
 64k  IOPS=21.3k, BW=1333MiB/s, Lat=1498.92usec
128k  IOPS=14.4k, BW=1795MiB/s, Lat=2227.07usec
256k  IOPS=6143, BW=1536MiB/s, Lat=5203.70usec
512k  IOPS=3776, BW=1888MiB/s, Lat=8464.79usec
  1m  IOPS=1866, BW=1867MiB/s, Lat=17126.36usec


First thing that catches my eye is that for small blocks there is no big
difference at all, but as the block increases, crimsons iops starts to
decline. Can it be the transport issue? Can be tested as well.


-- Part 2, complete writes immediately, even not leaving the transport

Would be great to avoid PG logic costs, exactly like we did for objectstore, i.e. the following question can be asked "how fast we can handle writes and
complete them immediately from the transport callback and measure socket
read/write costs?".  I introduced new option 'osd_immediate_completions'
and handle it directly from 'OSD::ms_[fast_]dispatch' function replying with
success just immediately (for details see patch at the bottom).


# legacy-osd

MON=1 MDS=0 OSD=1 MGR=1 ../src/vstart.sh --memstore -n \
    -o 'osd_immediate_completions=true'

  4k  IOPS=59.2k, BW=231MiB/s, Lat=539.68usec
  8k  IOPS=55.1k, BW=430MiB/s, Lat=580.44usec
 16k  IOPS=50.5k, BW=789MiB/s, Lat=633.03usec
 32k  IOPS=44.6k, BW=1394MiB/s, Lat=716.74usec
 64k  IOPS=33.5k, BW=2093MiB/s, Lat=954.60usec
128k  IOPS=20.8k, BW=2604MiB/s, Lat=1535.01usec
256k  IOPS=10.6k, BW=2642MiB/s, Lat=3026.19usec
512k  IOPS=5400, BW=2700MiB/s, Lat=5920.86usec
  1m  IOPS=2549, BW=2550MiB/s, Lat=12539.40usec


# crimson-osd

MON=1 MDS=0 OSD=1 MGR=1 ../src/vstart.sh --crimson --memstore -n \
    -o 'osd_immediate_completions=true'

  4k  IOPS=60.2k, BW=235MiB/s, Lat=530.95usec
  8k  IOPS=52.0k, BW=407MiB/s, Lat=614.21usec
 16k  IOPS=47.1k, BW=736MiB/s, Lat=678.41usec
 32k  IOPS=37.8k, BW=1180MiB/s, Lat=846.75usec
 64k  IOPS=26.6k, BW=1660MiB/s, Lat=1203.51usec
128k  IOPS=15.5k, BW=1936MiB/s, Lat=2064.12usec
256k  IOPS=7506, BW=1877MiB/s, Lat=4259.19usec
512k  IOPS=3941, BW=1971MiB/s, Lat=8112.67usec
  1m  IOPS=1785, BW=1786MiB/s, Lat=17896.44usec


As a summary I can say that for me is quite surprising not to notice any
iops improvements on crimson side (not to mention the problem with reading of big blocks). Since I run only 1 osd on one particular load I admit the
artificial nature of such tests (thus called micro benchmark), but then
on what cluster scale and what benchmark can I run to see some improvements
of a new architecture?

   Roman

---
 src/common/options.cc           |  4 ++++
 src/crimson/os/cyan_store.cc    |  6 +++++-
 src/crimson/osd/ops_executer.cc |  4 ++--
 src/crimson/osd/osd.cc          | 20 ++++++++++++++++++++
 src/os/memstore/MemStore.cc     |  6 +++++-
 src/osd/OSD.cc                  | 24 ++++++++++++++++++++++++
 6 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/src/common/options.cc b/src/common/options.cc
index d91827c1a803..769666d2955c 100644
--- a/src/common/options.cc
+++ b/src/common/options.cc
@@ -4234,6 +4234,10 @@ std::vector<Option> get_global_options() {
     .set_default(false)
     .set_description(""),

+ Option("osd_immediate_completions", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+    .set_default(false)
+    .set_description(""),
+
     // --------------------------
     // bluestore

diff --git a/src/crimson/os/cyan_store.cc b/src/crimson/os/cyan_store.cc
index f0749cb921f9..c05e0e40b721 100644
--- a/src/crimson/os/cyan_store.cc
+++ b/src/crimson/os/cyan_store.cc
@@ -463,7 +463,11 @@ int CyanStore::_write(const coll_t& cid, const ghobject_t& oid,
     return -ENOENT;

   ObjectRef o = c->get_or_create_object(oid);
- if (len > 0 && !local_conf()->memstore_debug_omit_block_device_write) {
+  if (len > 0 &&
+      (!local_conf()->memstore_debug_omit_block_device_write ||
+ // We still want cluster meta-data to be saved, so pass only small
+       // writes, expecting user writes will be >= 4k.
+       len < 4096)) {
     const ssize_t old_size = o->get_size();
     o->write(offset, bl);
     used_bytes += (o->get_size() - old_size);
diff --git a/src/crimson/osd/ops_executer.cc b/src/crimson/osd/ops_executer.cc
index 13f6f086c4ea..a76fc6e206d8 100644
--- a/src/crimson/osd/ops_executer.cc
+++ b/src/crimson/osd/ops_executer.cc
@@ -431,8 +431,8 @@ OpsExecuter::execute_osd_op(OSDOp& osd_op)

   default:
     logger().warn("unknown op {}", ceph_osd_op_name(op.op));
-    throw std::runtime_error(
-      fmt::format("op '{}' not supported", ceph_osd_op_name(op.op)));
+    // Without that `fio examples/rbd.fio` hangs on exit
+    throw ceph::osd::operation_not_supported{};
   }
 }

diff --git a/src/crimson/osd/osd.cc b/src/crimson/osd/osd.cc
index ddd8742d1a74..737cc266766e 100644
--- a/src/crimson/osd/osd.cc
+++ b/src/crimson/osd/osd.cc
@@ -17,6 +17,7 @@
 #include "messages/MOSDOp.h"
 #include "messages/MOSDPGLog.h"
 #include "messages/MOSDRepOpReply.h"
+#include "messages/MOSDOpReply.h"
 #include "messages/MPGStats.h"

 #include "os/Transaction.h"
@@ -881,6 +882,25 @@ seastar::future<> OSD::committed_osd_maps(version_t first,
 seastar::future<> OSD::handle_osd_op(ceph::net::Connection* conn,
                                      Ref<MOSDOp> m)
 {
+
+  //
+  // Immediately complete requests even without leaving the transport
+  //
+  if (local_conf().get_val<bool>("osd_immediate_completions")) {
+    m->finish_decode();
+
+    for (auto op : m->ops) {
+      if (op.op.op == CEPH_OSD_OP_WRITE &&
+          // Complete big writes only
+          op.op.extent.length >= 4096) {
+
+ auto reply = make_message<MOSDOpReply>(m.get(), 0, osdmap->get_epoch(), + CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK, true);
+        return conn->send(reply);
+      }
+    }
+  }
+
   shard_services.start_operation<ClientRequest>(
     *this,
     conn->get_shared(),
diff --git a/src/os/memstore/MemStore.cc b/src/os/memstore/MemStore.cc
index 05d16edb6cc0..265dc64c808d 100644
--- a/src/os/memstore/MemStore.cc
+++ b/src/os/memstore/MemStore.cc
@@ -1047,7 +1047,11 @@ int MemStore::_write(const coll_t& cid, const ghobject_t& oid,
     return -ENOENT;

   ObjectRef o = c->get_or_create_object(oid);
-  if (len > 0 && !cct->_conf->memstore_debug_omit_block_device_write) {
+  if (len > 0 &&
+      (!cct->_conf->memstore_debug_omit_block_device_write ||
+ // We still want cluster meta-data to be saved, so pass only small
+       // writes, expecting user writes will be bigger than 4k.
+       len < 4096)) {
     const ssize_t old_size = o->get_size();
     o->write(offset, bl);
     used_bytes += (o->get_size() - old_size);
diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc
index 96aed0b706e3..796bf927126f 100644
--- a/src/osd/OSD.cc
+++ b/src/osd/OSD.cc
@@ -7223,6 +7223,30 @@ void OSD::ms_fast_dispatch(Message *m)
     return;
   }

+  //
+  // Immediately complete requests even without leaving the transport
+  //
+  if (g_conf().get_val<bool>("osd_immediate_completions") &&
+      m->get_type() == CEPH_MSG_OSD_OP) {
+    MOSDOp *osdop = static_cast<MOSDOp*>(m);
+
+    osdop->finish_decode();
+
+    for (auto op : osdop->ops) {
+      if (op.op.op == CEPH_OSD_OP_WRITE &&
+          // Complete big writes only
+          op.op.extent.length >= 4096) {
+        MOSDOpReply *reply;
+
+        reply = new MOSDOpReply(osdop, 0, osdmap->get_epoch(),
+ CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK, true);
+        osdop->get_connection()->send_message(reply);
+        m->put();
+        return;
+      }
+    }
+  }
+
   // peering event?
   switch (m->get_type()) {
   case CEPH_MSG_PING:
_______________________________________________
Dev mailing list -- dev@xxxxxxx
To unsubscribe send an email to dev-leave@xxxxxxx



[Index of Archives]     [CEPH Users]     [Ceph Devel]     [Ceph Large]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux