只有光头才能变强html
今天继续来学习Redis,上一篇从零单排学Redis【青铜】已经将Redis经常使用的数据结构过了一遍了。若是还没看的同窗能够先去看一遍再回来~git
这篇主要讲的内容有:程序员
本文力求简单讲清每一个知识点,但愿你们看完能有所收获github
咱们应该都用过MySQL,MySQL咱们能够在里边建立好几个库:redis
一样地,Redis服务器中也有数据库这么一个概念。若是不指定具体的数量,默认会有16个数据库。sql
上面的命令咱们也能够发现:当切换到15号数据库,存进15号库的数据,再切换到0号数据库时,是获取不到的!数据库
Redis服务器用redisServer结构体来表示,其中redisDb是一个数组,用来保存全部的数据库,dbnum表明数据库的数量(这个能够配置,默认是16)数组
struct redisServer{ //redisDb数组,表示服务器中全部的数据库 redisDb *db; //服务器中数据库的数量 int dbnum; };
咱们知道Redis是C/S结构,Redis客户端经过redisClient结构体来表示:缓存
typedef struct redisClient{ //客户端当前所选数据库 redisDb *db; }redisClient;
Redis客户端链接Redis服务端时的示例图:安全
Redis中对每一个数据库用redisDb结构体来表示:
typedef struct redisDb { int id; // 数据库ID标识 dict *dict; // 键空间,存放着全部的键值对 dict *expires; // 过时哈希表,保存着键的过时时间 dict *watched_keys; // 被watch命令监控的key和相应client long long avg_ttl; // 数据库内全部键的平均TTL(生存时间) } redisDb;
从代码上咱们能够发现最重要的应该是dict *dict
,它用来存放着全部的键值对。对于dict
数据结构(哈希表)咱们在上一篇也已经详细说了。通常咱们将存储全部键值对的dict
称为键空间。
键空间示意图:
Redis的数据库就是使用字典(哈希表)来做为底层实现的,对数据库的增删改查都是构建在字典(哈希表)的操做之上的。
例如:
redis > GET message "hello world"
Redis是基于内存,内存是比较昂贵的,容量确定比不上硬盘的。就咱们如今一台普通的机子,可能就8G内存,但硬盘随随便便都1T了。
由于咱们的内存是有限的。因此咱们会干掉不经常使用的数据,保留经常使用的数据。这就须要咱们设置一下键的过时(生存)时间了。
EXPIRE
或者PEXPIRE
命令。EXPIREAT
或者PEXPIREAT
命令。其实EXPIRE
、PEXPIRE
、EXPIREAT
这三个命令都是经过PEXPIREAT
命令来实现的。
咱们在redisDb结构体中还发现了dict *expires;
属性,存放全部键过时的时间。
举个例子基本就能够理解了:
redis > PEXPIREAT message 1391234400000 (integer) 1
设置了message键的过时时间为1391234400000
既然有设置过时(生存)时间的命令,那确定也有移除过时时间,查看剩余生存时间的命令了:
上面咱们已经可以了解到:过时键是保存在哈希表中了。那这些过时键到了过时的时间,就会立马被删除掉吗??
要回答上面的问题,须要咱们了解一下删除策略的知识,删除策略可分为三种
Redis采用的是惰性删除+按期删除两种策略,因此说,在Redis里边若是过时键到了过时的时间了,未必被立马删除的!
若是按期删除漏掉了不少过时key,也没及时去查(没走惰性删除),大量过时key堆积在内存里,致使redis内存块耗尽了,咋整?
咱们能够设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
Redis的内存淘汰机制有如下几种:
通常场景:
使用 Redis 缓存数据时,为了提升缓存命中率,须要保证缓存数据都是热点数据。能够将内存最大使用量设置为热点数据占用的内存量,而后启用allkeys-lru淘汰策略,将最近最少使用的数据淘汰
Redis是基于内存的,若是不想办法将数据保存在硬盘上,一旦Redis重启(退出/故障),内存的数据将会所有丢失。
Redis提供了两种不一样的持久化方法来说数据存储到硬盘里边:
RDB持久化能够手动执行,也能够根据服务器配置按期执行。RDB持久化所生成的RDB文件是一个通过压缩的二进制文件,Redis能够经过这个文件还原数据库的数据。
有两个命令能够生成RDB文件:
SAVE
会阻塞Redis服务器进程,服务器不能接收任何请求,直到RDB文件建立完毕为止。BGSAVE
建立出一个子进程,由子进程来负责建立RDB文件,服务器进程能够继续接收请求。Redis服务器在启动的时候,若是发现有RDB文件,就会自动载入RDB文件(不须要人工干预)
除了手动调用SAVE
或者BGSAVE
命令生成RDB文件以外,咱们可使用配置的方式来按期执行:
在默认的配置下,若是如下的条件被触发,就会执行BGSAVE
命令
save 900 1 #在900秒(15分钟)以后,至少有1个key发生变化, save 300 10 #在300秒(5分钟)以后,至少有10个key发生变化 save 60 10000 #在60秒(1分钟)以后,至少有10000个key发生变化
原理大概就是这样子的(结合上面的配置来看):
struct redisServer{ // 修改计数器 long long dirty; // 上一次执行保存的时间 time_t lastsave; // 参数的配置 struct saveparam *saveparams; };
遍历参数数组,判断修改次数和时间是否符合,若是符合则调用besave()
来生成RDB文件
总结:经过手动调用SAVE
或者BGSAVE
命令或者配置条件触发,将数据库某一时刻的数据快照,生成RDB文件实现持久化。
上面已经介绍了RDB持久化是经过将某一时刻数据库的数据“快照”来实现的,下面咱们来看看AOF是怎么实现的。
好比说咱们对空白的数据库执行如下写命令:
redis> SET meg "hello" OK redis> SADD fruits "apple" "banana" "cherry" (integer) 3 redis> RPUSH numbers 128 256 512 (integer) 3
Redis会产生如下内容的AOF文件:
这些都是以Redis的命令请求协议格式保存的。Redis协议规范(RESP)参考资料:
AOF持久化功能的实现能够分为3个步骤:
flushAppendOnlyFile函数的行为由服务器配置的appendfsyn选项来决定的:
appendfsync always # 每次有数据修改发生时都会写入AOF文件。 appendfsync everysec # 每秒钟同步一次,该策略为AOF的默认策略。 appendfsync no # 从不一样步。高效可是数据不会被持久化。
从字面上应该就更好理解了,这里我就不细说了...
下面来看一下AOF是如何载入与数据还原的:
从前面的示例看出,咱们写了三条命令,AOF文件就保存了三条命令。若是咱们的命令是这样子的:
redis > RPUSH list "Java" "3y" (integer)2 redis > RPUSH list "Java3y" integer(3) redis > RPUSH list "yyy" integer(4)
一样地,AOF也会保存3条命令。咱们会发现一个问题:上面的命令是能够合并起来成为1条命令的,并不须要3条。这样就能够让AOF文件的体积变得更小。
AOF重写由Redis自行触发(参数配置),也能够用BGREWRITEAOF
命令手动触发重写操做。
好比说如今有一个Redis数据库的数据以下:
新的AOF文件的命令以下,没有一条是多余的!
Redis将AOF重写程序放到子进程里执行(BGREWRITEAOF
命令),像BGSAVE
命令同样fork出一个子进程来完成重写AOF的操做,从而不会影响到主进程。
AOF后台重写是不会阻塞主进程接收请求的,新的写命令请求可能会致使当前数据库和重写后的AOF文件的数据不一致!
为了解决数据不一致的问题,Redis服务器设置了一个AOF重写缓冲区,这个缓存区会在服务器建立出子进程以后使用。
RDB持久化对过时键的策略:
SAVE
或者BGSAVE
命令建立出的RDB文件,程序会对数据库中的过时键检查,已过时的键不会保存在RDB文件中。RDB持久化对过时键的策略:
复制模式:
RDB和AOF并不互斥,它俩能够同时使用。
若是Redis服务器同时开启了RDB和AOF持久化,服务器会优先使用AOF文件来还原数据(由于AOF更新频率比RDB更新频率要高,还原的数据更完善)
可能涉及到RDB和AOF的配置:
redis持久化,两种方式 一、rdb快照方式 二、aof日志方式 ----------rdb快照------------ save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir /var/rdb/ -----------Aof的配置----------- appendonly no # 是否打开 aof日志功能 appendfsync always #每个命令都当即同步到aof,安全速度慢 appendfsync everysec appendfsync no 写入工做交给操做系统,由操做系统判断缓冲区大小,统一写入到aof 同步频率低,速度快 no-appendfsync-on-rewrite yes 正在导出rdb快照的时候不要写aof auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ./bin/redis-benchmark -n 20000
官网文档:
如今临近双十一买阿里云服务器就特别省钱!以前我买学生机也要9.8块钱一个月,如今最低价只须要8.3一个月!
不管是Nginx/Elasticsearch/Redis这些技术都是在Linux下完美运行的,若是仍是程序员新手,买一个学习Linux基础命令,学习搭建环境也是不错的选择。
若是有要买服务器的同窗可经过个人连接直接享受最低价:https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.pfn5xpli
若是你们有更好的理解方式或者文章有错误的地方还请你们不吝在评论区留言,你们互相学习交流~~~
参考资料:
一个坚持原创的Java技术公众号:Java3y,欢迎你们关注
3y全部的原创文章: