在 Egg.js 中使用 redis 緩存提高性能

前言

Redis 是一款開源的,基於 BSD 許可的,高級鍵值緩存和存儲系統。Redis 的鍵包括 string,hash,list,set,sorted set,bitmap 和 hyperloglog。你能夠在這些類型上面運行原子操做,例如,追加字符串,增長哈希中的值,加入一個元素到列表,計算集合的交集、並集和差集,或者是從有序集合中獲取最高排名的元素。node

要在 Egg.js 中使用 redis,只須要安裝 npm i redis 便可git

經過一個例子來驗證一下,建立一個能夠返回開源倉庫在 Github 上的 star 數量的數據接口,來測試使用 Redis 後帶來的提高github

代碼地址: github.com/xrr2016/egg…redis

原文連接: coldstone.fun/post/2019/0…npm

開發

首先使用 Egg.js 建立一個項目json

mkdir egg-redis-test && cd egg-redis-test

npm init egg --type=simple

npm i
複製代碼

安裝 redisapi

npm i redis
複製代碼

啓動項目緩存

npm run dev

open http://localhost:7001
複製代碼

先建立 controller 和 service 目錄,用來放處理請求和返回數據的方法,完成後的項目目錄爲bash

folder

修改 router.js 文件,添加路由,而後在 controller/home.js 文件實現 stars 方法app

'use strict'

module.exports = app => {
  const { router, controller } = app

  router.get('/', controller.home.index)
  router.get('/stars', controller.home.stars)
}
複製代碼

修改 controller/home.js 文件,接收請求傳過來的 query 參數向下傳給 stars service 返回結果

'use strict'

const Controller = require('egg').Controller

class HomeController extends Controller {
  async stars() {
    const { ctx, service } = this
    const { owner, name } = ctx.query

    ctx.body = await service.home.stars(owner, name)
  }
}

module.exports = HomeController
複製代碼

在 service/home.js 裏實現 stars 方法,須要作的就是經過 controller 傳過來的 owner, name 參數,請求 Github 的接口,返回數據。

須要注意的是,這裏請求的是 Github 的 graphql 接口,因此首先須要在 Github 上新建一個 token,token 不能直接寫在代碼裏面,須要將 token 放在環境變量裏,不然代碼提交到 Github 後會失效。

token

建立 token 後使用 dotenv 保存環境變量,先安裝而後在項目目錄建立一個 .env 文件

npm i dotenv
複製代碼

token

而後就可使用 egg.js 自帶的 crul 方法向 Github 接口發送 post 請求,代碼以下

'use strict'

require('dotenv').config()
const Service = require('egg').Service

class HomeService extends Service {
  async stars(owner, name) {
    function setResponse(name, stars) {
      return { msg: `${name} has ${stars} stars.` }
    }

    const query = ` query { repository(owner: ${owner}, name: ${name}) { stargazers { totalCount } } } `

    const result = await this.ctx.curl('https://api.github.com/graphql', {
      method: 'POST',
      dataType: 'json',
      headers: {
        Authorization: `token ${process.env.TOKEN}`
      },
      data: JSON.stringify({ query }),
      timeout: 10000
    })

    const data = result.data.data

    return setResponse(name, data.repository.stargazers.totalCount)
  }
}

module.exports = HomeService
複製代碼

使用 postman 測試一下接口

folder

耗時平均 1 秒左右,接下來就是使用 Redis 添加緩存,首先須要在本地安裝 Redis,參考 Redis download,Mac 能夠直接使用 homebrew 安裝

安裝

brew install redis
複製代碼

啓動

redis-server /usr/local/etc/redis.conf
複製代碼

進入 redis 命令行

redis-cli
複製代碼

緩存的主要邏輯就是,第一次請求完獲得 Github 的數據將數據放到緩存中,再次請求的時候直接使用緩存中的數據,也須要給緩存設置一個過時時間。 請求時須要從環境變量中拿到 token,請求的數據要用 JSON.stringify 方法傳給 Github 接口,不然會出現解析錯誤

代碼以下

'use strict'

require('dotenv').config()
const redis = require('redis')
const { promisify } = require('util')
const Service = require('egg').Service

const REDIS_PORT = process.env.PORT || 6379
const client = redis.createClient(REDIS_PORT)
const getAsync = promisify(client.get).bind(client)
const setexAsync = promisify(client.setex).bind(client)

class HomeService extends Service {
  async stars(owner, name) {
    const key = `${owner}/${name}`
    const stars = await getAsync(key)

    function setResponse(name, stars) {
      return { msg: `${name} has ${stars} stars.` }
    }

    if (stars !== null) {
      return setResponse(name, stars)
    }

    const query = ` query { repository(owner: ${owner}, name: ${name}) { stargazers { totalCount } } } `

    const result = await this.ctx.curl('https://api.github.com/graphql', {
      method: 'POST',
      dataType: 'json',
      headers: {
        Authorization: `token ${process.env.TOKEN}`
      },
      data: JSON.stringify({ query }),
      timeout: 10000
    })

    const data = result.data.data

    await setexAsync(key, 10, data.repository.stargazers.totalCount)
    return setResponse(name, data.repository.stargazers.totalCount)
  }
}

module.exports = HomeService
複製代碼

再次測試,首先把 Redis 裏面的緩存清空,使用 Redis 的命令行運行

FLUSHALL
複製代碼

發送請求,第一次的耗時仍是一秒多,而後在失效時間內請求,能夠看到使用緩存的數據後,請求耗時大大減小了,性能提高效果顯著,實際項目能夠設置一個較長的緩存失效時間

folder

固然緩存過時後又要從新向 Github 發送請求了,由於 Redis 已經把數據刪除了

folder

參考

Redis documentation

Node Redis

相關文章
相關標籤/搜索