Redis

缓存背景

由于数据库是建立在硬盘上的,当有大量数据读写数据库时,而硬盘的读写速度慢,导致数据库性能有瓶颈,数据吞吐不够。

因此在客户端和数据库之前间,加一个缓存,而这个缓存是用内存做的,内存的读写速度非常快。 当要对数据库进行读写时,先访问中间层的缓存,读数据时先看缓存中有无想要的数据,若有直接从缓存拿,若无则再去访问数据库;写数据时,先写进缓存,之后缓存再慢慢同步到数据库。这样就帮数据库有效地拦截了一些频繁的读写操作。

【什么样的数据存入缓存】缓存中存的应是读写数据库非常频繁的数据。

【防止缓存穿透】缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。这需要一些算法去识别,比如布隆算法。参考文章👉点击


缓存这一层就用Redis来做。Redis既使用内存,也使用硬盘。作为读写操作的时候是用内存的,但是内存存数据是暂时的,机器一关内存里的东西就没了,所以需要用到硬盘来做缓存备份。内存与硬盘之间是同步数据和恢复数据的关系。

Redis是用C语言写的,Redis支持多种数据结构,key-value、key-map、key-set、key-list等等。比较常用的就是key-value,key一般是字符串,value可以是数字也可以是字符串。但是C语言中是没有字符串的。而Redis中的字符串长度是可变的,是用了SDS结构(Simple Dynamic String)。

1
2
3
4
5
6
7
8
9
10
11
12
13
struct sdshdr {

// 记录 buf 数组中已使用字节的数量
// 等于 SDS 所保存字符串的长度
int len;

// 记录 buf 数组中未使用字节的数量
int free;

// 字节数组,用于保存字符串
char buf[];

};

当字符串变长时,先看sds结构内free还有没有足够的空间,没有的话就要重新创建一个更大的字节数组用以存储变长后的字符串。

关于更多Redis源码的知识这里就不说了,因为我只懂一点皮毛。


Windows使用Redis

Redis是微软开源的一个存储数据库。可以在GitHub上下载👉https://github.com/microsoftarchive/redis/releases

注意window系统中只有64位的系统才能使用Redis。

下载后点击,不需要配置什么,按提示安装就行了。安装后要配置一些配置文件。


设置链接密码,修改redis.windows-service.conf


查看是否允许本地访问,有的版本是允许的,如下所示


配置修改后需要重启Redis,打开系统的”服务“,找到Redis重启即可。


双击redis-cli.exe启动。

输入auth 123456连接Redis。通过set键值对来写入数据,通过get键来获取数据。

CentOS使用Redis

使用安装包下载👇

1
wget http://download.redis.io/releases/redis-4.0.2.tar.gz

解压

1
tar xzf redis-4.0.2.tar.gz

下载gcc依赖环境

1
yum install gcc

执行下面的命令

1
2
3
make MOLLOC=libc

make install

之后再/usr/local/bin目录下就多了Redis的可执行文件

执行命令👇

1
redis-sever &

这样它就可以在后台运行了。

执行ps aux grep|"redis"查看到redis的进程正在执行。

如果要关闭Redis,就杀了它的进程。


node操作Redis

需要npm install redis --save安装redis模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var redis = require('redis');

var port = 6379;
var host = "127.0.0.1";
var password = "123456";

var client = redis.createClient(port, host);
client.auth(password, function () {
console.log("OK,redis连接成功");
});

function getKey(key, callback) {

client.on("connect", function () {
client.get(key, callback);
});

}

function setKey(key, value, callback) {

client.on('connect', function () {
client.set(key, value, callback);
});
}

function callback(error, reply) {
if (error == null) {
console.log(reply);
} else {
console.log(error);
}
}
setKey('iii', 'III', callback);
getKey('iii', callback);


之前说过redis除了key-value的数据结构,还可以存哈希结构的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function sethash(hash, key, value, callback) {
client.on('connect', function () {
client.hset(hash, key, value, callback)
})
}
function gethash(hash, key, callback) {
client.on('connect', function () {
client.hget(hash, key, callback)
})
}
function getallhash(hash, callback) {
client.on('connect', function () {
client.hgetall(hash, callback)
})
}
function hmset(hash, params, callback) {
client.on('connect', function () {
client.hmset(hash, ...params, callback)
})
}
function callback(error, reply) {
if (error == null) {
console.log(reply);
} else {
console.log(error);
}
}

sethash('map1', 'key1', 'value1', callback)
sethash('map1', 'key2', 'value2', callback)
hmset('set1', [0, 3, 1, 12], callback)
gethash('map1', 'key1', callback)
getallhash('map1', callback)
getallhash('set1', callback)