Redis 学习 - 06 漂流瓶案例

案例介绍

微信有几亿的用户群,某一时刻可能有几千上万人同时在玩漂流瓶,对于这种高并发数据量小的服务,使用 Node.js 和 Redis 绝对是一个推荐的选择。

接口设计

扔一个漂流瓶

  • 请求方法:POST
  • 请求路径:/
  • 请求体参数:
    • time:漂流瓶扔出的时间戳,默认设置为 Date.now()
    • owner:漂流瓶主人(用户 id)
    • type:漂流瓶类型
      • male:男性
      • female:女性
    • content:漂流瓶内容
  • 返回:完整数据内容

捡一个漂流瓶

  • 请求方法:GET
  • 请求路径:/
  • 查询参数:
    • user:捡漂流瓶的人(用户 id)
    • type:漂流瓶类型
      • all:全部
      • male:男性
      • female:女性
  • 返回数据:
{
  "time": 1641883884765, // 漂流瓶扔出的时间戳
  "owner": 1, // 漂流瓶主人
  "type": "male", // 漂流瓶类型
  "content": "hello world" // 漂流瓶内容
}

设计思路

可以将 Redis 想象成一片大海,Redis 中的每一条 Hash 类型的数据就是一个漂流瓶,每个漂流瓶都有独一无二的 id(即 Redis 中的键),里面包含了漂流瓶的一些信息(即 Redis 中键的值)。

使用两个数据库,分别存储两种 type 的漂流瓶,目的是为了方便使用 Redis 中的 RANDOMKEY 命令,该命令返回当前数据库中的一个随机键,不能加任何条件。

扔漂流瓶时,为其创建一个唯一 id(使用 uuidv4),以这个 id 为 key,漂流瓶的数据为值,添加一条 Hash 类型的数据,并设置 1 天有效期。

捡漂流瓶时,根据 type 决定从哪个数据库中随机读取数据,漂流瓶一经捡起,就从数据库中删除。

开始开发

初始化项目

mkdir drift-bottle
cd drift-bottle
npm init -y
npm i express ioredis uuidv4

app.js:

const { uuid } = require('uuidv4')
const Redis = require('ioredis')
const express = require('express')

const app = express()
app.use(express.json())

// 创建 Redis 实例
const connectRedis = () => {
  return new Redis()
}

// 扔一个漂流瓶
app.post('/', (req, res, next) => {
  try {
  	res.send('post /')
  } catch (error) {
    next(error)
  }
})

// 捡一个漂流瓶
app.get('/', (req, res, next) => {
  try {
  	res.send('get /')
  } catch (error) {
    next(error)
  }
})

// 统一处理异常
app.use((err, req, res, next) => {
  res.status(500).json({
    error: err.message
  })
})

app.listen(3000, () => {
  console.log('runnning')
})

扔一个漂流瓶

// 扔一个漂流瓶
app.post('/', async (req, res, next) => {
  try {
    const bottle = req.body

    // 设置时间戳
    bottle.time = bottle.time || Date.now()

    // 为每个漂流瓶随机生成一个不重复的id
    const bottleId = uuid()

    const type = {
      male: 0,
      female: 1
    }

    await redis
      .pipeline()
      // 根据类型切换数据库
      .select(type[bottle.type])
      // 将数据存为 Hash
      .hmset(bottleId, bottle)
      // 设置 1 天有效期
      .expire(bottleId, 24 * 60 * 60)
      .exec()

    res.status(201).json({
      bottle: {
        id: bottleId,
        ...bottle
      }
    })
  } catch (error) {
    next(error)
  }
})

捡一个漂流瓶

// 捡一个漂流瓶
app.get('/', async (req, res, next) => {
  try {
    const query = req.query

    const type = {
      all: Math.round(Math.random()),
      male: 0,
      female: 1
    }

    query.type = query.type || 'all'

    // 根据类型切换数据库
    await redis.select(type[query.type])

    // 随机获取一个 key
    const bottleId = await redis.randomkey()

    if (!bottleId) {
      res.status(200).json({
        message: '大海很干净...'
      })
    }

    // 根据漂流瓶 id 获取完整的漂流瓶信息
    const bottle = await redis.hgetall(bottleId)

    res.status(201).json({
      bottle
    })

    // 从 Redis 中删除捡到的漂流瓶
    redis.del(bottleId)
  } catch (error) {
    next(error)
  }
})
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值