特点及优点
1、开源的,使用C编写,基于内存且支持持久化
2、高性能的Key-Value的NoSQL数据库
3、支持数据类型丰富,字符串strings,散列hashes,列表lists,集合sets,有序集合sorted sets 等等
4、支持多种编程语言(C C++ Python Java PHP ... )
5、单进程单线程
与其他数据库对比
1、MySQL : 关系型数据库,表格,基于磁盘,慢
2、MongoDB:键值对文档型数据库,值为类似JSON文档,数据结构相对单一
3、Redis的诞生是为了解决什么问题?? # 解决硬盘IO带来的性能瓶颈
应用场景
1,缓存 、并发计数、排行榜、生产者消费者模型...
Redis附加功能
1、持久化
将内存中数据保存到磁盘中,保证数据安全,方便进行数据备份和恢复
2、过期键功能
为键设置一个过期时间,让它在指定时间内自动删除
<节省内存空间>
# 音乐播放器,日播放排名,过期自动删除
3、事务功能
原子的执行多个操作
4、主从复制
5、Sentinel哨兵
# Ubuntu安装
sudo apt-get install redis-server
# 服务端启动
sudo /etc/init.d/redis-server status | start | stop | restart
# 客户端连接
redis-cli -h IP地址 -p 6379 -a 密码
#centos
[root@vm ~]# tar -zxvf redis-4.0.8.tar.gz #上传
[root@vm ~]# cd redis-4.0.8/
[root@vm redis-4.0.8]# make && make install
[root@vm redis-4.0.8]# ./utils/install_server.sh //初始化,一路enter
[root@vm redis-4.0.8]# /etc/init.d/redis_6379 stop
[root@vm redis-4.0.8]# vim /etc/redis/6379.conf
70 bind 192.168.1.11
93 port 6379
501 requirepass 123456 #开启密码功能,搭建集群时不要打开注释
[root@vm redis-4.0.8]# /etc/init.d/redis_6379 start
[root@vm redis-4.0.8]# redis-cli -h 192.168.1.11 -a 123456 ping
PONG
通用命令 适用于所有数据类型
# 切换库(number的值在0-15之间,db0 ~ db15)
select number
# 查看键
keys 表达式 # keys *
# 数据类型
type key
# 键是否存在
exists key
# 删除键
del key
# 键重命名
rename key newkey
# 清除当前库中所有数据(慎用)
flushdb
# 清除所有库中所有数据(慎用)
flushall
类型 | 特点 | 使用场景 |
---|---|---|
string | 简单key-value类型,value可为字符串和数字 | 常规计数(验证码,微博数, 粉丝数等功能) |
hash | 是一个string类型的field和value的映射表,hash特别适合用于存储对象 | 存储部分可能需要变更的数据(比如用户信息) |
list | 有序可重复列表 | 消息(任务)队列等,同rabbitmq |
set | 无序不可重复列表 | 存储并计算关系(如微博,关注人或粉丝存放在集合,可通过交集、并集、差集等操作实现如共同关注、共同喜好等功能) |
sorted set | 每个元素带有分值的集合 | 各种排行榜 |
1、字符串、数字,都会转为字符串来存储
2、以二进制的方式存储在内存中
字符串常用命令-必须掌握
# 1. 设置一个key-value
set key value
# 2. 获取key的值
get key
# 3. key不存在时再进行设置(nx)
set key value nx # not exists
# 4. 设置过期时间(ex)
set key value ex seconds
# 5. 同时设置多个key-value
mset key1 value1 key2 value2 key3 value3
# 6. 同时获取多个key-value
mget key1 key2 key3
字符串常用命令-作为了解
# 1.获取长度
strlen key
# 2.获取指定范围切片内容 [包含start stop] -1到结尾
getrange key start stop
# 3.从索引值开始,value替换原内容
setrange key index value
数值操作-字符串类型数字(必须掌握)
# 整数操作
incrby key 步长
decrby key 步长
incr key : +1操作
decr key : -1操作
# 应用场景: 抖音上有人关注你了,是不是可以用INCR呢,如果取消关注了是不是可以用DECR
# 浮点数操作: 自动先转为数字类型,然后再进行相加减,不能使用append
incrbyfloat key step
192.168.1.11:6379> incr fans
(integer) 1
192.168.1.11:6379> incr fans
(integer) 2
192.168.1.11:6379> incr fans
(integer) 3
# 字符串操作
1、set key value
2、set key value nx
3、get key
3、mset key1 value1 key2 value2
4、mget key1 key2 key3
5、set key value nx ex seconds
6、strlen key
# 返回旧值并设置新值(如果键不存在,就创建并赋值)
7、getset key value
# 数字操作
7、incrby key 步长
8、decrby key 步长
9、incr key
10、decr key
11、incrbyfloat key number#(可为正数或负数)
# 设置过期时间的两种方式
# 方式一
1、set key value ex 3
# 方式二
1、set key value
2、expire key 5 # 秒
3、pexpire key 5 # 毫秒
# 查看存活时间
ttl key
# 删除过期
persist key
string数据类型注意
# key命名规范
可采用 - wang:email
# key命名原则
1、key值不宜过长,消耗内存,且在数据中查找这类键值的计算成本高
2、不宜过短,可读性较差
# 值
1、一个字符串类型的值最多能存储512M内容
业务场景
缓存
- 将mysql中的数据存储到redis字符串类型中
并发计数 - 点赞/秒杀
- 说明:通过redis单进程单线程的特点,由redis负责计数,并发问题转为串行问题
带有效期的验证码 - 短信验证码
- 借助过期时间,存放验证码;到期后,自动消亡
1、元素是字符串类型
2、列表头尾增删快,中间增删慢,增删元素是常态
3、元素可重复
4、最多可包含2^32 -1个元素
5、索引同python列表
6、注意使用LRANGE,判断好操作的顺序
列表常用命令
# 增
1、从列表头部压入元素
LPUSH key value1 value2
返回:list长度
2、从列表尾部压入元素
RPUSH key value1 value2
返回:list长度
3、从列表src尾部弹出1个元素,压入到列表dst的头部
RPOPLPUSH src dst
返回:被弹出的元素
4、在列表指定元素后/前插入元素
LINSERT key after|before value newvalue
返回:
1,如果命令执行成功,返回列表的长度
2,如果没有找到 pivot ,返回 -1
3,如果 key 不存在或为空列表,返回 0
# 查
5、查看列表中元素
LRANGE key start stop
# 查看列表中所有元素: LRANGE key 0 -1
6、获取列表长度
LLEN key
# 删
7、从列表头部弹出1个元素
LPOP key
8、从列表尾部弹出1个元素
RPOP key
9、列表头部,阻塞弹出,列表为空时阻塞
BLPOP key timeout
10、列表尾部,阻塞弹出,列表为空时阻塞
BRPOP key timeout
# 关于BLPOP 和 BRPOP
1、如果弹出的列表不存在或者为空,就会阻塞
2、超时时间设置为0,就是永久阻塞,直到有数据可以弹出
3、如果多个客户端阻塞再同一个列表上,使用First In First Service原则,先到先服务
11、删除指定元素
LREM key count value
count>0:表示从头部开始向表尾搜索,移除与value相等的元素,数量为count
count<0:表示从尾部开始向表头搜索,移除与value相等的元素,数量为count
count=0:移除表中所有与value相等的值
返回:被移除元素的数量
12、保留指定范围内的元素
LTRIM key start stop
返回:ok
样例:
LTRIM mylist1 0 2 # 只保留前3条
# 应用场景: 保存微博评论最后500条
LTRIM weibo:comments 0 499
# 改
13、将列表 key 下标为 index 的元素的值设置为 value
LSET key index newvalue
定义
1、位图不是真正的数据类型,它是定义在字符串类型中
2、一个字符串类型的值最多能存储512M字节的内容,位上限:2^32
# 1MB = 1024KB, 1KB = 1024Byte(字节), 1Byte = 8bit(位)
强势点
以实时的进行统计,极其节省空间。
官方在模拟1亿2千8百万用户的模拟环境下,统计“日用户数”的时间消耗小于50ms, 占用16MB内存
SETBIT 命令
#设置某位置上的二进制值,SETBIT key offset value,offset - 偏移量 从0开始,value - 0或者1
# 默认扩展位以0填充
> set name ab # 0110 0001 0110 0010 #查对应的二进制ASC
> get name # "ab"
> setbit name 3 1 #0111 0001 0110 0010
> get name #"qb"
GETBIT 命令
获取某一位上的值,语法:GETBIT key offset
> getbit name 3 #(integer) 1
> getbit name 0 #(integer) 0
BITCOUNT 命令
统计键所对应的值中1的个数,BITCOUNT key start end,参数:start/end是按字节索引
> get bit # "qb" 0111 0001 0110 0010
> bitcount bit 0 0 #(integer) 4
> bitcount bit 0 1 #(integer) 7
应用场景案例
# 网站用户的上线次数统计(寻找活跃用户)
用户名为key,上线的天作为offset,上线设置为1
# 示例,用户名为 user1:login 的用户,今年第1天上线,第30天上线
SETBIT user1:login 0 1
SETBIT user1:login 29 1
BITCOUNT user1:login # 2上线两天
1、由field和关联的value组成的键值对 #类似于python的字典
2、field和value是字符串类型
3、一个hash中最多包含2^32-1个键值对 "key1:{f1:v1,f2:v2,f3,v3}"
优点
1、节约内存空间 - 特定条件下: field字段小于512个,value不能超过64字节
2、可按需获取字段的值
缺点
1,使用过期键功能:键过期功能只能对键进行过期操作,而不能对散列的字段进行过期操作
2,存储消耗大于字符串结构
基本命令操作
# 1、设置单个字段
HSET key field value
HSETNX key field value
# 2、设置多个字段
HMSET key field value field value
# 3、返回字段个数
HLEN key
# 4、判断字段是否存在(不存在返回0)
HEXISTS key field
# 5、返回字段值
HGET key field
# 6、返回多个字段值
HMGET key field filed
# 7、返回所有的键值对
HGETALL key
# 8、返回所有字段名
HKEYS key
# 9、返回所有值
HVALS key
# 10、删除指定字段
HDEL key field
# 11、在字段对应值上进行整数增量运算
HINCRBY key filed increment
# 12、在字段对应值上进行浮点数增量运算
HINCRBYFLOAT key field increment
python操作hash
# 1、更新一条数据的属性,没有则新建
hset(name, key, value)
# 2、读取这条数据的指定属性, 返回字符串类型
hget(name, key)
# 3、批量更新数据(没有则新建)属性,参数为字典
hmset(name, mapping)
# 4、批量读取数据(没有则新建)属性
hmget(name, keys)
# 5、获取这条数据的所有属性和对应的值,返回字典类型
hgetall(name)
# 6、获取这条数据的所有属性名,返回列表类型
hkeys(name)
# 7、删除这条数据的指定属性
hdel(name, *keys)
Python代码hash散列
应用场景:用户维度数据统计
用户维度统计
统计数包括:关注数、粉丝数、喜欢商品数、发帖数
用户为key,不同维度为field,value为统计数
比如关注了5人
HSET user:10000 fans 5
HINCRBY user:10000 fans 1
应用场景: 缓存 - redis+mysql+hash组合使用
原理
用户想要查询个人信息
1、到redis缓存中查询个人信息
2、redis中查询不到,到mysql查询,并缓存到redis
3、再次查询个人信息
1、无序、去重
2、元素是字符串类型
3、最多包含2^32-1个元素
基本命令
# 1、增加一个或者多个元素,自动去重;返回值为成功插入到集合的元素个数
SADD key member1 member2
# 2、查看集合中所有元素
SMEMBERS key
# 3、删除一个或者多个元素,元素不存在自动忽略
SREM key member1 member2
# 4、元素是否存在,返回0,1
SISMEMBER key member
# 5、随机返回集合中指定个数的元素,默认为1个,不会删除原始数据
SRANDMEMBER key [count]
# 6、弹出成员,删除
SPOP key [count]
# 7、返回集合中元素的个数,不会遍历整个集合,只是存储在键当中了
SCARD key
# 8、把元素member从源集合移动到目标集合
SMOVE source destination member
# 9、差集(number1 1 2 3 number2 1 2 4 结果为3),注意先后顺序
SDIFF key1 key2
# 10、差集保存到另一个集合中
SDIFFSTORE destination key1 key2
# 11、交集
SINTER key1 key2
SINTERSTORE destination key1 key2
# 11、并集
SUNION key1 key2
SUNIONSTORE destination key1 key2
案例:微博的共同关注
# 需求: 当用户访问另一个用户的时候,会显示出两个用户共同关注过哪些相同的用户
# 设计: 将每个用户关注的用户放在集合中,求交集即可
# 实现:
user001 = {'peiqi','qiaozhi','danni'}
user002 = {'peiqi','qiaozhi','lingyang'}
user001和user002的共同关注为:
SINTER user001 user002
结果为: {'peiqi','qiaozhi'}
1、有序、去重
2、元素是字符串类型
3、每个元素都关联着一个浮点数分值(score),并按照分值从小到大排列集合的元素(分值可以相同)
4、最多包含2^32-1元素
示例
一个保存了员工薪水的有序集合
分值 | 6000 | 8000 | 10000 | 12000 | |
---|---|---|---|---|---|
元素 | lucy | tom | jim | jack |
一个保存了正在阅读某些技术书的人数
有序集合常用命令
# 在有序集合中添加一个成员 返回值为 成功插入到集合中的元素个数
zadd key score member
> zadd zk1 100 c 90 python 98 c++ 60 php 70 c# 50 go
# 查看指定区间元素(升序)
zrange key start stop [withscores]
> zrange zk1 0 -1
1) "python"
2) "c++"
3) "c"
# 查看指定区间元素(降序)
zrevrange key start stop [withscores]
> zrange zk1 0 1 withscores
1) "python"
2) "90"
3) "c++"
4) "98"
# 查看指定元素的分值
zscore key member
> zscore zk1 python # "90"
# 返回指定区间元素
# offset : 跳过多少个元素,开始索引?
# count : 返回几个
# 小括号 : 开区间 zrangebyscore fruits (2.0 8.0
zrangebyscore key min max [withscores] [limit offset count]
> zrangebyscore zk1 90 95 withscores
1) "python"
2) "90"
# 每页显示10个成员,显示第5页的成员信息:
# limit 40 10
# MySQL: 每页显示10条记录,显示第5页的记录
# limit 40,10
# limit 2,3 显示: 第3 4 5条记录,
# 删除成员
zrem key member
# 增加或者减少分值
zincrby key increment member
> zincrby zk1 10 python #"100"
# 返回元素排名
zrank key member
> zrank zk1 python #(integer) 2 #第一位0 返回索引值
# 返回元素逆序排名
zrevrank key member
> zrevrank zk1 python #(integer) 0
# 删除指定区间内的元素
zremrangebyscore key min max
# 返回集合中元素个数
zcard key
# 返回指定范围中元素的个数
zcount key min max
zcount salary 6000 8000
zcount salary (6000 8000 # 6000
zcount salary (6000 (8000 #6000
# 并集
zunionstore destination numkeys key [weights 权重值] [AGGREGATE SUM|MIN|MAX]
# zunionstore salary3 2 salary salary2 weights 1 0.5 AGGREGATE MAX
# 2代表集合数量,weights之后 权重1给salary,权重0.5给salary2集合,算完权重之后执行聚合AGGREGATE
# 交集:和并集类似,只取相同的元素
zinterstore destination numkeys key1 key2 weights weight AGGREGATE SUM(默认)|MIN|MAX
类型 | 特点 | 使用场景 |
---|---|---|
string | 简单key-value类型,value可为字符串和数字 | 常规计数(验证码,微博数, 粉丝数等功能) |
hash | 是一个string类型的field和value的映射表,hash特别适合用于存储对象 | 存储部分可能需要变更的数据(比如用户信息) |
list | 有序可重复列表 | 消息(任务)队列等,同rabbitmq |
set | 无序不可重复列表 | 存储并计算关系(如微博,关注人或粉丝存放在集合,可通过交集、并集、差集等操作实现如共同关注、共同喜好等功能) |
sorted set | 每个元素带有分值的集合 | 各种排行榜 |
单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断
不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制
事务命令
1、MULTI # 开启事务 mysql begin
2、命令1 # 放入执行队列
3、命令2 ... ...
4、EXEC # 提交到redis依次执行 mysql commit
4、DISCARD # 取消事务 mysql 'rollback'
使用步骤
# 开启事务
127.0.0.1:6379> MULTI
OK
# 命令1入队列
127.0.0.1:6379> INCR n1
QUEUED
# 命令2入队列
127.0.0.1:6379> INCR n2
QUEUED
# 提交到数据库执行
127.0.0.1:6379> EXEC
1) (integer) 1
2) (integer) 1
# 1、命令语法错误,命令入队失败,直接自动discard退出这个事务,都不执行
这个在命令在执行调用之前会发生错误。例如,这个命令可能有语法错误(错误的参数数量,错误的命令名)
处理方案:语法错误则自动执行discard,都不执行
案例:
127.0.0.1:6379[7]> MULTI
OK
127.0.0.1:6379[7]> get a
QUEUED
127.0.0.1:6379[7]> getsss a
(error) ERR unknown command 'getsss'
127.0.0.1:6379[7]>
127.0.0.1:6379[7]>
127.0.0.1:6379[7]> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
# 2、命令语法没错,但类型操作有误,则事务执行调用之后失败,无法进行事务回滚
我们执行了一个由于错误的value的key操作(例如对着String类型的value施行了List命令操作)
处理方案:发生在EXEC之后的是没有特殊方式去处理的:即使某些命令在事务中失败,其他命令都将会被执行。
案例
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set num 10
QUEUED
127.0.0.1:6379> LPOP num
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get num
"10"
127.0.0.1:6379>
持久化定义:将数据从掉电易失的内存放到永久存储的设备上,因为所有的数据都在内存上。
1、保存真实的数据
2、将服务器包含的所有数据库数据以二进制文件的形式保存到硬盘里面
3、默认文件名 :/var/lib/redis/dump.rdb
创建rdb文件的两种方式
**方式一:**redis终端中使用SAVE或者BGSAVE命令
127.0.0.1:6379> SAVE
OK
# 特点 不要用
1、执行SAVE命令过程中,redis服务器将被阻塞,无法处理客户端发送的命令请求
2、如果RDB文件已经存在,那么服务器将自动使用新的RDB文件代替旧的RDB文件
# 工作中定时持久化保存一个文件
127.0.0.1:6379> BGSAVE
Background saving started
# 执行过程如下
1、客户端 发送 BGSAVE 给服务器
2、服务器马上返回 Background saving started 给客户端
3、服务器 fork() 子进程做这件事情
4、服务器继续提供服务
5、子进程创建完RDB文件后再告知Redis服务器,结束子进程
# 配置文件相关
/etc/redis/redis.conf
263行: dir /var/lib/redis # 表示rdb文件存放路径
253行: dbfilename dump.rdb # 文件名
# 两个命令比较
SAVE比BGSAVE快,因为需要创建子进程,消耗额外的内存
# 补充:可以通过查看日志文件来查看redis都做了哪些操作
# 日志文件:配置文件中搜索 logfile
logfile /var/log/redis/redis-server.log
方式二:设置配置文件条件满足时自动保存(使用最多)
# redis配置文件默认
218行: save 900 1
219行: save 300 10
表示如果距离上一次创建RDB文件已经过去了300秒,超过10次修改,那么自动执行BGSAVE命令
220行: save 60 10000
1、只要三个条件中的任意一个被满足时,服务器就会自动执行BGSAVE
2、每次创建RDB文件之后,服务器为实现自动持久化而设置的时间计数器和次数计数器就会被清零,并重新开始计数,所以多个保存条件的效果不会叠加
# 该配置项也可以在命令行执行 [不推荐]
redis>save 60 10000
RDB缺点
1、创建RDB文件需要将服务器所有的数据库的数据都保存起来,这是一个非常消耗资源和时间的操作,
所以服务器需要隔一段时间才创建一个新的RDB文件,也就是说,创建RDB文件不能执行的过于频繁,
否则会严重影响服务器的性能
2、可能丢失数据
1、存储的是命令,而不是真实数据
2、默认不开启
# 开启方式(修改配置文件)
1、/etc/redis/redis.conf
672行: appendonly yes # 把 no 改为 yes
676行: appendfilename "appendonly.aof"
2、重启服务
sudo /etc/init.d/redis-server restart
AOF持久化原理及优点
# 原理
1、每当有修改数据库的命令被执行时,
2、因为AOF文件里面存储了服务器执行过的所有数据库修改的命令,所以给定一个AOF文件,服务器只要重新执行一遍AOF文件里面包含的所有命令,就可以达到还原数据库的目的
# 优点
用户可以根据自己的需要对AOF持久化进行调整,让Redis在遭遇意外停机时不丢失任何数据,或者只丢失一秒钟的数据,这比RDB持久化丢失的数据要少的多
特殊说明
因为
虽然服务器执行一个修改数据库的命令,就会把执行的命令写入到AOF文件,但这并不意味着AOF文件持久化不会丢失任何数据,在目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是将内容放入一个内存缓存区(buffer)里面,等到缓冲区被填满时才将存储在缓冲区里面的内容真正写入到硬盘里
所以
1、AOF持久化:当一条命令真正的被写入到硬盘里面时,这条命令才不会因为停机而意外丢失
2、AOF持久化在遭遇停机时丢失命令的数量,取决于命令被写入到硬盘的时间
3、越早将命令写入到硬盘,发生意外停机时丢失的数据就越少,反之亦然
策略 - 配置文件
# 打开配置文件:/etc/redis/redis.conf,找到相关策略如下
1、701行: alwarys
服务器每写入一条命令,就将缓冲区里面的命令写入到硬盘里面,服务器就算意外停机,也不会丢失任何已经成功执行的命令数据
2、702行: everysec(# 默认)
服务器每一秒将缓冲区里面的命令写入到硬盘里面,这种模式下,服务器即使遭遇意外停机,最多只丢失1秒的数据
3、703行: no
服务器不主动将命令写入硬盘,由操作系统决定何时将缓冲区里面的命令写入到硬盘里面,丢失命令数量不确定
# 运行速度比较
always:速度慢
everysec和no都很快,默认值为everysec
AOF重写
思考:AOF文件中是否会产生很多的冗余命令?
为了让AOF文件的大小控制在合理范围,避免胡乱增长,redis提供了AOF重写功能,通过这个功能,服务器可以产生一个新的AOF文件
-- 新的AOF文件记录的数据库数据和原由的AOF文件记录的数据库数据完全一样
-- 新的AOF文件会使用尽可能少的命令来记录数据库数据,因此新的AOF文件的提及通常会小很多
-- AOF重写期间,服务器不会被阻塞,可以正常处理客户端发送的命令请求
示例
原有AOF文件 | 重写后的AOF文件 |
---|---|
select 0 | SELECT 0 |
sadd myset peiqi | SADD myset peiqi qiaozhi danni lingyang |
sadd myset qiaozhi | SET msg ‘hello tarena’ |
sadd myset danni | RPUSH mylist 2 3 5 |
sadd myset lingyang | |
INCR number | |
INCR number | |
DEL number | |
SET message ‘hello world’ | |
SET message ‘hello tarena’ | |
RPUSH mylist 1 2 3 | |
RPUSH mylist 5 | |
LPOP mylist |
AOF重写-触发
1、客户端向服务器发送BGREWRITEAOF命令
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
2、修改配置文件让服务器自动执行BGREWRITEAOF命令
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 解释
1、只有当AOF文件的增量大于100%时才进行重写,也就是大一倍的时候才触发
# 第一次重写新增:64M
# 第二次重写新增:128M
# 第三次重写新增:256M(新增128M)
RDB和AOF持久化对比
RDB持久化 | AOF持久化 |
---|---|
全量备份,一次保存整个数据库 | 增量备份,一次保存一个修改数据库的命令 |
保存的间隔较长 | 保存的间隔默认为一秒钟 |
数据还原速度快 | 数据还原速度一般,冗余命令多,还原速度慢 |
执行SAVE命令时会阻塞服务器,但手动或者自动触发的BGSAVE不会阻塞服务器 | 无论是平时还是进行AOF重写时,都不会阻塞服务器 |
# 用redis用来存储真正数据,每一条都不能丢失,都要用always,有的做缓存,有的保存真数据,我可以开多个redis服务,不同业务使用不同的持久化,新浪每个服务器上有4个redis服务,整个业务中有上千个redis服务,分不同的业务,每个持久化的级别都是不一样的。
数据恢复(无需手动操作)
既有dump.rdb,又有appendonly.aof,恢复时找谁?
先找appendonly.aof
配置文件常用配置总结
# 设置密码
1、requirepass password
# 开启远程连接
2、bind 127.0.0.1 ::1 注释掉
3、protected-mode no 把默认的 yes 改为 no
# rdb持久化-默认配置
4、dbfilename 'dump.rdb'
5、dir /var/lib/redis
# rdb持久化-自动触发(条件)
6、save 900 1
7、save 300 10
8、save 60 10000
# aof持久化开启
9、appendonly yes
10、appendfilename 'appendonly.aof'
# aof持久化策略
11、appendfsync always
12、appendfsync everysec # 默认
13、appendfsync no
# aof重写触发
14、auto-aof-rewrite-percentage 100
15、auto-aof-rewrite-min-size 64mb
# 设置为从服务器
16、salveof <master-ip> <master-port>
Redis相关文件存放路径
1、配置文件: /etc/redis/redis.conf
2、备份文件: /var/lib/redis/*.rdb|*.aof
3、日志文件: /var/log/redis/redis-server.log
4、启动文件: /etc/init.d/redis-server
# /etc/下存放配置文件
# /etc/init.d/下存放服务启动文件
1、一个Redis服务可以有多个该服务的复制品,这个Redis服务成为master,其他为slaves
2、master会一直将自己的数据更新同步给slaves,保持主从同步
3、只有master可以执行写命令,slave只能执行读命令
作用:分担了读的压力(高并发)
原理
从服务器执行客户端发送的读命令,比如GET、LRANGE、SMEMMBERS、HGET、ZRANGE等等,客户端可以连接slaves执行读请求,来降低master的读压力
实现方式
# 从服务端
redis-server --port 6380 --slaveof 127.0.0.1 6379
# 从客户端
redis-cli -p 6380
> keys *
# 发现是复制了原6379端口的redis中数据
> set mykey 123
(error) READONLY You can't write against a read only slave.
# 从服务器只能读数据,不能写数据
# 两条命令
1、>slaveof ip port
2、>slaveof no one
# 服务端启动
redis-server --port 6381
# 客户端连接
~$ redis-cli -p 6381
> set mykey 123
OK
# 切换为从
> slaveof 127.0.0.1 6379
OK
> set newkey 456
(error) READONLY You can't write against a read only slave.
> keys *
1) "myset"
2) "mylist"
# 再切换为主
> slaveof no one
OK
> set name hello
OK
# 每个redis服务,都有1个和他对应的配置文件
# 两个redis服务
1、6379 -> /etc/redis/redis.conf
2、6380 -> /home/redis_6380.conf
# 修改配置文件
vi redis_6800.conf
slaveof 127.0.0.1 6379
port 6800
# 启动redis服务
redis-server /home/redis_6380.conf
# 客户端连接测试
redis-cli -p 6380
> hset user:1 username guods
(error) READONLY You can't write against a read only slave.
问题:master挂了怎么办?
1、一个Master可以有多个Slaves
2、Slave下线,只是读请求的处理性能下降
3、Master下线,写请求无法执行
4、其中一台Slave使用SLAVEOF no one命令成为Master,其他Slaves执行SLAVEOF命令指向这个新的Master,从它这里同步数据
# 以上过程是手动的,能够实现自动,这就需要Sentinel哨兵,实现故障转移Failover操作
Redis之哨兵 - sentinel
1、Sentinel会不断检查Master和Slaves是否正常
2、每一个Sentinel可以监控任意多个Master和该Master下的Slaves
案例演示
**1、**环境搭建
# 共3个redis的服务
1、启动6379的redis服务器
sudo /etc/init.d/redis-server start
2、启动6380的redis服务器,设置为6379的从
redis-server --port 6380
~$ redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
3、启动6381的redis服务器,设置为6379的从
redis-server --port 6381
~$ redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379
**2、**安装并搭建sentinel哨兵
# 1、安装redis-sentinel
sudo apt install redis-sentinel
验证: sudo /etc/init.d/redis-sentinel stop
# 2、新建配置文件sentinel.conf
port 26379
sentinel monitor tedu 127.0.0.1 6379 1
# 3、启动sentinel
方式一: redis-sentinel sentinel.conf
方式二: redis-server sentinel.conf --sentinel
#4、将master的redis服务终止,查看从是否会提升为主
sudo /etc/init.d/redis-server stop
# 发现提升6381为master,其他两个为从
# 在6381上设置新值,6380查看
127.0.0.1:6381> set name tedu
OK
# 启动6379,观察日志,发现变为了6381的从
主从+哨兵基本就够用了
sentinel.conf解释
# sentinel监听端口,默认是26379,可以修改
port 26379
# 告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效
sentinel monitor <master-name> <ip> <redis-port> <quorum>
#如果master有密码,则需要添加该配置
sentinel auth-pass <master-name> <password>
#master多久失联才认为是不可用了,默认是30秒
sentinel down-after-milliseconds <master-name> <milliseconds>
python获取master
很少使用
from redis.sentinel import Sentinel
#生成哨兵连接
sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1)
#初始化master连接
master = sentinel.master_for('tedu', socket_timeout=0.1, db=1)
slave = sentinel.slave_for('tedu',socket_timeout=0.1, db=1)
#使用redis相关命令
master.set('mymaster', 'yes')
print(slave.get('mymaster'))