diff --git a/core/core.services.yml b/core/core.services.yml
index c3bb8d2..d28d5d7 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -22,6 +22,13 @@ services:
     arguments: ['@request', '@theme.negotiator']
     tags:
       - { name: cache.context}
+  cache_inconsistent_factory:
+    class: Drupal\Core\Cache\InconsistentBackendFactory
+    arguments: ['@settings']
+    calls:
+      - [setContainer, ['@service_container']]
+  cache.backend.apc:
+    class: Drupal\Core\Cache\ApcBackendFactory
   cache.backend.database:
     class: Drupal\Core\Cache\DatabaseBackendFactory
     arguments: ['@database']
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index d6e6aee..d660a95 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -904,8 +904,12 @@ function drupal_serve_page_from_cache(stdClass $cache, Response $response, Reque
   }
   $response->headers->set('Cache-Control', 'public, max-age=' . $max_age);
 
+  // Cache items have a created time accurate to the millisecond, however http
+  // times only work up to the second, round created.
+  $created = (int) $cache->created;
+
   // Entity tag should change if the output changes.
-  $response->setEtag($cache->created);
+  $response->setEtag($created);
 
   // See if the client has provided the required HTTP headers.
   $if_modified_since = $request->server->has('HTTP_IF_MODIFIED_SINCE') ? strtotime($request->server->get('HTTP_IF_MODIFIED_SINCE')) : FALSE;
@@ -913,7 +917,7 @@ function drupal_serve_page_from_cache(stdClass $cache, Response $response, Reque
 
   if ($if_modified_since && $if_none_match
       && $if_none_match == $response->headers->get('etag') // etag must match
-      && $if_modified_since == $cache->created) {  // if-modified-since must match
+      && $if_modified_since == $created) {  // if-modified-since must match
     $response->setStatusCode(304);
     return;
   }
@@ -926,7 +930,7 @@ function drupal_serve_page_from_cache(stdClass $cache, Response $response, Reque
     drupal_add_http_header($name, $value);
   }
 
-  $response->setLastModified(\DateTime::createFromFormat('U', $cache->created));
+  $response->setLastModified(\DateTime::createFromFormat('U', $created));
 
   // HTTP/1.0 proxies does not support the Vary header, so prevent any caching
   // by sending an Expires date in the past. HTTP/1.1 clients ignores the
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 46a9356..aa3d47d 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3008,7 +3008,7 @@ function drupal_page_set_cache(Response $response, Request $request) {
       ),
       'tags' => HtmlViewSubscriber::convertHeaderToCacheTags($response->headers->get('X-Drupal-Cache-Tags')),
       'expire' => Cache::PERMANENT,
-      'created' => REQUEST_TIME,
+      'created' => microtime(TRUE),
     );
 
     $cache->data['headers'] = $response->headers->all();
