diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
index 9b06a16bba6d1173a406d0cc0fcfb422badaa6de..183b2b42c8e5dc578ed5f4e240d9e7bda37b1cb4 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java
@@ -125,7 +125,7 @@ public class SummaryListener implements RateSummaryListener {
         _eventName = createName(_context, baseName + ".events");
         File rrdFile = null;
         try {
-            RrdBackendFactory factory = RrdBackendFactory.getFactory(getBackendName());
+            RrdBackendFactory factory = getBackendFactory();
             String rrdDefName;
             if (_isPersistent) {
                 // generate full path for persistent RRD files
@@ -133,7 +133,7 @@ public class SummaryListener implements RateSummaryListener {
                 rrdFile = new File(rrdDir, RRD_PREFIX + _name + RRD_SUFFIX);
                 rrdDefName = rrdFile.getAbsolutePath();
                 if (rrdFile.exists()) {
-                    _db = new RrdDb(rrdDefName, factory);
+                    _db = RrdDb.getBuilder().setPath(rrdDefName).setBackendFactory(factory).build();
                     Archive arch = _db.getArchive(CF, STEPS);
                     if (arch == null)
                         throw new IOException("No average CF in " + rrdDefName);
@@ -160,7 +160,7 @@ public class SummaryListener implements RateSummaryListener {
                     _rows = MIN_ROWS;
                 }
                 def.addArchive(CF, XFF, STEPS, _rows);
-                _db = new RrdDb(def, factory);
+                _db = RrdDb.getBuilder().setRrdDef(def).setBackendFactory(factory).build();
                 if (_isPersistent)
                     SecureFileOutputStream.setPerms(new File(rrdDefName));
                 if (_log.shouldLog(Log.INFO))
@@ -179,6 +179,12 @@ public class SummaryListener implements RateSummaryListener {
                 rrdFile.delete();
         } catch (IOException ioe) {
             _log.error("Error starting RRD for stat " + baseName, ioe);
+        } catch (IllegalArgumentException iae) {
+            // No backend from RrdBackendFactory
+            _log.error("Error starting RRD for stat " + baseName, iae);
+            _log.log(Log.CRIT, "rrd4j backend error, graphs disabled");
+            System.out.println("rrd4j backend error, graphs disabled");
+            StatSummarizer.setDisabled(_context);
         } catch (NoSuchMethodError nsme) {
             // Covariant fail Java 8/9/10
             // java.lang.NoSuchMethodError: java.nio.MappedByteBuffer.position(I)Ljava/nio/MappedByteBuffer;
@@ -207,7 +213,7 @@ public class SummaryListener implements RateSummaryListener {
         _rate.setSummaryListener(null);
         if (!_isPersistent) {
             // close() does not release resources for memory backend
-            ((RrdMemoryBackendFactory)RrdBackendFactory.getFactory("MEMORY")).delete(_db.getPath());
+            ((RrdMemoryBackendFactory)getBackendFactory(false)).delete(_db.getPath());
         }
         _db = null;
     }
@@ -254,9 +260,24 @@ public class SummaryListener implements RateSummaryListener {
 
     long now() { return _context.clock().now(); }
     
-    /** @since 0.8.7 */
-    String getBackendName() {
-        return _isPersistent ? "NIO" : "MEMORY";
+    /** @since 0.9.46 */
+    RrdBackendFactory getBackendFactory() {
+        return getBackendFactory(_isPersistent);
+    }
+
+    /** @since 0.9.46 */
+    @SuppressWarnings("deprecation")
+    private static RrdBackendFactory getBackendFactory(boolean isPersistent) {
+        // getFactory(String) is deprecated, but to avoid it
+        // we'd have to use findFactory(URI), but it only returns from the active factory list,
+        // so we'd have to call addActiveFactories(getFactory(String)) anyway.
+        //try {
+            return isPersistent ? RrdBackendFactory.getDefaultFactory()                   // NIO
+                                //: RrdBackendFactory.findFactory(new URI("memory:foo")); // MEMORY
+                                : RrdBackendFactory.getFactory("MEMORY");                 // MEMORY
+        //} catch (URISyntaxException use) {
+        //    throw new IllegalArgumentException(use);
+        //}
     }
 
     /** @since 0.8.7 */
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java
index 734bce6e2a8105ebda0ebf3187199f6879f774ce..efc7838008ab0ac14f81b106a45be6b84bd1f1a5 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java
@@ -26,6 +26,7 @@ import net.i2p.util.SystemVersion;
 
 import org.rrd4j.ConsolFun;
 import org.rrd4j.core.RrdException;
+import org.rrd4j.data.Variable;
 import org.rrd4j.graph.ElementsNames;
 import org.rrd4j.graph.RrdGraph;
 import org.rrd4j.graph.RrdGraphDef;
@@ -207,16 +208,22 @@ class SummaryRenderer {
             //if (started > start && started < end)
             //    def.vrule(started / 1000, RESTART_BAR_COLOR, _t("Restart"), 4.0f);
 
-            def.datasource(plotName, path, plotName, SummaryListener.CF, _listener.getBackendName());
+            def.datasource(plotName, path, plotName, SummaryListener.CF, _listener.getBackendFactory());
             if (descr.length() > 0) {
                 def.area(plotName, AREA_COLOR, descr + "\\l");
             } else {
                 def.area(plotName, AREA_COLOR);
             }
             if (!hideLegend) {
-                def.gprint(plotName, SummaryListener.CF, "   " + _t("Avg") + ": %.2f%s");
-                def.gprint(plotName, ConsolFun.MAX, ' ' + _t("Max") + ": %.2f%S");
-                def.gprint(plotName, ConsolFun.LAST, ' ' + _t("Now") + ": %.2f%S\\l");
+                Variable var = new Variable.AVERAGE();
+                def.datasource("avg", plotName, var);
+                def.gprint("avg", "   " + _t("Avg") + ": %.2f%s");
+                var = new Variable.MAX();
+                def.datasource("max", plotName, var);
+                def.gprint("max", ' ' + _t("Max") + ": %.2f%S");
+                var = new Variable.LAST();
+                def.datasource("last", plotName, var);
+                def.gprint("last", ' ' + _t("Now") + ": %.2f%S\\l");
             }
             String plotName2 = null;
             if (lsnr2 != null) {
@@ -224,12 +231,18 @@ class SummaryRenderer {
                 plotName2 = dsNames2[0];
                 String path2 = lsnr2.getData().getPath();
                 String descr2 = _t(lsnr2.getRate().getRateStat().getDescription());
-                def.datasource(plotName2, path2, plotName2, SummaryListener.CF, lsnr2.getBackendName());
+                def.datasource(plotName2, path2, plotName2, SummaryListener.CF, lsnr2.getBackendFactory());
                 def.line(plotName2, LINE_COLOR, descr2 + "\\l", 2);
                 if (!hideLegend) {
-                    def.gprint(plotName2, SummaryListener.CF, "   " + _t("Avg") + ": %.2f%s");
-                    def.gprint(plotName2, ConsolFun.MAX, ' ' + _t("Max") + ": %.2f%S");
-                    def.gprint(plotName2, ConsolFun.LAST, ' ' + _t("Now") + ": %.2f%S\\l");
+                    Variable var = new Variable.AVERAGE();
+                    def.datasource("avg2", plotName2, var);
+                    def.gprint("avg2", "   " + _t("Avg") + ": %.2f%s");
+                    var = new Variable.MAX();
+                    def.datasource("max2", plotName2, var);
+                    def.gprint("max2", ' ' + _t("Max") + ": %.2f%S");
+                    var = new Variable.LAST();
+                    def.datasource("last2", plotName2, var);
+                    def.gprint("last2", ' ' + _t("Now") + ": %.2f%S\\l");
                 }
             }
             if (!hideLegend) {