Day25:内存式NoSQL数据库Redis
Posted 保护胖仔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day25:内存式NoSQL数据库Redis相关的知识,希望对你有一定的参考价值。
- 知识点01:回顾
- 知识点02:目标
- 知识点03:Redis持久化:数据存储设计
- 知识点04:Redis持久化:RDB设计
- 知识点05:Redis持久化:RDB测试
- 知识点06:Redis持久化:AOF设计
- 知识点07:Redis持久化:AOF实现
- 知识点08:Redis的事务机制
- 知识点09:Redis实现消息队列
- 知识点10:Redis过期策略与内存淘汰机制
- 知识点11:Redis架构:问题与主从复制集群设计
- 知识点12:Redis架构:主从复制集群的实现
- 知识点13:Redis架构:主从复制同步与配置
- 知识点14:Redis架构:哨兵集群的设计
- 知识点15:Redis架构:哨兵集群的实现
- 知识点16:Redis架构:分片集群的设计
- 知识点17:Redis架构:分片集群的实现
- 知识点18:Redis常见面试题
知识点01:回顾
-
RDBMS与NoSQL的特点分别是什么?
- RDBMS:事务特性,稳定性和数据安全性,小数据量性能较好
- NoSQL:高并发、高性能
-
Redis的功能与应用场景是什么?
- 功能:提供高性能和高并发的数据存储
- 应用
- 数据库:提供高性能的读写
- 缓存:解决高并发问题
- 消息队列:实现高性能和高并发的数据传递,一般不用
- 特点
- 基于C语言开发,底层兼容性更好
- 基于内存的数据存储
- 分布式
- 支持多种数据类型
-
Redis中的数据是什么结构?Value的常用类型有哪几种?
- 数据结构:KV结构
- 数据类型
- K:String
- V:String、Hash、List、Set、Zset、BitMap、HyperLogLog
-
每种类型的常用命令有哪些?
- String:set、get、mset、mget、strlen、setnx
- Hash:hset、hget、hgetall、hdel
- List:lpush/rpush、lrange、lpop/rpop、llen
- Set:sadd、srem、smembers、scard
- Zset:zadd、zrange、zrevrange、zrem、zcard
-
Jedis中有哪些类和方法?
- 类
- Jedis:客户端连接对象
- JedisPool:连接池对象
- getResource:获取连接对象
- JedisPoolConfig:连接池配置对象
- 方法:所有操作都对应命令名称同名的方法
- 类
知识点02:目标
- 如何保证Redis的数据安全?
- 内存中的数据如何保证不丢失?
- 默认机制:RDB
- 可选机制:AOF
- Redis中的理论点
- Redis事务:单线程
- Redis实现消息队列
- 数据过期策略和内存淘汰机制
- expire
- setex
- Redis集群架构:分布式:实现即可
- 主从复制
- 哨兵集群
- 分片集群
- 常见一些面试题
- 缓存雪崩
- 缓存穿透
- 缓存击穿
- 为什么Redis是单线程还很快?
知识点03:Redis持久化:数据存储设计
-
目标:掌握常见数据存储的设计
-
实施
- 问题
- 数据存储如何保证数据安全?
- 解决
- 磁盘存储:数据直接存储在硬盘上
- 特点:容量大、安全性高、读写速度上相对不如内存
- 软件备份:在软件层次备份多份
- HDFS数据存储:每个文件实际存储了3份
- Hadoop3.0开始:HDFS通过纠错码来实现安全机制
- 硬件备份:磁盘冗余阵列:RAID
- RAID0:两块硬盘,每块1TB,操作系统中只能看到1块硬盘,2TB
- RAID1:两块硬盘,每块1TB,操作系统中只能看到1块硬盘,1TB
- 内存存储:数据直接放在内存中
- 特点:容量小、安全性低、读写性能高
- 内存备份:解决内存数据容易丢失的问题
- 持久化方案:persist
- 将内存的数据同步到磁盘
- 常见实现:只追加记录变化:日志记录方式
- HDFS的NameNode管理元数据:edits
- mysql:binlog
- 磁盘存储:数据直接存储在硬盘上
- 问题
-
小结
- 掌握常见数据存储的设计
知识点04:Redis持久化:RDB设计
-
目标:掌握Redis的RDB持久化机制
-
路径
- step1:问题
- step2:RDB方案
- step3:优缺点
-
实施
-
问题
Redis中的数据都存储在内存中,由内存对外提供读写,Redis一旦断电重启,内存中的数据就会丢失,Redis如何实现持久化?
-
RDB方案
-
Redis**默认的持久化方案**
-
思想
- 按照一定的时间内,如果Redis内存中的数据产生了一定次数的更新,就将整个Redis内存中的所有数据拍摄一个快照文件存储在硬盘上
- 新的快照会覆盖老的快照文件,快照是全量快照,包含了内存中所有的内容,基本与内存一致
- 如果Redis故障重启,从硬盘的快照文件进行恢复
-
举例
- 配置:save 30 2
- 解释:如果30s内,redis内存中的数据发生了2条更新,就将整个Redis内存数据保存到磁盘文件中,作为快照
-
过程
-
触发
-
手动触发:当执行某些命令时,会自动拍摄快照【一般不用】
- save:手动触发拍摄RDB快照的,将内存的所有数据拍摄最新的快照
- 前端运行
- 阻塞所有的客户端请求,等待快照拍摄完成后,再继续处理客户端请求
- 特点:快照与内存是一致的,数据不会丢失,用户的请求会被阻塞
- save:手动触发拍摄RDB快照的,将内存的所有数据拍摄最新的快照
-
bgsave:手动触发拍摄RDB快照的,将内存的所有数据拍摄最新的快照
- 后台运行
- 主进程会fork一个子进程负责拍摄快照,客户端可以正常请求,不会被阻塞
- 特点:用户请求继续执行,用户的新增的更新数据不在快照中
-
shutdown:执行关闭服务端命令
- flushall:清空,没有意义
-
自动触发:按照一定的时间内发生的更新的次数,拍摄快照
- 配置文件中有对应的配置,决定什么时候做快照
#Redis可以设置多组rdb条件,默认设置了三组,这三组共同交叉作用,满足任何一个都会拍摄快照 save 900 1 save 300 10 save 60 10000
- 为什么默认设置3组?
- 原因:如果只有一组策略,面向不同的写的场景,会导致数据丢失
- 针对不同读写速度,设置不同策略,进行交叉保存快照,满足各种情况下数据的保存策略
-
-
-
优缺点
-
优点
- rdb方式实现的是全量快照,快照文件中的数据与内存中的数据是一致的
- 快照是二进制文件,生成快照加载快照都比较快,体积更小
- Fork进程实现,性能更好
- 总结:更快、更小、性能更好
-
缺点
-
存在一定概率导致部分数据丢失
-
应用:希望有一个高性能的读写,不影响业务,允许一部分的数据存在一定概率的丢失,大规模的数据备份和恢复
-
-
-
小结
- 什么是RDB机制,优缺点分别是什么?
- 思想:在一定时间内如果发生一定次数的更新,就拍摄全量快照记录在磁盘上
- 优点:更快、更小、性能更好
- 缺点:有一定的概率存在数据丢失的情况
- 应用:大量数据的备份和恢复
- 什么是RDB机制,优缺点分别是什么?
知识点05:Redis持久化:RDB测试
-
目标:实现RDB持久化的测试
-
实施
-
查看当前快照
ll /export/server/redis/datas/
-
-
配置修改
cd /export/server/redis vim redis.conf #202行 save 900 1 save 300 10 save 60 10000 save 20 2
-
重启redis服务,配置才会生效
ps -ef | grep redis kill -9 pid redis-start.sh
-
插入数据
set s1 "laoda" set s2 "laoliu"
-
查看dump的rdb快照
ll /export/server/redis/datas/
-
小结
- 实现RDB持久化的测试
知识点06:Redis持久化:AOF设计
-
目标:掌握Redis的AOF持久化机制
-
路径
- step1:问题
- step2:AOF方案
- step3:优缺点
- step4:持久化方案
-
实施
-
问题
RDB存在一定概率的数据丢失,如何解决?
-
AOF方案
-
思想
- 按照一定的规则,将内存数据的操作日志追加写入一个文件中
- 当Redis发生故障,重启,从文件中进行读取所有的操作
- 重新对Redis进行执行,用于恢复内存中的数据
-
过程
-
实现
- appendfsync always
- 每更新一条数据就同步将这个更新操作追加到文件中
- 优点:数据会相对安全,几乎不会出现数据丢失的情况
- 缺点:频繁的进行数据的追加,增大磁盘的IO,导致性能较差
- appendfsync everysec
- 每秒将一秒内Redis内存中数据的操作异步追加写入文件
- 优点:在安全性和性能之间做了权衡,性能要比always高
- 缺点:有数据丢失风险 ,但最多丢失1秒
- appendfsync no
- 交给操作系统来做,不由Redis控制
- appendfsync always
-
-
优缺点
-
优点:安全性和性能做了折中方案,如果性能要求不高,安全性可以达到最高
-
缺点
-
这个文件是普通文本文件,相比于二进制文件来说,每次追加和加载比较慢
-
数据的变化以追加的方式写入AOF文件
- 问题:文件会不断变大,文件中会包含不必要的操作【过期的数据】
-
-
解决:模拟类似于RDB做全量的方式,定期生成一次全量的AOF文件
-
应用:数据持久化安全方案
-
-
持久化方案
-
两种方案怎么选?
- 两种方案可以共存
- 问题:既有RDB全量快照又有AOF操作日志,下次Redis重启读谁?
- 解决:AOF优先级高于RDB
-
-
-
小结
- 什么是AOF机制?
- 按照一定规则将Redis内存的变化操作日志追加写入文件
- 下次重启Redis,从操作日志中解析恢复数据
- 什么是AOF机制?
知识点07:Redis持久化:AOF实现
-
目标:实现AOF持久化
-
实施
-
开启并配置
vim redis.conf #594行:开启aof appendonly yes #624行:默认每s刷写一次 appendfsync everysec #665,666 #增幅100%就重新覆盖一次 auto-aof-rewrite-percentage 100 #文件至少要大于64MB,一般建议更改为GB大小 auto-aof-rewrite-min-size 64mb
-
重启Redis
ps -ef | grep redis kill -9 pid redis-start.sh
-
查看数据
keys *
-
- 从AOF文件恢复数据
-
查看aof文件
ll /export/server/redis/datas
-
小结
- 实现AOF持久化
知识点08:Redis的事务机制
-
目标:了解Redis的事务机制
-
实施
-
事务定义:事务是数据库操作的最小工作单元,包含原子性、一致性、隔离性、持久性
-
Redis事务:Redis一般不用事务
- Redis本身是单线程的,所以本身没有事务等概念
- Redis 支持事务的本质是一组命令的集合,事务支持一次执行多个命令,串行执行每个命令
- 一旦Redis开启了事务,将所有命令放入一个队列中,提交事务时,对整个队列中的命令进行执行
- redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
- 没有隔离性:批量的事务命令执行前在缓存队列中,没有事务交叉,不存在脏读幻读等问题
- 不能保证原子性:单条命令是原子性执行的,但事务不保证原子性,且没有回滚机制,事务中任意命令执行失败,其余的命令仍会被执行。
-
过程
- 开启事务
- 提交命令
- 执行事务
-
命令
- multi:开启事务
- exec:执行事务
- discard:取消事务
- watch:监听机制,类似于乐观锁
- unwatch:取消监听
-
测试1:正常使用
set user1 hadoop1 set user2 hadoop2 get user1 get user2 multi set user1 hadoop3 set user2 hadoop4 exec get user1 get user2
-
测试2:语法【编译】错误
flushdb set user1 hadoop1 set user2 hadoop2 get user1 get user2 multi set user1 hadoop3 sets user2 hadoop4 exec get user1 get user2
-
测试3:类型【运行】错误
flushdb set user1 hadoop1 set user2 hadoop2 get user1 get user2 multi set user1 hadoop3 lpush user2 hadoop4 exec get user1 get user2
-
测试4:取消事务
flushdb set user1 hadoop1 set user2 hadoop2 get user1 get user2 multi set user1 hadoop3 set user2 hadoop4 discard get user1 get user2
-
测试5:监听
flushdb watch user2 set user1 hadoop1 set user2 hadoop2 get user1 get user2 multi set user1 hadoop3 lpush user2 hadoop4 exec get user1 get user2
-
测试6:取消监听
flushdb watch user2 set user1 hadoop1 set user2 hadoop2 get user1 get user2 unwatch multi set user1 hadoop3 lpush user2 hadoop4 exec get user1 get user2
-
-
小结
- 了解Redis的事务机制
知识点09:Redis实现消息队列
-
目标:了解Redis如何实现消息队列
-
实施
- 消息队列是什么?
- 问题
- A的并发高,B的并发量低,导致B无法接受所有数据,会有数据丢失
- A的数据只给了B,如果C也要A的数据,必须重修修改代码,让A给C再发一份
- 解决:引入消息队列
-
Redis如何实现消息队列?
-
命令
- PUBLISH:广播生产消息
- subscribe:订阅消息
- unsubscribe:取消订阅
-
测试
-
启动多个客户端,先订阅后发布
-
客户端1
PUBLISH "cctv.5" "this is China"
-
客户端2
SUBSCRIBE "cctv.5"
-
客户端3
SUBSCRIBE "cctv.5"
-
-
-
小结
- 了解Redis如何实现消息队列
知识点10:Redis过期策略与内存淘汰机制
-
目标:了解Redis的过期策略与内存淘汰机制
-
路径
- step1:内存问题
- step2:过期策略
- step3:淘汰机制
-
实施
-
内存问题
Redis使用的是内存,内存如果满了,怎么解决?
-
过期策略
-
设计思想:避免内存满,指定Key的存活时间,到达存活时间以后自动删除
- 命令:expire/setex
-
定时过期:指定Key的存活时间,一直监听这个存活时间,一旦达到存活时间,自动删除
- 需要CPU一直做监听,如果Key比较多,CPU的消耗比较严重
-
惰性过期:指定Key的存活时间,当使用这个Key的时候,判断是否过期,如果过期就删除
- 如果某个Key设置了过期时间,但是一直没有使用,不会被发现过期了,就会导致资源浪费
-
定期过期:每隔一段时间就检查数据是否过期,如果过期就进行删除
- 中和的策略机制
-
Redis中使用了惰性过期和定期过期两种策略公共作用
-
-
淘汰机制
-
设计思想:内存满了,怎么淘汰
-
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据, Redis 源码中的默认配置
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory # is reached. You can select among five behaviors: #最大内存策略:当到达最大使用内存时,你可以在下面5种行为中选择,Redis如何选择淘汰数据库键 #当内存不足以容纳新写入数据时 # volatile-lru -> remove the key with an expire set using an LRU algorithm # volatile-lru :在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把 redis 既当缓存,又做持久化存储的时候才用。 # allkeys-lru -> remove any key according to the LRU algorithm # allkeys-lru : 移除最近最少使用的key (推荐) # volatile-random -> remove a random key with an expire set # volatile-random : 在设置了过期时间的键空间中,随机移除一个键,不推荐 # allkeys-random -> remove a random key, any key # allkeys-random : 直接在键空间中随机移除一个键,弄啥叻 # volatile-ttl -> remove the key with the nearest expire time (minor TTL) # volatile-ttl : 在设置了过期时间的键空间中,有更早过期时间的key优先移除 不推荐 # noeviction -> don't expire at all, just return an error on write operations # noeviction : 不做过键处理,只返回一个写操作错误。 不推荐 # Note: with any of the above policies, Redis will return an error on write # operations, when there are no suitable keys for eviction. # 上面所有的策略下,在没有合适的淘汰删除的键时,执行写操作时,Redis 会返回一个错误。下面是写入命令: # At the date of writing these commands are: set setnx setex append # incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby # zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby # getset mset msetnx exec sort # 过期策略默认是: # The default is: # maxmemory-policy noeviction
-
实际项目中设置内存淘汰策略:maxmemory-policy allkeys-lru,移除最近最少使用的key。
-
-
-
小结
- 了解Redis的过期策略与内存淘汰机制
知识点11:Redis架构:问题与主从复制集群设计
-
目标:掌握Redis架构中的问题及主从复制集群的设计
-
路径
- step1:架构问题
- step2:主从复制集群设计
-
实施
-
架构问题
- Redis的服务只有单台机器
- 问题1:单点故障问题,如果Redis服务故障,整个Redis服务将不可用
- 问题2:单台机器的内存比较小,数据存储的容量不足,会导致redis无法满足需求
-
主从复制集群设计
- 架构
-
- **设计**
- 分布式主从架构
- Master:主节点
- 负责对外提供数据的读写
- Slave:从节点
- 负责对外提供读的请求
- 负责与主节点同步数据
- 特点:主从节点上的数据都是一致的,连接任何一个节点实现读,==写操作只能连接主节点==
- **优缺点**
- 优点:实现了读写分离,分摊了读写的压力负载,如果一台Redis故障,其他的Redis服务节点照常对外提供服务
- 缺点:如果Master故障,整个集群不能对外提供写的操作,==Master没有HA机制==
-
小结
- 掌握Redis架构中的问题及主从复制集群的设计
知识点12:Redis架构:主从复制集群的实现
-
目标:实现Redis主从复制集群的搭建测试
-
实施
-
配置三台Redis
-
复制到第二台和第三台
cd /export/server/ scp -r redis-3.2.8-bin node2:$PWD scp -r redis-3.2.8-bin node3:$PWD
-
配置node2和node3
-
创建链接
cd /export/server/ ln -s redis-3.2.8-bin redis
-
配置环境变量
vim /etc/profile
# REDIS HOME export REDIS_HOME=/export/server/redis export PATH=:$PATH:$REDIS_HOME/bin
source /etc/profile
-
修改配置文件
cd /export/server/redis vim redis.conf
-
node2
#61行 bind node2 #266行 slaveof node1 6379
-
node3
#61行 bind node3 #266行 slaveof node1 6379
-
-
三台机器都执行
cd /export/server/redis rm -rf ./datas/* ./logs/*
-
-
启动测试
-
依次启动三台Redis
redis-start.sh
-
连接服务端
redis-cli -h node1 info replication
-
读写测试
-
主节点
-
从
-
-
-
-
小结
- 实现Redis主从复制集群的搭建测试
知识点13:Redis架构:主从复制同步与配置
-
目标:了解主从复制的同步策略及配置
-
路径
- step1:同步策略
- step2:常见配置
-
实施
-
同步策略
- 全量同步
- 新的Slave节点添加到集群中或者Slave与Master断开很长时间,超出了数据积压缓冲大小
- Master会通过bgsave构建一份完整的内存快照,发送给Slave,Slave加载快照的数据
- Master也会维护一个缓存队列,将快照中没有的数据,放在缓存队列中,Slave会同步缓存中的数据
- 全量同步比较消耗性能
- 增量同步
- Master会将当前Slave没有同步的数据放在积压缓存区中
- Slave请求同步数据时,Master如果判断同步的数据在积压缓冲区中进行进行返回同步
- 全量同步
-
常见配置
################################# REPLICATION ################################# # 复制选项,slave复制对应的master。 slaveof <masterip> <masterport> # 如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。 # masterauth就是用来配置master的密码,这样可以在连上master后进行认证。 # masterauth <master-password> # 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式: # 1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求。 # 2) 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之外的任何请求都会返回一个错误”SYNC with master in progress”。 slave-serve-stale-data yes # 作为从服务器,默认情况下是只读的(yes) slave-read-only yes # 是否使用socket方式复制数据。 # 目前redis复制提供两种方式,disk和socket。 # 如果新的slave连上来或者重连的slave无法部分同步,就会执行全量同步,master会生成rdb文件。 # 有2种方式: # 1.disk方式是master创建一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。 # 2.socket是master创建一个新的进程,直接把rdb文件以socket的方式发给slave。 # disk方式的时候,当一个rdb保存的过程中,多个slave都能共享这个rdb文件。 # socket的方式就的一个个slave顺序复制。 # 在磁盘速度缓慢,网速快的情况下推荐用socket方式。 repl-diskless-sync no # diskless复制的延迟时间,防止设置为0。 # 一旦复制开始,节点不会再接收新slave的复制请求直到下一个rdb传输。 # 所以最好等待一段时间,等更多的slave连上来。 repl-diskless-sync-delay 5 # slave根据指定的时间间隔向服务器发送ping请求。 # 时间间隔可以通过 repl_ping_slave_period 来设置,默认10秒。 # repl-ping-slave-period 10 # 复制连接超时时间。 # master和slave都有超时时间的设置。 # master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。 # slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。 # 需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时。 # repl-timeout 60 # 是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。 # 默认是no,即使用tcp nodelay。 # 如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。 # 但是这也可能带来数据的延迟。 # 默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes。 repl-disable-tcp-nodelay no # 复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。 # 这样在slave离线的时候,不需要完全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。 # 缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。 # 没有slave的一段时间,内存会被释放出来,默认1m。 # repl-backlog-size 5mb # master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。 # 单位为秒。 # repl-backlog-ttl 3600 # 当master不可用,Sentinel会根据slave的优先级选举一个master。 # 最低的优先级的slave,当选master。 # 而配置成0,永远不会被选举。 # 注意:要实现Sentinel自动选举,至少需要2台slave。 slave-priority 100 # redis提供了可以让master停止写入的方式,如果配置了min-slaves-to-write,健康的slave的个数小于N,mater就禁止写入。 # master最少得有多少个健康的slave存活才能执行写命令。 # 这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。 # 设置为0是关闭该功能,默认也是0。 # min-slaves-to-write 3 # 延迟小于min-slaves-max-lag秒的slave才认为是健康的slave。 # min-slaves-max-lag 10
-
-
小结
- 了解主从复制的同步策略及配置
知识点14:Redis架构:哨兵集群的设计
-
目标:掌握哨兵集群的设计
-
路径
- step1:问题
- step2:哨兵设计
-
实施
-
问题
主从复制集群的Master存在单点故障问题,怎么解决?
- 类似于ZK的设计
- 每台节点存储的数据都是一样的
- 如果Leader故障,允许Follower选举成为Leader
- 类似于ZK的设计
-
哨兵设计
-
思想:基于主从复制模式之上封装了哨兵模式,如果Master出现故障,让Slave选举成为新的Master
-
实现:哨兵进程实现
- 必须能发现Master的故障
- 必须负责重新选举新的Master
-
架构
-
-
- Redis主从架构
- 哨兵进程
- 每个哨兵负责监听所有Redis节点和其他哨兵
- 为什么要监听所有Redis的节点:发现所有节点是否会出现故障
- 如果Master出现故障,会进行投票选择一个Slave来成为新的Master
- 为什么要监听别的哨兵:如果哨兵故障,不能让这个哨兵参与投票选举等
- 哨兵功能
- 集群监控:监控节点状态
- 消息通知:汇报节点状态
- 故障转移:实现Master重新选举
- 配置中心:实现配置同步
- **流程**
- step1:如果Master突然故障,有一个哨兵会发现这个问题,这个哨兵会立即通告给所有哨兵
- 主观性故障【sdown】
- step2:当有一定的个数的哨兵都通告Master故障了,整体认为Master故障了
- 客观性故障【odown】
- step3:所有哨兵根据每台Slave通信的健康状况以及Slave权重选举一个新的Master
- step4:将其他所有的Slave的配置文件中的Master切换为当前最新的Master
-
小结
- 掌握哨兵集群的设计
知识点15:Redis架构:哨兵集群的实现
-
目标:实现哨兵模式的搭建测试
-
实施
-
配置哨兵服务
-
第一台机器复制哨兵配置文件:sentinel.conf
cp /export/server/redis-3.2.8/sentinel.conf /export/server/redis/
-
修改配置文件
vim sentinel.conf
#18行 bind 0.0.0.0 protected-mode no daemonize yes logfile "/export/server/redis-3.2.8-bin/logs/sentinel.log" #73行 sentinel monitor mymaster node1 6379 2
-
分发给第二台和第三台
cd /export/server/redis scp -r sentinel.conf root@node2:$PWD scp -r sentinel.conf root@node3:$PWD
-
-
启动
-
启动三台Redis服务
redis-start.sh
-
启动三台哨兵服务
redis-sentinel /export/server/redis/sentinel.conf
-
-
测试
-
连接Redis
redis-cli -h node1
-
-
- 连接哨兵
```
redis-cli -h node3 -p 26379
info sentinel
```
-
Jedis中哨兵的连接
//方案三:构建哨兵连接池:第一个参数是master的逻辑名称,第二个参数是哨兵列表,第三个是连接池的配置 HashSet<String> sets = new HashSet<>(); sets.add("node1:26379"); sets.add("node2:26379"); sets.add("node3:26379"); JedisSentinelPool mymaster = new JedisSentinelPool("mymaster", sets, jedisPoolConfig); //从连接池中获取连接 jedis = mymaster.getResource();
-
小结
- 实现哨兵模式的搭建测试
知识点16:Redis架构:分片集群的设计
-
目标:掌握分片集群的设计
-
路径
- step1:问题
- step2:分片集群设计
-
实施
-
问题
Redis哨兵集群中的存储容量只有单台机器,如何解决大量数据使用Redis存储问题?
-
分片集群设计
-
分片集群模式
-
思想:将多个Redis小集群从逻辑上合并为一个大集群,每个小集群分摊一部分槽位,对每一条Redis的数据进行槽位计算,这条数据属于哪个槽位,就存储对应槽位的小集群中
- 分片的规则:根据Key进行运算:CRC16【K】 & 16383 = 0 ~ 16383
-
-
- 架构
-
小结
- 掌握分片集群的设计
知识点17:Redis架构:分片集群的实现
-
目标:实现分片集群的搭建
-
实施
-
关闭所有机器的redis服务与哨兵服务
redis-cli -h node1 -p 6379 SHUTDOWN redis-cli -h node2 -p 6379 SHUTDOWN redis-cli -h node3 -p 6379 SHUTDOWN redis-cli -h node1 -p 26379 SHUTDOWN redis-cli -h node2 -p 26379 SHUTDOWN redis-cli -h node3 -p 26379 SHUTDOWN
-
删除三台机器的软连接
rm -rf /export/server/redis
-
三台机器都保证有C语言环境
yum -y install gcc-c++ tcl
-
-
上传redis5到第一台机器
cd /export/software/ rz
-
解压编译安装
tar -zxf redis-5.0.8.tar.gz -C /export/server/ cd /export/server/redis-5.0.8 # 编译 make # 安装至指定目录 make PREFIX=/export/server/redis-5.0.8-bin install
-
创建软连接
cd /export/server ln -s redis-5.0.8-bin redis
-
拷贝配置文件
cp /export/server/redis-5.0.8/redis.conf /export/server/redis
-
创建两个服务目录
# 创建目录:7001和7002 cd /export/server/redis mkdir -p 7001 7002
-
配置7001
cd /export/server/redis cp redis.conf 7001/redis_7001.conf
vim 7001/redis_7001.conf
#69行 bind 0.0.0.0 #88行 protected-mode no #92行 port 7001 #136行 daemonize yes #158行 pidfile /var/run/redis_7001.pid #171行 logfile "/export/server/redis-5.0.8-bin/7001/logs/redis.log" #263行 dir /export/server/redis-5.0.8-bin/7001/datas/ #293行 masterauth 123456 #507行 requirepass 123456 #699行 appendonly yes #832行 cluster-enabled yes #840行 cluster-config-file nodes-7001.conf #846行 cluster-node-timeout 15000
mkdir -p /export/server/redis/7001/logs mkdir -p /export/server/redis/7001/datas
-
配置7002
-
拷贝
cd /export/server/redis cp 7001/redis_7001.conf 7002/redis_7002.conf
-
替换
所有7001换成7002
-
创建目录
mkdir -p /export/server/redis/7002/logs mkdir -p /export/server/redis/7002/datas
-
-
发送给node2和node3
cd /export/server scp -r redis-5.0.8-bin root@node2:$PWD scp -r redis-5.0.8-bin root@node3:$PWD
-
创建软连接
cd /export/server ln -s redis-5.0.8-bin redis
-
启动服务
-
三台机器启动所有redis进程
redis-server /export/server/redis/7001/redis_7001.conf redis-server /export/server/redis/7002/redis_7002.conf
-
- 初始化配置集群
```
redis-cli -a 123456 --cluster create \\
192.168.88.130:7001 192.168.88.130:7002 \\
192.168.88.131:7001 192.168.88.131:7002 \\
192.168.88.132:7001 192.168.88.132:7002 \\
--cluster-replicas 1
```
- --cluster-replicas :每个小的集群有几个副本,不包含master
- 结果
```
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.88.131:7002 to 192.168.88.130:7001
Adding replica 192.168.88.132:7002 to 192.168.88.131:7001
Adding replica 192.168.88.130:7002 to 192.168.88.132:7001
M: 2564bea6bdc5a367ae8098f5674957a69a929659 192.168.88.130:7001
slots:[0-5460] (5461 slots) master
S: a20f85e538e538ca97d1bf052d55719409648854 192.168.88.130:7002
replicates de952c29bda3a33321d9e5ab756975a5c3cf015a
M: 9db82f4d39d40b0c486e7d0f319bc2a5fb82cac7 192.168.88.131:7001
slots:[5461-10922] (5462 slots) master
S: b20bb439d99d4fb0e861578ef3ca45d4d29f6afd 192.168.88.131:7002
replicates 2564bea6bdc5a367ae8098f5674957a69a929659
M: de952c29bda3a33321d9e5ab756975a5c3cf015a 192.168.88.132:7001
slots:[10923-16383] (5461 slots) master
S: 25839625c79a49274875b5b28887d4e3e4a775fd 192.168.88.132:7002
replicates 9db82f4d39d40b0c486e7d0f319bc2a5fb82cac7
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 192.168.88.130:7001)
M: 2564bea6bdc5a367ae8098f5674957a69a929659 192.168.88.130:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 9db82f4d39d40b0c486e7d0f319bc2a5fb82cac7 192.168.88.131:7001
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: de952c29bda3a33321d9e5ab756975a5c3cf015a 192.168.88.132:7001
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: b20bb439d99d4fb0e861578ef3ca45d4d29f6afd 192.168.88.131:7002
slots: (0 slots) slave
replicates 2564bea6bdc5a367ae8098f5674957a69a929659
S: 25839625c79a49274875b5b28887d4e3e4a775fd 192.168.88.132:7002
slots: (0 slots) slave
replicates 9db82f4d39d40b0c486e7d0f319bc2a5fb82cac7
S: a20f85e538e538ca97d1bf052d55719409648854 192.168.88.130:7002
slots: (0 slots) slave
replicates de952c29bda3a33321d9e5ab756975a5c3cf015a
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
```
-
连接集群
redis-cli -c -h node1 -p 7001 -a 123456
-
测试:cluster nodes
- 其他操作
-
启动脚本
cd /export/server/redis vim bin/redis-cluster-start.sh
#!/bin/bash REDIS_HOME=/export/server/redis # Start Server ## node1 ssh node1 "$REDIS_HOME/bin/redis-server /export/server/redis/7001/redis_7001.conf" ssh node1 "$REDIS_HOME/bin/redis-server /export/server/redis/7002/redis_7002.conf" ## node2 ssh node2 "$REDIS_HOME/bin/redis-server /export/server/redis/7001/redis_7001.conf" ssh node2 "$REDIS_HOME/bin/redis-server /export/server/redis/7002/redis_7002.conf" ## node3 ssh node3 "$REDIS_HOME/bin/redis-server /export/server/redis/7001/redis_7001.conf" ssh node3 "$REDIS_HOME/bin/redis-server /export/server/redis/7002/redis_7002.conf"
chmod u+x bin/redis-cluster-start.sh
-
关闭脚本
vim bin/redis-cluster-stop.sh
#!/bin/bash REDIS_HOME=/export/server/redis # Stop Server ## node1 $REDIS_HOME/bin/redis-cli -h node1 -p 7001 -a 123456 SHUTDOWN $REDIS_HOME/bin/redis-cli -h node1 -p 7002 -a 123456 SHUTDOWN ## node2 $REDIS_HOME/bin/redis-cli -h node2 -p 7001 -a 123456 SHUTDOWN $REDIS_HOME/bin/redis-cli -h node2 -p 7002 -a 123456 SHUTDOWN ## node3 $REDIS_HOME/bin/redis-cli -h node3 -p 7001 -a 123456 SHUTDOWN $REDIS_HOME/bin/redis-cli -h node3 -p 7002 -a 123456 SHUTDOWN
chmod u+x bin/redis-cluster-stop.sh
-
Jedis中连接
- 注意
- 单节点模式/哨兵模式:Jedis
- set/get
- 分片集群模式:JedisCluster
- set/get
@Before public void getJedisCluster() //构建连接池的配置对象 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(30);//总连接数 jedisPoolConfig.setMaxIdle(20);//最大空闲连接 jedisPoolConfig.setMaxWaitMillis(1500);//等待时间 //构建集群模式的额连接池 HashSet<HostAndPort> sets = new HashSet<HostAndPort>(); sets.add(new HostAndPort("node1",7001)); sets.add(new HostAndPort("node1",7002)); sets.add(new HostAndPort("node2",7001)); sets.add(new HostAndPort("node2",7002)); sets.add(new HostAndPort("node3",7001)); sets.add(new HostAndPort("node3",7002)); jedisCluster = new JedisCluster(sets,2000,2000,5,"123456",jedisPoolConfig);
-
小结
- 实现分片集群的搭建
知识点18:Redis常见面试题
- 分片集群问题
-
常见面试题
-
什么是缓存穿透,怎么解决?
-
现象:客户端高并发不断向Redis请求一个不存在的Key,MySQL中也没有
- 由于Redis没有,导致这个并发全部落在MySQL上
-
解决
-
step1:对于那些每秒访问频次过高的IP进行限制,拒绝访问
-
step2:如果第一次redis中没有,读MYSQL,MySQL也没有,在Redis中设置一个临时默认值
-
step3:利用BitMap类型构建布隆过滤器
- MySQL
- 1 hadoop
- 2 hive
- 3 hive
- 4 spark
- 5 hue
- 10 oozie
111110000100000000000000000000000000000000000000000000000000
-
如果用户请求一个Key,对Key进行计算取余一个数字:10
-
将MySQL中如果存在的数据都设置为1
-
如果用户请求1:MySQL中有,可以请求
-
如果用户请求8:MySQL中没有这个值,不可以请求MySQL
- MySQL
-
-
-
什
以上是关于Day25:内存式NoSQL数据库Redis的主要内容,如果未能解决你的问题,请参考以下文章
-