diff --git a/core/lib/Drupal/Core/Cache/ApcBackend.php b/core/lib/Drupal/Core/Cache/ApcBackend.php
new file mode 100644
index 0000000..397dbf7
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ApcBackend.php
@@ -0,0 +1,320 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\ApcBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines an APC user cache implementation.
+ *
+ * @ingroup cache
+ */
+class ApcBackend implements CacheBackendInterface {
+
+  /**
+   * @var string
+   */
+  protected $tagPrefix;
+
+  /**
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * Constructs an ApcBackend object.
+   *
+   * @param string $bin
+   *   The cache bin for which the object is created.
+   */
+  public function __construct($bin) {
+    $bin = 'cache_' . $bin;
+    $this->bin = $bin;
+    $this->tagPrefix = 'tags-' . $this->bin . '_';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid, $allow_invalid = FALSE) {
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids, $allow_invalid);
+    return reset($cache);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items) {
+    $prefixed_items = array();
+    foreach ($items as $cid => $item) {
+      $prefixed_items[$this->bin . '-' . $cid] = $item;
+    }
+    apc_store($prefixed_items);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids, $allow_invalid = FALSE) {
+    $prefixed_cids = array();
+    foreach ($cids as $cid) {
+      $prefixed_cids[$this->bin . '-' . $cid] = $cid;
+    }
+    $result = apc_fetch(array_keys($prefixed_cids));
+    $cache = array();
+    foreach ($result as $item) {
+      if ($item = $this->prepareItem($item, $allow_invalid)) {
+        $cache[$item->cid] = $item;
+      }
+    }
+    $cids = array_diff($cids, array_keys($cache));
+    return $cache;
+  }
+
+  /**
+   * Prepares a cached item.
+   *
+   * Checks that items are either permanent or did not expire, and unserializes
+   * data as appropriate.
+   *
+   * @param object $cache
+   *   An item loaded from cache_get() or cache_get_multiple().
+   * @param bool $allow_invalid
+   *   If FALSE, the method returns FALSE if the cache item is not valid.
+   *
+   * @return mixed|false
+   *   The item with data unserialized as appropriate and a property indicating
+   *   whether the item is valid, or FALSE if there is no valid item to load.
+   */
+  protected function prepareItem($cache, $allow_invalid) {
+    if (!isset($cache->data)) {
+      return FALSE;
+    }
+
+    $cache->tags = $cache->tags ? explode(' ', $cache->tags) : array();
+
+    $checksum = $this->checksumTags($cache->tags);
+
+    // Check if deleteTags() has been called with any of the entry's tags.
+    if ($cache->checksum_deletions != $checksum['deletions']) {
+      return FALSE;
+    }
+
+    // Check expire time.
+    $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME;
+
+    // Check if invalidateTags() has been called with any of the entry's tags.
+    if ($cache->checksum_invalidations != $checksum['invalidations']) {
+      $cache->valid = FALSE;
+    }
+
+    if (!$allow_invalid && !$cache->valid) {
+      return FALSE;
+    }
+
+    // Unserialize and return the cached data.
+    if ($cache->serialized) {
+      $cache->data = unserialize($cache->data);
+    }
+
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
+    $flat_tags = $this->flattenTags($tags);
+    $deleted_tags = &drupal_static('Drupal\Core\Cache\ApcBackend::deletedTags', array());
+    $invalidated_tags = &drupal_static('Drupal\Core\Cache\ApcBackend::invalidatedTags', array());
+    // Remove tags that were already deleted or invalidated during this request
+    // from the static caches so that another deletion or invalidation can
+    // occur.
+    foreach ($flat_tags as $tag) {
+      if (isset($deleted_tags[$tag])) {
+        unset($deleted_tags[$tag]);
+      }
+      if (isset($invalidated_tags[$tag])) {
+        unset($invalidated_tags[$tag]);
+      }
+    }
+    $checksum = $this->checksumTags($flat_tags);
+    $fields = (object) array(
+      'serialized' => 0,
+      'created' => microtime(TRUE),
+      'expire' => $expire,
+      'tags' => implode(' ', $flat_tags),
+      'checksum_invalidations' => $checksum['invalidations'],
+      'checksum_deletions' => $checksum['deletions'],
+      'cid' => $cid,
+      'data' => $data,
+      'serialized' => 0,
+    );
+    apc_store(array($this->bin . '-' . $cid => $fields));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    $this->deleteMultiple(array($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    $prefixed_cids = array();
+    foreach ($cids as $cid) {
+      $prefixed_cids[$this->bin . '-' . $cid] = $cid;
+    }
+    apc_delete($prefixed_cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteTags(array $tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
+    $deleted_tags = &drupal_static('Drupal\Core\Cache\ApcBackend::deletedTags', array());
+    foreach ($this->flattenTags($tags) as $tag) {
+      // Only delete tags once per request unless they are written again.
+      if (isset($deleted_tags[$tag])) {
+        continue;
+      }
+      $deleted_tags[$tag] = TRUE;
+      unset($tag_cache[$tag]);
+      $prefixed_tags = $this->tagPrefix . $tag;
+    }
+    apc_delete($prefixed_tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    apc_delete(new APCIterator('user', '/^' . $this->bin . '-/'));
+    apc_delete(new APCIterator('user', '/^' . $this->tagPrefix . '/'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidate($cid) {
+    $this->invalidateMultiple(array($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateMultiple(array $cids) {
+    $this->deleteMultiple($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateTags(array $tags) {
+    foreach ($tags as $tag) {
+      apc_inc($this->tagPrefix . $tag);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateAll() {
+    $this->deleteAll();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    // No work to be done.
+  }
+
+  /**
+   * 'Flattens' a tags array into an array of strings.
+   *
+   * @param array $tags
+   *   Associative array of tags to flatten.
+   *
+   * @return array
+   *   An indexed array of flattened tag identifiers.
+   */
+  protected function flattenTags(array $tags) {
+    if (isset($tags[0])) {
+      return $tags;
+    }
+
+    $flat_tags = array();
+    foreach ($tags as $namespace => $values) {
+      if (is_array($values)) {
+        foreach ($values as $value) {
+          $flat_tags[] = "$namespace:$value";
+        }
+      }
+      else {
+        $flat_tags[] = "$namespace:$values";
+      }
+    }
+    return $flat_tags;
+  }
+
+  /**
+   * Returns the sum total of validations for a given set of tags.
+   *
+   * @param array $flat_tags
+   *   Array of flat tags.
+   *
+   * @return array
+   *   Array containing the sums of all invalidations and deletions.
+   *
+   * @see \Drupal\Core\Cache\ApcBackend::flattenTags()
+   */
+  protected function checksumTags($flat_tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
+
+    $checksum = array(
+      'invalidations' => 0,
+      'deletions' => 0,
+    );
+
+    $query_tags = array_diff($flat_tags, array_keys($tag_cache));
+    if ($query_tags) {
+      $db_tags = apc_fetch($flat_tags);
+      $tag_cache += $db_tags;
+
+      // Fill static cache with empty objects for tags not found in the APC user
+      // cache.
+      $tag_cache += array_fill_keys(array_diff($query_tags, array_keys($db_tags)), $checksum);
+    }
+
+    foreach ($flat_tags as $tag) {
+      $checksum['invalidations'] += $tag_cache[$tag]['invalidations'];
+      $checksum['deletions'] += $tag_cache[$tag]['deletions'];
+    }
+
+    return $checksum;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    $apc = new ApcIterator('user');
+    return $apc->getTotalCount > 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/ApcBackendFactory.php b/core/lib/Drupal/Core/Cache/ApcBackendFactory.php
new file mode 100644
index 0000000..86e9c5f
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ApcBackendFactory.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\ApcBackendFactory.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines the APC cache backend factory.
+ */
+use Drupal\Component\Utility\Settings;
+
+class ApcBackendFactory implements CacheFactoryInterface {
+
+  /**
+   * Instantiates a cache backend class for a given cache bin.
+   *
+   * @param string $bin
+   *   The cache bin for which a cache backend object should be returned.
+   *
+   * @return \Drupal\Core\Cache\ApcBackend
+   *   An APC cache backend for the given bin.
+   */
+  public function get($bin) {
+    return new ApcBackend($bin);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 3ae9eac..26e1bd0 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -25,7 +25,6 @@ class DatabaseBackend implements CacheBackendInterface {
    */
   protected $bin;
 
-
   /**
    * The database connection.
    *
@@ -180,7 +179,7 @@ protected function doSet($cid, $data, $expire, $tags) {
     $checksum = $this->checksumTags($flat_tags);
     $fields = array(
       'serialized' => 0,
-      'created' => REQUEST_TIME,
+      'created' => microtime(TRUE),
       'expire' => $expire,
       'tags' => implode(' ', $flat_tags),
       'checksum_invalidations' => $checksum['invalidations'],
@@ -460,15 +459,15 @@ protected function flattenTags(array $tags) {
   /**
    * Returns the sum total of validations for a given set of tags.
    *
-   * @param array $tags
+   * @param array $flat_tags
    *   Array of flat tags.
    *
-   * @return int
-   *   Sum of all invalidations.
+   * @return array
+   *   Array containing the sums of all invalidations and deletions.
    *
    * @see \Drupal\Core\Cache\DatabaseBackend::flattenTags()
    */
-  protected function checksumTags($flat_tags) {
+  protected function checksumTags(array $flat_tags) {
     $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
 
     $checksum = array(
@@ -594,8 +593,10 @@ public function schemaDefinition() {
         ),
         'created' => array(
           'description' => 'A Unix timestamp indicating when the cache entry was created.',
-          'type' => 'int',
+          'type' => 'numeric',
           'not null' => TRUE,
+          'precision' => 14,
+          'scale' => 3,
           'default' => 0,
         ),
         'serialized' => array(
diff --git a/core/lib/Drupal/Core/Cache/InconsistentBackend.php b/core/lib/Drupal/Core/Cache/InconsistentBackend.php
new file mode 100644
index 0000000..343c0a5
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/InconsistentBackend.php
@@ -0,0 +1,260 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\InconsistentBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+use Drupal\Core\State\StateInterface;
+
+/**
+ * Defines a backend with an inconsistent and consistent backend chain.
+ *
+ * We always use the inconsistent (but faster) backend when reading (get())
+ * entries from cache, but check whether they were created before the last write
+ * (set()) to this (chained) cache backend. Those cache entries that were
+ * created before the last write are discarded, but we use their cache IDs to
+ * then read them from the consistent (slower) cache backend instead; at the
+ * same time we update the inconsistent cache backend so that the next read will
+ * hit the (faster) inconsistent backend again. Hence we can guarantee that the
+ * cache entries we return are all up-to-date, and maximally exploit the faster
+ * cache backend.
+ * This cache backend uses and maintains a "last write timestamp" to determine
+ * which cache entries should be discarded.
+ *
+ * @ingroup cache
+ */
+class InconsistentBackend implements CacheBackendInterface {
+
+  /**
+   * State entry key prefix, for the bin-specific entry to track the last write.
+   */
+  const LAST_WRITE_TIMESTAMP_PREFIX = 'cache_last_write_timestamp_';
+
+  /**
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * The consistent cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $consistentBackend;
+
+  /**
+   * The inconsistent cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $inconsistentBackend;
+
+  /**
+   * The state instance to get and set the last write timestamp.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * The time at which the last write to this cache bin happened.
+   *
+   * @var int
+   */
+  protected $lastWriteTimestamp;
+
+  /**
+   * Constructs a InconsistentBackend object.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface
+   *   The consistent cache backend.
+   * @param \Drupal\Core\Cache\CacheBackendInterface
+   *   The inconsistent cache backend.
+   * @param string $bin
+   *   The cache bin for which the object is created.
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state instance to get and set the last write timestamp.
+   */
+  public function __construct(CacheBackendInterface $consistent_backend, CacheBackendInterface $inconsistent_backend, $bin, StateInterface $state) {
+    $this->consistentBackend = $consistent_backend;
+    $this->inconsistentBackend = $inconsistent_backend;
+    $this->bin = 'cache_' . $bin;
+    $this->state = $state;
+    $this->lastWriteTimestamp = NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid, $allow_invalid = FALSE) {
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids, $allow_invalid);
+    return reset($cache);
+  }
+
+  /**
+   * Initialize the last write timestamp using the state instance.
+   */
+  public function lastWriteTimestamp() {
+    if ($this->lastWriteTimestamp === NULL) {
+      $this->lastWriteTimestamp = $this->state->get(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin);
+    }
+    return $this->lastWriteTimestamp;
+  }
+
+  protected function setLastWriteTimestamp($timestamp) {
+    $this->lastWriteTimestamp = $timestamp;
+  }
+
+  /**
+   * Mark the inconsistent cache bin as outdated because of a write.
+   */
+  protected function markAsOutdated() {
+    $now = microtime(TRUE);
+    if ($now > $this->lastWriteTimestamp()) {
+      $this->setLastWriteTimestamp($now);
+      $this->state->set(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin, $this->lastWriteTimestamp);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items) {
+    $this->markAsOutdated();
+    $this->consistentBackend->setMultiple($items);
+    $this->inconsistentBackend->setMultiple($items);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids, $allow_invalid = FALSE) {
+    // Retrieve as many cache entries as possible from the (faster) inconsistent
+    // backend. (Some cache entries may have been created before the last write
+    // to this cache bin and therefore be stale/wrong/inconsistent.)
+    $cache = array();
+    $last_write_timestamp = $this->lastWriteTimestamp();
+    if ($last_write_timestamp) {
+      foreach ($this->inconsistentBackend->getMultiple($cids, $allow_invalid) as $item) {
+        if ($item->created < $last_write_timestamp) {
+          $cids[] = $item->cid;
+        }
+        else {
+          $cache[$item->cid] = $item;
+        }
+      }
+    }
+
+    // If there were any cache entries that weren't available in the
+    // inconsistent backend, retrieve them from the consistent backend and store
+    // them in the inconsistent one.
+    if ($cids) {
+      foreach ($this->consistentBackend->getMultiple($cids, $allow_invalid) as $item) {
+        $cache[$item->cid] = $item;
+        $this->inconsistentBackend->set($item->cid, $item->data);
+      }
+    }
+
+    return $cache;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
+    $this->markAsOutdated();
+    $this->consistentBackend->set($cid, $data, $expire, $tags);
+    $this->inconsistentBackend->set($cid, $data, $expire, $tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    $this->markAsOutdated();
+    $this->consistentBackend->deleteMultiple(array($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    $this->markAsOutdated();
+    $this->consistentBackend->deleteMultiple($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteTags(array $tags) {
+    $this->markAsOutdated();
+    $this->consistentBackend->deleteTags($tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    $this->markAsOutdated();
+    $this->consistentBackend->deleteAll();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidate($cid) {
+    $this->invalidateMultiple(array($cid));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateMultiple(array $cids) {
+    $this->markAsOutdated();
+    $this->consistentBackend->invalidateMultiple($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateTags(array $tags) {
+    $this->markAsOutdated();
+    $this->consistentBackend->invalidateTags($tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateAll() {
+    $this->markAsOutdated();
+    $this->consistentBackend->invalidateAll();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    $this->consistentBackend->garbageCollection();
+    $this->inconsistentBackend->garbageCollection();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return $this->consistentBackend->isEmpty();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+    $this->consistentBackend->removeBin();
+    $this->inconsistentBackend->removeBin();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/InconsistentBackendFactory.php b/core/lib/Drupal/Core/Cache/InconsistentBackendFactory.php
new file mode 100644
index 0000000..2671166
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/InconsistentBackendFactory.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\InconsistentBackendFactory.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines the chained inconsistent cache backend factory.
+ */
+class InconsistentBackendFactory extends CacheFactory {
+
+  /**
+   * Instantiates an inconsistent cache backend class for a given cache bin.
+   *
+   * @param string $bin
+   *   The cache bin for which a cache backend object should be returned.
+   *
+   * @return \Drupal\Core\Cache\CacheBackendInterface
+   *   The cache backend object associated with the specified bin.
+   */
+  public function get($bin) {
+    $consistent_service = 'cache.backend.database';
+    $inconsistent_service = 'cache.backend.apc';
+
+    $cache_settings = $this->settings->get('cache');
+    if (isset($cache_settings['inconsistent_cache']) && is_array($cache_settings['inconsistent_cache'])) {
+      if (!empty($cache_settings['inconsistent_cache']['consistent'])) {
+        $consistent_service = $cache_settings['inconsistent_cache']['consistent'];
+      }
+      if (!empty($cache_settings['inconsistent_cache']['inconsistent'])) {
+        $inconsistent_service = $cache_settings['inconsistent_cache']['inconsistent'];
+      }
+    }
+
+    return new InconsistentBackend(
+      $this->container->get($consistent_service)->get($bin),
+      $this->container->get($inconsistent_service)->get($bin),
+      $bin,
+      $this->container->get('state')
+    );
+  }
+
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 8e4596f..a9cc776 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -57,34 +57,6 @@ public function onRespond(FilterResponseEvent $event) {
     // Set the Content-language header.
     $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->id);
 
-    // Because pages are highly dynamic, set the last-modified time to now
-    // since the page is in fact being regenerated right now.
-    // @todo Remove this and use a more intelligent default so that HTTP
-    // caching can function properly.
-    $response->setLastModified(new \DateTime(gmdate(DATE_RFC1123, REQUEST_TIME)));
-
-    // Also give each page a unique ETag. This will force clients to include
-    // both an If-Modified-Since header and an If-None-Match header when doing
-    // conditional requests for the page (required by RFC 2616, section 13.3.4),
-    // making the validation more robust. This is a workaround for a bug in
-    // Mozilla Firefox that is triggered when Drupal's caching is enabled and
-    // the user accesses Drupal via an HTTP proxy (see
-    // https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an
-    // authenticated user requests a page, and then logs out and requests the
-    // same page again, Firefox may send a conditional request based on the
-    // page that was cached locally when the user was logged in. If this page
-    // did not have an ETag header, the request only contains an
-    // If-Modified-Since header. The date will be recent, because with
-    // authenticated users the Last-Modified header always refers to the time
-    // of the request. If the user accesses Drupal via a proxy server, and the
-    // proxy already has a cached copy of the anonymous page with an older
-    // Last-Modified date, the proxy may respond with 304 Not Modified, making
-    // the client think that the anonymous and authenticated pageviews are
-    // identical.
-    // @todo Remove this line as no longer necessary per
-    //   http://drupal.org/node/1573064
-    $response->setEtag(REQUEST_TIME);
-
     // Authenticated users are always given a 'no-cache' header, and will fetch
     // a fresh page on every request. This prevents authenticated users from
     // seeing locally cached pages.
@@ -102,9 +74,18 @@ public function onRespond(FilterResponseEvent $event) {
 
     $max_age = \Drupal::config('system.performance')->get('cache.page.max_age');
     if ($max_age > 0 && ($cache = drupal_page_set_cache($response, $request))) {
+      // If we just created a cache item, use it's created time for last
+      // modified and etag headers.
+      $response->setEtag((int) $cache->created);
+      $response->setLastModified(new \DateTime(gmdate(DATE_RFC1123, (int) $cache->created)));
       drupal_serve_page_from_cache($cache, $response, $request);
     }
     else {
+      // Because pages are highly dynamic, set the last-modified time to now
+      // since the page is in fact being regenerated right now.
+      // @todo Remove this and use a more intelligent default so that HTTP
+      // caching can function properly.
+      $response->setLastModified(new \DateTime(gmdate(DATE_RFC1123, REQUEST_TIME)));
       $response->setExpires(\DateTime::createFromFormat('j-M-Y H:i:s T', '19-Nov-1978 05:00:00 GMT'));
       $response->headers->set('Cache-Control', 'no-cache, must-revalidate, post-check=0, pre-check=0');
     }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
index 9002314..63d9648 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php
@@ -141,7 +141,7 @@ public function testSetGet() {
     $this->assert(is_object($cached), "Backend returned an object for cache id test1.");
     $this->assertIdentical(7, $cached->data);
     $this->assertTrue($cached->valid, 'Item is marked as valid.');
-    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertTrue($cached->created >= REQUEST_TIME && $cached->created < microtime(TRUE), 'Created time is correct.');
     $this->assertEqual($cached->expire, Cache::PERMANENT, 'Expire time is correct.');
 
     $this->assertIdentical(FALSE, $backend->get('test2'), "Backend does not contain data for cache id test2.");
@@ -150,7 +150,7 @@ public function testSetGet() {
     $this->assert(is_object($cached), "Backend returned an object for cache id test2.");
     $this->assertIdentical(array('value' => 3), $cached->data);
     $this->assertTrue($cached->valid, 'Item is marked as valid.');
-    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertTrue($cached->created >= REQUEST_TIME && $cached->created < microtime(TRUE), 'Created time is correct.');
     $this->assertEqual($cached->expire, REQUEST_TIME + 3, 'Expire time is correct.');
 
     $backend->set('test3', 'foobar', REQUEST_TIME - 3);
@@ -158,7 +158,7 @@ public function testSetGet() {
     $cached = $backend->get('test3', TRUE);
     $this->assert(is_object($cached), 'Backend returned an object for cache id test3.');
     $this->assertFalse($cached->valid, 'Item is marked as valid.');
-    $this->assertEqual($cached->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertTrue($cached->created >= REQUEST_TIME && $cached->created < microtime(TRUE), 'Created time is correct.');
     $this->assertEqual($cached->expire, REQUEST_TIME - 3, 'Expire time is correct.');
   }
 
@@ -247,7 +247,7 @@ public function testGetMultiple() {
     $this->assert(isset($ret['test7']), "Existing cache id test7 is set.");
     // Test return - ensure that objects has expected properties.
     $this->assertTrue($ret['test2']->valid, 'Item is marked as valid.');
-    $this->assertEqual($ret['test2']->created, REQUEST_TIME, 'Created time is correct.');
+    $this->assertTrue($ret['test2']->created >= REQUEST_TIME && $ret['test2']->created < microtime(TRUE), 'Created time is correct.');
     $this->assertEqual($ret['test2']->expire, Cache::PERMANENT, 'Expire time is correct.');
     // Test return - ensure it does not contain nonexistent cache ids.
     $this->assertFalse(isset($ret['test19']), "Nonexistent cache id test19 is not set.");
diff --git a/core/tests/Drupal/Tests/Core/Cache/InconsistentBackendTest.php b/core/tests/Drupal/Tests/Core/Cache/InconsistentBackendTest.php
new file mode 100644
index 0000000..feb34d4
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Cache/InconsistentBackendTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests\Core\Cache;
+
+use Drupal\Core\Cache\MemoryBackend;
+use Drupal\Core\Cache\InconsistentBackend;
+use Drupal\Core\State\StateInterface;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @group Cache
+ */
+class InconsistentBackendTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => '',
+      'description' => '',
+      'group' => 'Cache'
+    );
+  }
+
+  public function setUp() {
+    $this->consistent_cache = new MemoryBackend("foo");
+    $this->inconsistent_cache = new MemoryBackend("foo");
+    $this->bin = "somebin";
+  }
+
+  public function testGetFromInconsistentCache() {
+    throw new \Exception('lulz');
+    $state = $this->getMock("Drupal\Core\State\StateInterface");
+    $state->expects($this->once())
+      ->method("get")
+      ->will($this->returnValue(1234));
+
+    $inconsistent_backend = new InconsistentBackend(
+      $this->consistent_cache,
+      $this->inconsistent_cache,
+      $this->bin,
+      $state
+    );
+
+    $this->consistent_cache->set("foo", "baz");
+    $inconsistent_backend->set("foo", "bar");
+    $this->assertEquals("bar", $inconsistent_backend->get("foo")->data);
+  }
+
+  public function testFallThroughToConsistentCache() {
+    $state = $this->getMock("Drupal\Core\State\StateInterface");
+    $state->expects($this->once())
+      ->method("get")
+      ->will($this->returnValue(time() + 99999));
+
+    $inconsistent_cache = $this->getMock("Drupal\Core\Cache\MemoryBackend", array("set"), array("foo"));
+    $inconsistent_cache->expects($this->exactly(2))
+      ->method("set");
+
+    $inconsistent_backend = new InconsistentBackend(
+      $this->consistent_cache,
+      $inconsistent_cache,
+      $this->bin,
+      $state
+    );
+
+    $inconsistent_cache->set("foo", "bar");
+    $this->consistent_cache->set("foo", "baz");
+    $this->assertEquals("baz", $inconsistent_backend->get("foo")->data);
+  }
+
+}
