🚀【eggjs实战入门】🚀—— 4、看完就会操作redis

1,168 阅读9分钟

课程引导

  1. 🚀【eggjs实战10天入门-第1天】🚀—— 搭建项目
  2. 🚀【eggjs实战10天入门-第2天】🚀—— controller、service和config
  3. 🚀【eggjs实战10天入门-第3天】🚀—— 操作mysql
  4. 🚀【eggjs实战10天入门-第4天】🚀—— 看完就会操作redis(本节)

本节目标

了解redis的功能和作用

安装redis和redis可视化工具

了解redis的各种类型的读写操作

1、redis是什么?

本节只是演示redis的部分常用功能,看完本节只能是浅浅的了解redis

1.1、Redis 简介

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

1.2、Redis 优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

以上术语摘抄于菜鸟教程

在说具体的redis操作前,我们先要打起十二分的精神

因为我们操作服务端的内容,和玩前端静态项目有比较大的区别。前端静态项目是在浏览器里面操作,安全性很高,可以可劲的随便折腾,不会出什么大问题,最多把浏览器整挂了。那也只是一个用户受影响。

但是类型类似redis这种操作就会有风险,服务器出了问题,那就会影响到所有的用户 所以在我们学习redis之前,极力推荐先看一篇有意思的文章CPU 被挖矿,Redis 竟是内鬼!

2、安装redis和redis可视化工具

2.1、安装redis可视化工具

先安装简单的,我这里使用的是Redis Desktop Manager。

一款基于Qt5的跨平台Redis桌面管理软件
支持: Windows 7+, Mac OS X 10.10+, Ubuntu 14+
特点: C++ 编写,响应迅速,性能好。但不支持数据库备份与恢复。

官方下载地址:github.com/RedisInsigh…

如果此路不通那就换条路,解决这种小问题相信大家还是手到擒来的

2.2、安装redis可视化工具

官方安装文档,redis.io/docs/gettin…

我这里我还是以mac为例

安装redis

安装redis brew install redis 我们先查看下brew的服务,发现redis安装好了,还没有开启 image.png

启动redis

启动redis brew services start redis 经过查看redis服务已经启动 image.png

这时我们用桌面工具rdm链接测试下连接(点击蓝框的test connection),已经提示成功链接了,但是大家注意下红框,在密码这一栏我们什么也没有写。这是比较危险的,想想开头的小故事,CPU 被挖矿,Redis 竟是内鬼!。这就是高危操作。那么如何设置密码呢,我们继续往下 image.png

修改redis启动参数

我们打开文件~/Library/LaunchAgents/homebrew.mxcl.redis.plist, 在下图中可以看到brew的启动参数,

  • 启动命令redis-server
  • 配置文件redis.conf /usr/local/etc/redis.conf image.png

