课程引导
- 🚀【eggjs实战10天入门-第1天】🚀—— 搭建项目
- 🚀【eggjs实战10天入门-第2天】🚀—— controller、service和config
- 🚀【eggjs实战10天入门-第3天】🚀—— 操作mysql
- 🚀【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安装好了,还没有开启
启动redis
启动redis
brew services start redis经过查看redis服务已经启动
这时我们用桌面工具rdm链接测试下连接(点击蓝框的test connection),已经提示成功链接了,但是大家注意下红框,在密码这一栏我们什么也没有写。这是比较危险的,想想开头的小故事,CPU 被挖矿,Redis 竟是内鬼!。这就是高危操作。那么如何设置密码呢,我们继续往下
修改redis启动参数
我们打开文件
~/Library/LaunchAgents/homebrew.mxcl.redis.plist, 在下图中可以看到brew的启动参数,
- 启动命令redis-server
- 配置文件redis.conf /usr/local/etc/redis.conf
我们打开配置文件code /usr/local/etc/redis.conf,密码开启(去掉#号,#代表注释)设置为123456789(这个自己随意设置)
requirepass 123456789
然后重启redis, brew services restart redis
这个文件/usr/local/etc/redis.conf里面有很多的配置项,大家可以抽空自己看一下文档
重启后,我们发现不填写密码已经无法连接了,说明我们的配置成功了。
我们把密码改成123456789,然后正式连接上
连接后会看到如下所示
3、redis在eggjs项目中的操作
3.1、redis的简要的使用场景
我们接下来就以传统的token模式,演示前后端在用户方面的cookie和session进行说明redis的缓存功能
在开始之前我们先粗略的了解下传统token的鉴权方式
1、单机器单进程的服务
2、集群下的问题
造成问题的原因是
- 用户登陆的时候可能是在服务器1,那么token数据就存在了服务器1上面
- 然后登陆后,某次业务接口被分发到了服务器3上面,这时候服务器3上面并没有token数据,就导致了当前服务认为这个用户没有登陆,进而产生bug
解决的方案有很多
- 协调这些服务器,在服务器之间同步session(这事一听就头大)。
- 分发请求时绑定ip和服务器,就是小明这个用户只能访问服务器1,二者绑定好
- 采用Redis这样的高性能缓存服务器(我们就采用这一周了)
3、那么我们把上图改造一下,这样负载均衡下就可以满足session的共享了
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实例的。
我们接下来根据文档进行操作redis,https://www.npmjs.com/package/egg-redis。
我们先小试牛刀一下
async login({ phone, password }) {
const { app } = this;
app.redis.get('base1').set(phone, password)
return { result: "设置redis成功" }
}
然后我们打开rdm工具,去redis里面看一下
这时我们欣喜的发现,在db8里面出现了一条数据。 因为我们操作的是base1, 接下来我们换成base2试一下
async login({ phone, password }) {
const { app } = this;
app.redis.get('base2').set(phone, password)
return { result: "设置redis成功" }
}
可以看到,db9里面也出现了一条数据。
我们就可以根据这些原理,就可以做登陆校验
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的可维护性
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
这样我们可以很随意的去更新这个hash,不管是增减商品,还是增减某个商品的购买数量。这是hash的好处,可以比较灵活的操作对象。如果使用string实现上面的操作,也可以做到,但是想想需要经常的sting和object的转换就让人头疼不已。
| string + json | hash |
|---|---|
| 适合操作不大不常变化的属性 | 可以很灵活的操作某个属性,获取所有的属性 |
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/事务等,但是这些不在入门教程里面,单个一个系列都可以了。这里就不再细说了