redis实战 appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证了数据的完整持久化 appendfsync no //完全依赖os,性能最好,持久化没有保证

Redis实战回顾
Redis实战回顾
memcached mysql redis 缓存 php
5
前言
Remote Dictionary Server(远程数据的服务),是一种NoSQL技术,是一个基于key-value的高速缓存系统,是目前应用面最广的缓存系统之一。

Redis实战
第一部分 基本概念和注意事项
1.1 Redis是什么?
Redis:Remote Dictionary Server(远程数据的服务),是一种NoSQL技术,是一个基于key-value的高速缓存系统,Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。类似于Memcache,但是支持更复杂的数据结构List,Set,SortedSet等,并且有持久化[1]的功能。

Redis有以下特点:

Redis支持数据的持久化,可以讲内存中数据曹村在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅是支持简单的key-value类型的数据,同事还提供List,Set,Hash等数据结构的存储。
Redis支持数据的备份,即master-salve模式的数据备份。
1.2 Redis缓存的原理
一般场景就是数据缓存服务器,与Memcache的角色保持一致;实质上Redis缓存数据库服务器在提供的缓存的基础上,同时提供数据持久化(复制),也就是提供数据库层面的功能。

实现机制:操作时,操作的内存允许设置同步到磁盘上。

1.3 Redis和Memcache的区别?
1.存储方式:

Memcache吧数据全部存在内存中,断电或者重启服务器会挂掉,不可以恢复数据,数据大小不能草果内存大小。
Redis有部分数据在磁盘上,这样能保证数据的持久化。可以定期保存到磁盘(持久化),内存上的数据丢失后可以通过aof恢复。
2.数据支持类型:

Redis在数据支持上要比Memcache多的多。Redis不仅仅支持简单的key-value类型的数据,同时还支持List,Set,Hash等数据结构的存储。
Redis的value最大支持512M,Memcache的value最大支持1M。
3.使用底层模型不同

新版本的Redis直接构建了自己的VM机制,因为一般的系统调用系统函数需要耗费一定的时间去移动和请求,有了自己的VM机制就节省了时间。
Redis是单核运行的,Memcache是多喝运行的。
读写速度:Redis的写速度与Memcache差不多,读速度Memcache比Redis快。
4.运行的环境不同

RedisRedis只支持Linux上执行,这样省去了对其他操作系统的支持,可以更好的用于本系统环境的优化。
5.对于两者的选择具体看应用场景

如果需要缓存的数据只是key-value这样简单的结构时首先考虑Memcache,它是足够稳定可靠。
如果涉及到存储,排序等一系列复杂操作时,毫无疑问选择Redis。
1.4 Redis.conf配置文件说明
1.Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程:daemonize no。

2.当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile制定存储位置:pidfile /var/run/redis.pid。

3.指定Redis监听端口,默认端口为6379.

4.绑定的主机地址:bind 127.0.0.1

5.当客户端闲置多长时间后关闭连接,如果制定为0,表示关闭该功能。timeout 300。

6.指定日志记录级别,Redis总共支持你四个级别debug、verbose、notice、warning、默认是verbose:loglevel verbose。

7.设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id:databases 16。

8.指定在多长时间内,有多少次更新数据,就将数据同步到数据文件,可以多个条件配合:

save
//Redis 默认配置文件提供了三个条件
save 900 1
save 300 10
save 60 10000
分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更高,60秒内有10000个更改。

9.指定本地数据文件名,默认值为dump.rdb:dbfilename dump.rdb

10.指定本地数据库存放目录:dir ./

11.设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH 命令提供密码,默认关闭:requirepass 输入密码

12.登录服务器的状态:info

1.5 Redis数据备份与恢复
备份原理和过程:缓存数据库服务器 =>缓存数据存储在内存 =>数据库存储在磁盘上 =>执行指令,都是在自动在内存中增加数据,数据备份到指定文件位置 => Redis SAVE 命令用于创建当前数据库的备份。

save:立即存储快照(内存数据保存到磁盘中)

bgsave:后台立即存储快照(内存数据保存到磁盘中)

