Практика кеша Nuxt

Vue.js PM2 Nuxt.js

nuxtосновывается наvueизssrРешением может быть использование синтаксиса vue для завершения изоморфизма передней и задней частей.

Однако при объединении с традиционными простыми строкамиssrПо сравнению со схемой производительность не так хороша.nuxtНеобходимо создать виртуалку на стороне сервераdomА затем сериализовать HTML-строку, мы часто говоримnodejsВ конце концов, высокая производительность относится к сценариям с частыми асинхронными операциями ввода-вывода, а не к сценариям с интенсивным использованием ЦП.nodejsОн работает в одном потоке. В сценариях с высокой степенью параллелизма производительность будет снижаться. Вы можете рассмотреть возможность принятия разумной стратегии кэширования.

nuxtКэш можно разделить наКэш уровня компонентов, Кэширование на уровне APIтак же каккеш уровня страницы

Кэш уровня компонентов

элемент конфигурацииnuxt.config.jsКонфигурация выглядит следующим образом:

const LRU = require('lru-cache')
module.exports = {
  render: {
    bundleRenderer: {
      cache: LRU({
        max: 1000,                     // 最大的缓存个数
        maxAge: 1000 * 60 * 15        // 缓存15分钟
      })
    }
  }
}

Это не означает, что кеширование на уровне компонентов реализовано при настройке этого пункта, а также необходимо делать кеширование вvueдобавлены компонентыnameтак же какserverCacheKeyполе для определения уникального значения ключа кэша, например:

export default {
  name: 'AppHeader',
  props: ['type'],
  serverCacheKey: props => props.type
}

Вышеупомянутые компоненты будут переданы в соответствии с родительским компонентом.typeЧтобы кэшировать значение, значение ключа:AppHeader::${props.type}, таким образом, когда приходит новый запрос, до тех пор, пока родительский компонентtypeСвойство было обработано ранее, и предыдущий результат кэша рендеринга можно повторно использовать для повышения производительности.

Как видно из этого примера, если компонент зависит от родительского компонента в дополнение кtypeсвойств, но и зависит от других свойств,serverCacheKeyСоответствующие изменения также должны быть сделаны здесь. Следовательно, если компонент зависит от большого глобального состояния, или, если зависимое состояние имеет много значений, это означает, что кэш должен быть установлен часто и переполнен, что не имеет смысла.lru-cacheВ конфигурации установлено максимальное количество кешей 1000, и оно будет очищено.

Во-вторых, субкомпоненты, которые могут иметь побочные эффекты в контексте рендеринга, не должны кэшироваться, например, компонентcreatedа такжеbeforeCreatedХук также будет проходить на стороне сервера. После кэширования компонента он не будет выполняться. Будьте осторожны, когда это может повлиять на контекст рендеринга. Для получения дополнительной информации см.:Кэш уровня компонентов

Вообще говоря, более подходящий сценарийv-forРендеринг большого количества данных, потому что операция петли потребляет больше процессора

Кэширование на уровне API

В сценариях рендеринга на стороне сервера запросы часто выполняются на стороне сервера, а страница визуализируется, а затем возвращается в браузер. Например, некоторые интерфейсы можно кэшировать, не полагаясь на состояние входа в систему и не полагаясь на слишком много параметров. , Также требуется время для обработки интерфейса, а кеш интерфейса может ускорить скорость обработки каждого запроса, быстрее выпустить запрос и повысить производительность.

использование API-запросаaxios,axiosЕго можно использовать на сервере или в браузере, код выглядит так

import axios from 'axios'
import md5 from 'md5'
import LRU from 'lru-cache'

// 给api加3秒缓存
const CACHED = LRU({
  max: 1000,
  maxAge: 1000 * 3
})

function request (config) {
  let key
  // 服务端才加缓存,浏览器端就不管了
  if (config.cache && !process.browser) {
    const { params = {}, data = {} } = config
    key = md5(config.url + JSON.stringify(params) + JSON.stringify(data))
    if (CACHED.has(key)) {
      // 缓存命中
      return Promise.resolve(CACHED.get(key))
    }
  }
  return axios(config)
    .then(rsp => {
      if (config.cache && !process.browser) {
        // 返回结果前先设置缓存
        CACHED.set(key, rsp.data)
      }
      return rsp.data
    })
}

Используйте как обычноaxiosВсе то же самое, просто добавьте большеcacheАтрибут определяет, нужно ли кешировать на стороне сервера.

const api = {
  getGames: params => request({
    url: '/gameInfo/gatGames',
    params,
    cache: true
  })
}

кэширование на уровне страницы

Не полагаясь на состояние входа и слишком много параметров, если объем параллелизма велик, вы можете рассмотреть возможность использования кэширования на уровне страницы. существуетnuxt.config.jsУвеличиватьserverMiddlewareАтрибуты

const nuxtPageCache = require('nuxt-page-cache')

module.exports = {
  serverMiddleware: [
    nuxtPageCache.cacheSeconds(1, req => {
      if (req.query && req.query.pageType) {
        return req.query.pageType
      }
      return false
    })
  ]
}

Приведенный выше пример основан на параметрах, следующих по ссылкеpageTypeсделай кеш, если есть ссылка послеpageTypeПараметр кэшируется, и время кэширования составляет 1 секунду, то есть одно и то же значение в течение 1 секунды.pageTypeзапрос, сервер выполнит только полный рендеринг

nuxt-page-cacheСсылкаroute-cache, написание относительно простое, вы также можете переупаковать его, и окончательные возвращаемые данные nuxt должны использоватьres.end(html, 'utf-8'), общая идея кэширования на уровне страницы выглядит следующим образом:

const LRU = require('lru-cache')

let cacheStore = new LRU({
  max: 100,         // 设置最大的缓存个数
  maxAge: 200
})

module.exports.cacheSeconds = function (secondsTTL, cacheKey) {
  // 设置缓存的时间
  const ttl = secondsTTL * 1000
  return function (req, res, next) {
    // 获取缓存的key值
    let key = req.originalUrl
    if (typeof cacheKey === 'function') {
      key = cacheKey(req, res)
      if (!key) { return next() }
    } else if (typeof cacheKey === 'string') {
      key = cacheKey
    }

    // 如果缓存命中,直接返回
    const value = cacheStore.get(key)
    if (value) {
      return res.end(value, 'utf-8')
    }

    // 缓存原先的end方案
    res.original_end = res.end

    // 重写res.end方案,由此nuxt调用res.end实际上是调用该方法,
    res.end = function () {
      if (res.statusCode === 200) {
        // 设置缓存
        cacheStore.set(key, data, ttl)
      }
      // 最终返回结果
      res.original_end(data, 'utf-8')
    }
  }
}

При попадании в кеш исходный результат расчета возвращается напрямую, что значительно повышает производительность.

Суммировать

В случае высокого параллелизма вы можете рассмотреть возможность использования кеша, а использование стратегии кеша зависит от сцены.Я не буду здесь вдаваться в подробности.Вы также можете рассмотреть возможность использования pm2, чтобы открыть режим кластера для управления нашими процессами , чтобы обеспечить более высокий параллелизм.