我们打开配置文件code /usr/local/etc/redis.conf,密码开启(去掉#号,#代表注释)设置为123456789(这个自己随意设置)

requirepass 123456789

然后重启redis, brew services restart redis

这个文件/usr/local/etc/redis.conf里面有很多的配置项,大家可以抽空自己看一下文档 image.png

重启后,我们发现不填写密码已经无法连接了,说明我们的配置成功了。 我们把密码改成123456789,然后正式连接上 image.png

连接后会看到如下所示 image.png

3、redis在eggjs项目中的操作

3.1、redis的简要的使用场景

我们接下来就以传统的token模式,演示前后端在用户方面的cookie和session进行说明redis的缓存功能

在开始之前我们先粗略的了解下传统token的鉴权方式

1、单机器单进程的服务 image.png

2、集群下的问题 image.png

造成问题的原因是

  • 用户登陆的时候可能是在服务器1,那么token数据就存在了服务器1上面
  • 然后登陆后,某次业务接口被分发到了服务器3上面,这时候服务器3上面并没有token数据,就导致了当前服务认为这个用户没有登陆,进而产生bug

解决的方案有很多

  • 协调这些服务器,在服务器之间同步session(这事一听就头大)。
  • 分发请求时绑定ip和服务器,就是小明这个用户只能访问服务器1,二者绑定好
  • 采用Redis这样的高性能缓存服务器(我们就采用这一周了)

3、那么我们把上图改造一下,这样负载均衡下就可以满足session的共享了 image.png

3.2、安装redis依赖和如何配置

安装eggjs插件egg-redis, yarn add egg-redis -S

插件中开启egg-reids

// config/plugin.js
exports.redis = {
  enable: true,
  package: 'egg-redis',
};

配置文件中添加redis配置,我们按照多redis进行配置 就是一个项目连接多个redis服务的情况, 在项目中我们尝试连接同一个库的不同db(当然这种写法是支持1-n个redis库,也就是说你配置一个redis也是可以的)

// config/config.default.js
config.redis = {
  clients: {
    base1: {
      port: 6379,               // Redis 端口
      host: '127.0.0.1',        // Redis 地址 因为我们是在本地启动的redis 所以地址为127.0.0.1
      password: '123456789',    // Redis 密码
      db: 8,                    // 0-15, 共16个
    },
    base2: {
      port: 6379,               // Redis 端口
      host: '127.0.0.1',        // Redis 地址 因为我们是在本地启动的redis 所以地址为127.0.0.1
      password: '123456789',    // Redis 密码
      db: 9,                    // 0-15, 共16个
    },
  }
}

3.3、redis的增删改查操作

经过我上面啰哩啰嗦的得得,我们终于到了写代码的环节了。开始整活 上面我们开启了插件,插件一般都是挂载到app这个全局应用对象上面的,所以我们大概能知道通过app.redis就可以拿到redis实例了。我们先写个登陆接口试一下。

我们应该还记得在config文件中写的是多redis配置,通过断点我们也可以看到redis下确实是存在两个redis实例的。 image.png

我们接下来根据文档进行操作redis,https://www.npmjs.com/package/egg-redisimage.png

我们先小试牛刀一下

async login({ phone, password }) {
    const { app } = this;
    app.redis.get('base1').set(phone, password)
    return { result: "设置redis成功" }
}

image.png

然后我们打开rdm工具,去redis里面看一下

image.png

这时我们欣喜的发现,在db8里面出现了一条数据。 因为我们操作的是base1, 接下来我们换成base2试一下

async login({ phone, password }) {
    const { app } = this;
    app.redis.get('base2').set(phone, password)
    return { result: "设置redis成功" }
}

可以看到,db9里面也出现了一条数据。 image.png 我们就可以根据这些原理,就可以做登陆校验

3.4、redis常用数据类型

3.4.1、Redis字符串(String)
普通的key-value形式, 但是这里的key一般是遵循业务:场景:变量等等,这种冒号相连的规则。如`app.redis.get('base2').hset(`auth:phone:phone`, password)`
优点
1. 能够根据某类 key 进行数据更新/清理, 可以批量操作
2. 语义化高,能够了解到这个key 的归属方和应用场景
4. 为统一化、平台化做准备,减少技术变更

我们随机操作了6次,可以看到6条数据,同时rdm也已经分好层次了。当然主要还是我们使用这种规范,可以规范我们项目redis的可维护性 image.png

3.4.2、Redis 哈希(Hash)

Redis hash 是一个string类型的 field(字段) 和 value(值) 的映射表,适合用于存储对象。

Redis中每个hash可以存储40多亿。

应用场景:购物车

我们可以做成 cart:userId:${userId}为key 商品id作为field, 购买数量作为value

当我们向购物车新增商品时,就新增一条filed和value就可以了。 我们操作演示下app.redis.get('base2').hset(cart:userId:${userId}, goodsId, 1), 默认加到购物车的数量为1

image.png

这样我们可以很随意的去更新这个hash,不管是增减商品,还是增减某个商品的购买数量。这是hash的好处,可以比较灵活的操作对象。如果使用string实现上面的操作,也可以做到,但是想想需要经常的sting和object的转换就让人头疼不已。

string + jsonhash
适合操作不大不常变化的属性可以很灵活的操作某个属性,获取所有的属性
3.4.3、Redis 列表(List)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边) 一个列表最多可以包含40多亿个元素。

应用场景:排行榜或者消息队列

对于排行榜或者消息队列这种随时都可能发生变化的场景,一般可以使用list类型去处理。 当然简单的队列redis确实可以做,不过在现在这个时代,Kafka、NSQ、RabbitMQ等大佬级的消息队列服务,我们可以直接使用这种成熟的产品,避免出现生产问题

注意,这里只是提供一种可能性的建议,还是要看具体业务和数据量,不能硬上。

3.4.4、Redis 集合(Set)

Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

集合对象的编码可以是 intset 或者 hashtable。

Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

集合中最大的成员数也是40多亿。

这个set和上面的list很像,他俩最大的区别就是List是可以重复的。而Set是不重复的,添加的成员如果已经在集合中,那么会被直接忽略。

应用场景:聚合统计

  • 比如A的好友和B的好友都使用Set存储,那么就可以很方便的计算A和B的共同好友
  • 或者查询某个IP是否位于黑名单集合中

当然还有sorted set/事务等,但是这些不在入门教程里面,单个一个系列都可以了。这里就不再细说了