1.6 Redis事务处理
Redis的事务处理比较简单。只能保证client发起的事务中的命令可以连续的执行,而且不会插入其他的client命令,当一个client在连接中发出multi命令时,这个连接就进入一个事务的上下文,该连接后续的命令不会执行,而是存放到一个队列中,当执行exec命令时,redis会顺序的执行队列中的所有命令。如果其中执行出现错误,执行正确的不会回滚,不同于关系型数据库的事务。

1.MULTI标记一个事务块的开始(开启)。

2.EXEC执行所以事务块内的命令。

127.0.0.1:6379> multi
Ok
127.0.0.1:6379> set user ak
QUEUED
127.0.0.1:6379> set school Tsinghua
QUEUED
127.0.0.1:6379> set Class Pking
QUEUED
127.0.0.1:6379> exec
OK
OK
OK
3.DISCARD取消事务,放弃执行事务块内的所以命令。

127.0.0.1:6379> multi
Ok
127.0.0.1:6379> set user ak
QUEUED
127.0.0.1:6379> set school Tsinghua
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get user
(nil)
4.WATCH key [key ...]监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。

127.0.0.1:6379> watch user
Ok
127.0.0.1:6379> watch school
ok
5.UNWATCH取消WATCH命令对所有key的监视。

1.7 Redis安全连接命令
1.设置在客户端连接是需要指定的密码(由于redis速度相当的快,一秒钟可以150K次的密码尝试,所以需要设置一个密码强度很大的密码)。

设置密码的方式有两种:

(1) 使用config set 命令的requirepass 参数,具体格式为config set requirepass “password”。 (2) 配置redis.conf 中设置requirepass属性,后面为密码。

输入认证的方式也有两种:

(1) 登录时可以 redis-cli -a password

(2)登录后使用 auth password

//1.设置密码:首先需要进入Redis的安装目录,然后修改配置文件redis.conf。根据grep命令的结果,使用vi编辑器修改“# requirepass foobared” 为“requirepass aklman”,然后保存退出。
$ grep -n requirepass /etc/redis.conf
$ sudo vim /etc/redis.conf

//2.重启redis-server与redis-cli:
$ sudo service redis-server restart
$ redis-cli

info
//没有权限提示
auth aklman
info
//成功查询数据
exit
//结果表明第一次info命令失败,在auth认证之后info命令正常返回。最后退出redis-cli。
//或者这样登录:
$ redis-cli -a aklman
info
2.ECHO message:打印字符串

3.PING:查看服务是否运行

4.QUIT:关闭当前连接

5.SELECT index:切换到指定的数据库

1.8 Redis数据持久化aof(Append Only File)
Redis是一个支持持久化的内存数据库,Redis需要经常将内存中的数据同步到磁盘来保证持久化。

Redis支持两种持久化方式:

1、snapshottingRDB(快照),将数据存放到文件里,默认方式。也就是把内存中的内容,压缩之后,直接存储到硬盘中,这种方式在启动的时候,加载速度非常的快!

是将内存中的数据已快照的方式写入到二进制文件中,默认文件dump.rdb,可以通过配置设置自动做快照持久化的方式。可配置Redis在n秒内如果超过m个key被修改就自动保存快照。

save 900 1 #900秒有1个keys改变,就会执行持久化
save 300 10 #300秒有10个keys改变,就会执行持久化,改成save 100 6更方便
save 60 10000 #60秒有1w个keys改变,就会执行持久化
优势:

1.数据库只包含一个文件,通过文件备份策略,定期配置,恢复系统灾难。
2.压缩文件转移到其他介质上。
3.性能最大化,Redis开始持久化时,分叉出进程,由进程完成持久化工作,避免服务器进程执行I/O操作,启动效率高。
劣势:

1.无法高可用:系统一定在定时持久化之前宕机,数据还没写入,数据已经丢失。
通过fock分叉进程完成工作,数据集大的时候,服务器停止几百毫秒甚至1秒。
总结:

