-
理解为什么要使用redis,redis解决了什么问题
redis是一种支持Key-Value等多种数据结构的存储系统。可用于缓存,事件发布或订阅,高速队列等场景。该数据库使用 C语言编写,支持网络,提供字符串,哈希,列表,队列,集合结构直接存取,基于内存,可持久化。- redis的优点
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。(事务)
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
- redis的用途
- 会话缓存
- 消息队列,例如支付
- 活动排行榜或者计数
- 发布、订阅消息(消息通知)
- 商品列表、评论列表
- redis的优点
-
单机版安装
redis单节点安装: 1、redis下载 http://download.redis.io/releases/ 2、redis的tar包上传到linux 3、解压 tar -zxf redis-2.8.18.tar.gz cd redis-2.8.18 4、安装gcc、tcl 到此处:https://opsx.alibaba.com/mirror?lang=zh-CN shell> curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo shell> yum clean all shell> yum makecache shell> yum install gcc tcl -y 编译redis源码 shell> make MALLOC=libc 安装: 指定安装路径 shell> make install PREFIX=/opt/redis 配置环境变量 export REDIS_HOME=/opt/redis export PATH=$PATH:$REDIS_HOME/bin 安装redis服务: cd /root/redis-2.8.18/utils ./install_server.sh Port : 6379 Config file : /etc/redis/6379.conf Log file : /var/log/redis_6379.log Data dir : /var/lib/redis/6379 Executable : /opt/redis/bin/redis-server Cli Executable : /opt/redis/bin/redis-cli Port : 9000 Config file : /opt/redis/myconf Log file : /opt/redis/mylog Data dir : /opt/redis/mydata Executable : /opt/redis/bin/redis-server Cli Executable : /opt/redis/bin/redis-cli
-
五种数据类型的操作
. 1. 字符串的增删改查#增加一个key为ay_key的值 127.0.0.1:6379> set ay_key "ay" OK #查询ay_key的值 127.0.0.1:6379> get ay_key "ay" #修改ay_key的值 127.0.0.1:6379> set ay_key "new_ay" OK 127.0.0.1:6379> get ay_key "new_ay" #修改ay_key名称 127.0.0.1:6379> rename ay_key new_ay_key OK 127.0.0.1:6379> keys * 1) "new_ay_key" #删除ay_key 127.0.0.1:6379> del ay_key (integer) 0 #查询是否存在ay_key 0 127.0.0.1:6379> exists ay_key (integer) 0
-
Set集合的增删改查
#删除当前选择数据库中的所有key 127.0.0.1:6379> flushdb OK #生成set集合,添加4个数据 127.0.0.1:6379> sadd set_ay_key "ay" "al" "xy" "xl" (integer) 4 #查询set里面所有值 127.0.0.1:6379> smembers set_ay_key 1) "xy" 2) "al" 3) "ay" 4) "xl" #删除value为"xl" , 返回 1 如果没有返回 0 127.0.0.1:6379> srem set_ay_key "xl" (integer) 1 127.0.0.1:6379> smembers set_ay_key 1) "xy" 2) "al" 3) "ay" #添加value为"xl" 127.0.0.1:6379> sadd set_ay_key "xl" (integer) 1 127.0.0.1:6379> smembers set_ay_key 1) "xy" 2) "al" 3) "ay" 4) "xl" #添加value为"xl" 添加不进去,但也不报错,set是不允许重复的 127.0.0.1:6379> sadd set_ay_key "xl" (integer) 0 #不多解释 127.0.0.1:6379> sadd set_ay_key "xl" (integer) 0 #不多解释 127.0.0.1:6379> sadd set_ay_key "xl" (integer) 0
-
List集合的增删改查
#添加key为list_ay_key的list集合 127.0.0.1:6379> lpush list_ay_key "ay" "al" "xy" "xl" (integer) 4 #查询key为list_ay_key的集合 127.0.0.1:6379> lrange list_ay_key 0 -1 1) "xl" 2) "xy" 3) "al" 4) "ay" #往list尾部添加元素 127.0.0.1:6379> rpush list_ay_key "together" (integer) 5 #往list头部添加元素 127.0.0.1:6379> lpush list_ay_key "first" (integer) 6 #查询list集合 127.0.0.1:6379> lrange list_ay_key 0 -1 1) "first" 2) "xl" 3) "xy" 4) "al" 5) "ay" 6) "together" #更新index为0的值 127.0.0.1:6379> lset list_ay_key 0 "update_first" OK 127.0.0.1:6379> lrange list_ay_key 0 -1 1) "update_first" 2) "xl" 3) "xy" 4) "al" 5) "ay" 6) "together" #删除index为1上的值 127.0.0.1:6379> lrem list_ay_key 1 "update_first" (integer) 1 127.0.0.1:6379> lrange list_ay_key 0 -1 1) "xl" 2) "xy" 3) "al" 4) "ay" 5) "together"
-
Hash集合(一个key连着一个map)的增删改查
127.0.0.1:6379> flushdb OK #生成hash集合,并添加key 为uuid_one value 为"12345" 127.0.0.1:6379> hset hash_ay_key "uuid_one" "12345" (integer) 1 127.0.0.1:6379> hlen hash_ay_key (integer) 1 #返回集合所有的key 127.0.0.1:6379> hkeys hash_ay_key 1) "uuid_one" #返回集合所有value 127.0.0.1:6379> hvals hash_ay_key 1) "12345" #集合添加值 127.0.0.1:6379> hset hash_ay_key "uuid_two" "22222" (integer) 1 #集合添加值 127.0.0.1:6379> hset hash_ay_key "uuid_three" "33333" (integer) 1 #获得key为uuid_one的值 127.0.0.1:6379> hget hash_ay_key uuid_one "12345" #删除key为uuid_three的值 127.0.0.1:6379> hdel hash_ay_key uuid_three (integer) 1 127.0.0.1:6379> hkeys hash_ay_key 1) "uuid_one" 2) "uuid_two" #获得所有,包括key和value 127.0.0.1:6379> hgetall hash_ay_key 1) "uuid_one" 2) "12345" 3) "uuid_two" 4) "22222" #更新key为uuid_one的值 127.0.0.1:6379> hset hash_ay_key uuid_one "11111" (integer) 0 127.0.0.1:6379> hset hash_ay_key "uuid_one" "11111" (integer) 0 127.0.0.1:6379> hgetall hash_ay_key 1) "uuid_one" 2) "11111" 3) "uuid_two" 4) "22222"
-
SortedSet集合(有序的set)的增删改查
#sorted set添加值ay 排序值为 1 127.0.0.1:6379> zadd zset_ay_key 1 "ay" (integer) 1 127.0.0.1:6379> zadd zset_ay_key 2 "al" (integer) 1 127.0.0.1:6379> zadd zset_ay_key 3 "xy" (integer) 1 127.0.0.1:6379> zadd zset_ay_key 4 "xl" (integer) 1 #查询所有的值 127.0.0.1:6379> zrange zset_ay_key 0 -1 1) "ay" 2) "al" 3) "xy" 4) "xl" #删除所有的值 127.0.0.1:6379> zrem zet_ay_key "xl" (integer) 0 127.0.0.1:6379> zrange zset_ay_key 0 -1 1) "ay" 2) "al" 3) "xy" 4) "xl"
什么是持久化
将数据从掉电易失的内存存放到能够永久存储的设备上(Redis是存储在内存中的数据库)
Redis为什么需要持久化
基于内存的,机器断电后数据会丢失,为了保证数据的可靠,需要持久化存储
缓存服务器,不需要
内存数据库,需要
消息队列,需要
Redis持久化方式
- RDB(Redis DB)–> hdfs: fsimage (只记录数据)
- AOF(AppendOnlyFile)–> hdfs : edit logs 关闭的 (记录操作语句,比RDB大)
RDB
在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中
方式:产生一个RDB:
a. 阻塞方式:客户端中执行save命令 (不要用save,会阻塞,用bgsave)
b. 非阻塞方式:(复杂度高?)bgsave
策略
自动:按照配置文件中的条件满足就执行BGSAVE
save 60 1000,Redis要满足在60秒内至少有1000个键被改动,会自动保存一次
手动:客户端发起SAVE、BGSAVE命令
SAVE命令
redis > save
阻塞Redis服务,无法响应客户端请求
创建新的dump.rdb替代旧文件
BGSAVE命令()
redis > bgsave
非阻塞,Redis服务正常接收处理客户端请求
Redis会fork()一个新的子进程来创建RDB文件,子进程处理完后会向父进程发送一个信号,通知它处理完毕
父进程用新的dump.rdb替代旧文件
BGSAVE是一个异步命令
fork():copy on write -->写时拷贝
子进程内存中存储父进程内实时内存的指向,不必开辟真实800G的内存占用
父进程不会阻塞,如果客户端修改了父进程的内存,阻塞(cow):父进程的值,会在子进程中开辟(旧的)。父进程才真正修改。阻塞是很小。
小的窗口:9:00 BGSAVE 10:00完成,持久化数据存储的是9:00
SAVE 和 BGSAVE 命令对比
SAVE不用创建新的进程,速度略快
BGSAVE需要创建子进程,消耗额外的内存
SAVE适合停机维护,服务低谷时段
BGSAVE适合线上执行
自动执行
本质上就是BGSAVE
默认配置
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis/6379
只要上面三个条件满足一个,就自动执行备份。
创建RDB文件之后,时间计数器和次数计数器会清零。所以多个条件的效果不是叠加的
RDB的优缺点
优点
完全备份,不同时间的数据集备份可以做到多版本恢复
紧凑的单一文件,方便网络传输,适合灾难恢复
恢复大数据集速度较AOF快
缺点
会丢失最近写入、修改的而未能持久化的数据
fork过程非常耗时,会造成毫秒级不能响应客户端请求
RDB生产环境
创建一个定时任务cron job,每小时或者每天将dump.rdb复制到指定目录
确保备份文件名称带有日期时间信息,便于管理和还原对应的时间点的快照版本
定时任务删除过期的备份
如果有必要,跨物理主机、跨机架、异地备份
AOF
Append only file,采用追加的方式保存
默认文件appendonly.aof
记录所有的写操作命令,在服务启动的时候使用这些命令就可以还原数据库
调整AOF持久化策略,可以在服务出现故障时,不丢失任何数据,也可以丢失一秒的数据。相对于RDB损失小得多
AOF写入机制
AOF方式不能保证绝对不丢失数据
目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是先将内容放入一个内存缓冲区(buffer)里面,等到缓冲区被填满,或者用户执行fsync调用和fdatasync调用时才将储存在缓冲区里的内容真正的写入到硬盘里,未写入磁盘之前,数据可能会丢失
写入磁盘的策略
appendfsync选项,这个选项的值可以是always、everysec或者no
always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据
everysec(默认):服务器每一秒重调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据
no:服务器不主动调用fdatasync,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的
运行速度:always的速度慢,everysec和no都很快
AOF文件优化 (重写机制 合并)
原有AOF文件 重写后的AOF文件 SELECT 0 SELECT 0 SADD fruits “apple” SADD fruits “apple” “banana” “cherry” SADD fruits “banana” SET msg “hello world again!” SADD fruits “cherry” RPUSH lst 3 5 7 SADD fruits “apple” INCR counter INCR counter DEL counter SET msg “hello world” SET msg “hello world again!” RPUSH lst 1 3 5 RPUSH lst 7 LPOP lst AOF重写机制
AOF文件过大
合并重复的操作,AOF会使用尽可能少的命令来记录
重写过程
1、执行AOF重写请求
2、父进程执行fork创建子进程,开销等同于bgsave过程
3.1、主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区,并根据appendfsync策略同步到磁盘,保证原有AOF机制正确性。
3.2、由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
4、子进程根据内存快照,按照命令合并规则写入到新AOF文件。每次批量写入硬盘数据量由aof-rewrite-incremental-fsync控制,默认是32MB,防止单词刷盘数据过多造成硬盘阻塞。
5.1、新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。
5.2、父进程把AOF重写缓冲区数据写入到新的AOF文件。
5.3、使用新AOF文件替换老文件,完成AOF重写。
注:如果写入操作的时候出现故障导致命令写半截,可以使用redis-check-aof工具修复
AOF重写触发
手动:客户端向服务器发送BGREWRITEAOF命令
自动:配置文件中的选项,自动执行BGREWRITEAOF命令
- auto-aof-rewrite-min-size <size>,触发AOF重写所需的最小体积:只要在AOF文件的体积大于等于size时,才会考虑是否需要进行AOF重写,这个选项用于避免对体积过小的AOF文件进行重写死循环
-
- auto-aof-rewrite-percentage <percent>,指定触发重写所需的AOF文件体积百分比:当AOF文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的AOF文件体积的percent %时,就会触发AOF重写。(如果服务器刚刚启动不久,还没有进行过AOF重写,那么使用服务器启动时载入的AOF文件的体积来作为基准值)。将这个值设置为0表示关闭自动AOF重写
AOF重写配置项举例
auto-aof-rewrite-percentage 100:只有当AOF文件的增量大于起始size的100%时(就是文件大小翻了一倍),启动重写
auto-aof-rewrite-min-size 64mb:当AOF文件大于64MB时候,可以考虑重写AOF文件
appendonly no / yes:默认关闭(no),请开启(yes)
AOF优缺点
优点
- 写入机制,默认fysnc每秒执行,性能很好不阻塞服务,最多丢失一秒的数据
- 重写机制,优化AOF文件
- 如果误操作了(FLUSHALL等),只要AOF未被重写,停止服务移除AOF文件尾部FLUSHALL命令,重启Redis,可以将数据集恢复到 FLUSHALL 执行之前的状态
缺点
- 相同数据集,AOF文件体积较RDB大了很多
- 恢复数据库速度比RDB慢(文本,命令重演)