redis是一个内存服务器,我们要操作的数据都存储在内存里面的。访问速度是非常的快的,但是我们的数据想要存储到硬盘,就要持久化。持久化的时候,就有持久化的机制,机制就有快照持久化;这种持久化是通过时间与key的改变来确定的。
默认的配置是非常好的配置,说明被改变的值,在没有持久化的时候,是在内存里面的。这个时候如果服务器有异常,这些在内存里面的值,都会被清空!如果服务器异常之后,再次启动,我们就会从持久化的文件里面读取数据到内存,之前没有持久化的数据,就在也找不到了。
2、 Append-only file(缩写为aof),将读写操作存放到文件中。

由于快照方式在一定间隔时间做一次,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

aof比快照方式有更好的持久化性,是由于使用aof时,redis会将每一个收到的写命令都通过write函数写入到文件中当redis启动时会通过重新执行文件中保存的写命令来在内存中重新建立整个数据库的内容。

由于os会在内核中缓存write做的修改,所以可能不是立即写到磁盘上,这样aof方式的持久化也还是有可能会丢失一部分数据。可以通过配置文件告诉redis我们想要通过fsync函数强制os写入到磁盘的时机。

配置文件中的可配置参数:

appendonly yes //启用aof持久化方式

appendfsync everysec //每秒中写入磁盘一次,在性能和持久化方面做了很好的折中

appendfsync no //完全依赖os,性能最好,持久化没有保证

参数说明:

always :总是保存执行的命令到我们的文件里面。任何一个的改变,都要保存到我们的文件里面。时时的写文件,这个就会和IO相关,我们的速度就会变慢。
everysec :每一秒中持久化一次。每一秒有多少改变都进行持久化!就是把我们一秒之内的写操作,修改操作,写进我们的文件里面。
no :就是根据我们系统的IO来随机操作。
每一秒中有600个key被改变,这个时候,如果有异常服务器挂了。我们就失去了600个KEY。
优势:

1.同步:
每秒同步:异步完成,效率高,一旦系统宕机,修改的数据丢失;
每修改同步:同步持久化,每分钟发生的变化记录到磁盘中,效率低,安全;
不同步
2.日志写入操作追加模式append:系统宕机,不影响存在的内容,写入一半数据,若系统崩溃,下次启动redis,redis-check-aof工具解决数据一致性。
3.如果日志过大,自动重写机制,修改的数据写入到到磁盘文件,创建新文件,记录产生的修改命令,重写切换时,保证数据安全。
4.格式清晰的日志文件,完成数据的重建
劣势:

对于相同数据文件,相比RDB,AOF文件较大
效率低
总结:对比两个持久化

快照持久化是把内存中的数据,压缩之后,直接存储到硬盘里面的。启动服务器的时候,直接拷贝到内存就可以直接使用了。
AOF持久化是把我们的操作语句存储到文件里面,启动服务器的时候,会执行这些语句,写在我们的内存里面。写操作会慢于拷贝!!
AOF可以做到每一秒持久化一次;快照持久化是时间和key的改变来匹配的。
1.9 Redis的主从模式(读写分析模式)
Redis通过主从模式可以允许多个slave(副) server拥有和master(主) server相同的数据库副本。从服务器只能读,不能写。

1.Redis Replication的工作原理:

Slave与master建立连接,发送sync同步命令。
Master会启动一个后台进程,将数据库快照保存到文件中,同时Master主进程会开始收集新的写命令并缓存。
后台完成保存后,就将此文件发送给Slave。
Slave将此文件保存到磁盘上。
原理解读:
在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。

如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。

总结:

当从服务器连接上主服务器时候,我们的主服务器就会把数据发送给从服务器,这些数据都是二进制,第一次连接的时候,是全量拷贝。
之后主服务器有任何数据的修改,都会发送给从服务器,现在发送都是修改的数据,就叫增量拷贝。
只要主从之间断开过,再次连接,就会实现一次全量拷贝。
2.Redis Replication的特点:

1.同一个Master可以同步多个Slaves。
2.多个slave可以连接同一个master外,还可以连接到其他的slave(当master重启后,相连的slave转变为master)。
3.Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
4.Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
5.Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
6.为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高(提高了系统的可伸缩性。)。
7.Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
3.如何配置

最少有两台(及以上)服务器
主服务器,端口号:6379;pid文件配置好了;数据目录也配置好了。
从服务器,端口号:6380;pid文件不能和主服务在一起;数据目录不能和主服务器在一起。
也就是一句话把主服务器的配置文件拷贝一份到从服务器一份修改文件名及相应配置参数。(slave.conf与主服务器的redis.conf一个目录里面,端口号是6380,dir /sdata ,appendonly no,再启动新服务器,检验是否启动成功,连接主服务器的IP地址和端口号 slaveod 127.0.0.1 6379,连接主服务器密码 masterauth aklman,停止从服务器再启动,验证)
总结:在Redis的主从配置中,从服务器是一个只读的设备。不能写操作。

第二部分 Redis支持的常用数据类型
2.1 字符串(String)
设置一个值:set key value

set name aklman
获取一个值:get key

get name
同时设置多个值:mset key1 value key2 value

同时获取多个值:mget key1 key2

删除值:del key

自增1(值必须是数字):incr key

自增指定的值:incrby key

incrby可以操作的最大范围:有符号的264;而修改Memcache的最大范围描述是无符号的264
超过Redis在整形最大范围的时候,继续自增会报错;而Memcache在最大值时继续增加会到0再继续加。自减也同理,只是把增加数值设定负数即可。Memcache在最小值时继续向下减依然是最小值。

Redis设置的数和增加的数值可以使用负数,Memcache不能使用负数。增减与上同理。

2.2 散列表(Hash)
形式:key => array(field1=>value1,field2=>value2,field3=>value2);value1可以重复,field不能重复。

设置值:hset key field value

hset user name aklman
获取值:hget key field

hget user name
设定多个值:hmset key field1 value1 field2 value2

hmset student name aklman age 18 sex 1
获取多个值(字段值的顺序可以换):hmget key field1 field2 field3

hash表中设定的字段值是唯一的,如果之前有,就会覆盖!!
获取hash标的field和value(获取所以字段及相应值):hgetall key

获取hash表里面的field:hkeys key

获取hash表里面的value的个数:hlen key

删除hash表里面的field值:hdel key field1 field2

注意:hash表中的操作,必须使用hash的方法来操作,字符串的操作就用字符串的方式,不能混着用。

2.3 列表(List)
列表:双向列表,队列,堆栈;里面的值是可以重复的。

双向列表:一边可以进出,另一边也可以进出
队列:只能一边进入,另一边弹出,先进先出
堆栈:只有一个口,口先进先出
1.双向列表:

给一个列表从左(右)边添加内容:lpush(rpush) Listname value1 value2 value3

查看list的内容:lrange Listname 起始位置(0或者其他) 结束位置(-1表示最后面)

从左(右)边弹出一个值:lpop(rpop) Listname

查看列表的长度:llen Listname

2.队列:

给一个列表从左边添加内容:lpushListname value1 value2 value3

从左边弹出一个值:lpop Listname

给一个列表从右边添加内容:rpush Listname value1 value2 value3

从右边弹出一个值:rpop Listname

3.堆栈

给一个列表从左边添加内容:lpushListname value1 value2 value3

从左边弹出一个值:lpop Listname

给一个列表从右边添加内容:rpush Listname value1 value2 value3

从右边弹出一个值:rpop Listname

2.4 集合(Set)
添加数据:sadd set value1 value2 value3

添加完数据后再想添加数据,可以再sadd setvalue4 value5 value3,发现直插入成功两个,因为集合不允许values的值重复出现。
查看数据:smembers set

随机弹出:spop set

为什么集合里面的数据能随机弹出?原因是集合中的数据是无序的,也就是无序集合有这个特性。
随机弹出多个值:spop set n (n不能超过集合元素数)

查看长度:scard set

交集:sinter setA setB

交集就是它们的共同部分,与数学中学的一个样
并集:sunion setA setB

重复的内容只显示一次。
差集:sdiff setA setB

redis里面的差集,是只显示,第一个集合的内容
2.5 有序集合(SortedSet)
添加数据:zadd SortedSetKey number1 value1 number2 value2

查看长度:zcard SortedSetKey

查看有序集合里面的值:zrange SortedSetKey 起始位置 结束位置(-1表示最后的位置)

显示有序集合排序的编号:zrange SortedSetKey 起始位置 结束位置(-1表示最后的位置) withscores

修改排序号:zincrby SortedSetKey n value1

把value1的排序号改成n(表示数字)
显示倒序:zrevrange SortedSetKey 起始位置 结束位置(-1表示最后的位置)

显示带编号的倒序:zrevrange SortedSetKey 起始位置 结束位置(-1表示最后的位置) withscores

注意:

当插入相同排的值时会覆盖写之前数据也就说会number一样覆盖value,value一样覆盖number。
无序集合与有序集合:里面的值都是唯一的,不可重复。当写入的值,里面已经有的时候,就直接覆盖!!
2.6 键(Key)
1.查看Redis里面有多少个key:keys *

一一列出来,星号是通配符,分左匹配和右匹配,左匹配列出指定字符开头的key,右匹配列出指定字符结尾的key。
通配符很重要,用Redis的时候,肯定是数据两特别大,此时要去测试数据,有很多类型的测试数据,都是只能使用一次,使用一次之后就要删除的,假如这些数据都要存储在Redis里面的,因此我们就要使用这种操作来删除不需要的数据。反复此时,测试玩删除数据之后再测试。
2.几条常用命令:

//在命令行直接运行命令
redis-cli keys ''
//在命令行删除内容,指定删除的key
redis-cli del 'test'
//结合两个命令实现搜索并且删除key,这样写会报错,因为keys在执行完成之后,一次性把文档里面拿给了del,此时,del就认为你文档里面的值,是一个值,要删除就会报错。
redis-cli keys '
' | redis-cli del
//解决方式如下,xargs的含义是:当左边命令结果通过管道的时候,只要有xargs参数,它就是告诉左边的命令,你执行一条结果,就给我一条结果。左边在执行的时候,执行一个结果,就立即传给我们右边去执行
redis-cli keys '*t' |xargs redis-cli del
思考问题:

1.当我们左边的查询内容是10G的时候,它要传给右边,需要的内存多少?
占用内存20G,因为使用了xargs参数,就是执行完一个结构就传给右边,一个结构可以占10K,传给右边也是10K,加起来就是20K。

2.在结合find的使用
当数据左边查询(操作)的数据量大的时候,一定使用xargs命令
find /toot/ -name '*php' | xargs ls -l
3.判断key是否存在:exists key

在Redis服务器里面使用
4.设置过期时间:expire key 20

比如,expire sex 10,时间到了就过期,过期了get sex得不到值
5.查看过期时间:ttl key

6.查看key的类型:type key

7.选择库:select 2

默认有16个库,索引是从0开始的,到15结束,默认库是0.
每一个库的数据都是互相独立的。
8.是在redis的客户端去ping我们redis的服务端:ping hello

回hello,也就是发什么给服务器,服务器如果在线都会回复你什么。如果没有在线,那就回复不了。只发ping回pong
9.清空当前库:flushdb

这个命令一般都不会使用,万一删了别人的数据就不好。
10.清空索引的库:flushall

11.Redis的key命名规范

给key进行设置的时候,一定使用:来作为分隔符。
在项目中,应该给每一个项目都设置单独的前缀来区分不同的项目。如,k12id2009,heduid2009
Redis是有密码验证功能的,可以在服务器端开启密码验证,登录的时候,就要输入密码,auth:密码。而Memcache服务器是没有密码验证功能的。密码在redis.conf中设置,设置玩重启redis(ps -ef | grep redis)。
kill pid号:默认是使用-15参数。就是我们的通知我们主进程,关闭系统。主进程会回收它的资源,然后进行关闭。-9 参数:就是我们强制性把程序关闭。
第三部分 总结和扩展
3.1 Redis其他令总结
1.EXISTS and DEL

EXISTS key 判断一个key是否存在;存在返回 1;否则返回0; DEL key 删除某个key,或是一系列key;
DEL key1 key2 key3 key4。成功返回1,失败返回0(key值不存在)。
2.TYPE and KEYS

TYPE key:返回某个key元素的数据类型 ( none:不存在,string:字符,list,set,zset,hash),key不存在返回空。
KEYS key—pattern :返回匹配的key列表 (KEYS foo*:查找foo开头的keys)
3.RANDOMKEY and CLEAR

RANDOMKEY : 随机获得一个已经存在的key,如果当前数据库为空,则返回空字符串。
CLEAR :清除界面。
4.RENAME and RENAMENX

RENAME oldname newname:改key的名字,新键如果存在将被覆盖 。
RENAMENX oldname newname:更改key的名字,如果newname存在,则更新失败;
5.DBSIZE

DBSIZE :返回当前数据库的key的总数
6.CONFIG GET and CONFIG SET

CONFIG GET:用来读取运行Redis服务器的配置参数。
CONFIG SET:用于更改运行Redis服务器的配置参数。
AUTH : 认证密码
7.CONFIG RESETSTAT

CONFIG RESETSTAT:重置数据统计报告,通常返回值为'OK"
3.2 PHP操作Redis基本操作
PHP操作Redis:使用我们的php客户端(redis扩展)连接到redis服务器

connect('127.0.0.1',6379); $redis->auth('aklman'); $redis->set('DomainServer','Aklman.com'); 就可以在Redis从服务器中看到这条信息了。 3.3 INFO 查询信息解读 INFO [section] :查询Redis相关信息。 INFO命令可以查询Redis几乎所有的信息,其命令选项有如下: server: Redis server的常规信息 clients: Client的连接选项 memory: 存储占用相关信息 persistence: RDB and AOF 相关信息 stats: 常规统计 replication: Master/slave请求信息 cpu: CPU 占用信息统计 cluster: Redis 集群信息 keyspace: 数据库信息统计 all: 返回所有信息 default: 返回常规设置信息 标注 [1] 持久化是指存储到磁盘,服务器重启后还可以存在。而存储到内存中的数据,一重启服务器就不存在。 nodeJs项目代码 'use strict' require('./db') let redis = require('redis'); let client = redis.createClient(); let util = require('util'); let getAsync = util.promisify(client.get).bind(client); let lrangeAsync = util.promisify(client.lrange).bind(client); let llenAsync = util.promisify(client.llen).bind(client); client.on('error', err=>{ console.log('redis connect fail : '+err.toString()); }); /** * 字符串key/value类型的使用 */ // async function testSetAndGet() { // // client.set('abc', '床前明月光,疑是地上霜') // let res = await getAsync('abc') // console.log(res); // } // testSetAndGet() async function testList() { // 设置数据 // client.rpush('bbb', 'a') // client.rpush('bbb', 'b') // client.rpush('bbb', 'c') let list = await lrangeAsync('bbb', 0 , -1) console.log(list); } // testList(); let key = 'products' let Product = require('./model/product'); // 准备商品数据,把商品数据取出来,全部放到redis中 async function prepareHotData() { let products = await Product.find() console.log(products); products.forEach( p=>{ client.rpush(key, JSON.stringify(p)) }); } // 热数据的准备,可以在项目启动的时候调用,也可以在用户访问频率较低的深夜调用 // prepareHotData(); let config = require('./config'); // 从redis中取商品数据 async function getProductsFromRedisByPage(page = 1) { let len = await llenAsync(key); if(len > 0){ // 从redis中获取数据,然后返回 let skip = (page-1)*config.PageCount; let stop = skip + config.PageCount - 1; let list = await lrangeAsync(key, skip, stop) console.log(list); return list }else { // redis没有数据,应该从mongodb中取 return await Product.find().skip( (page-1)*config.PageCount ).limit(config.PageCount) .sort("created").select("-__v") } } getProductsFromRedisByPage(2)