Redis 多机
【摘要】 Redis 多机集群当数据量过大时,单个 Redis 数据库就无法存放。我们需要多个 Redis 数据库组成集群(cluster),去分别存放不同的数据。key-value 数据进行存入时,会根据 key 的哈希值对 16384 取模,放入相应的槽(slot)存放。这 16384 个槽会分发给各个存储空间。各个存储空间之间会相互通信,并记录所有编号的槽都存储在哪个存储空间:保证最多访问 Re...
Redis 多机
集群
当数据量过大时,单个 Redis 数据库就无法存放。我们需要多个 Redis 数据库组成集群(cluster),去分别存放不同的数据。
-
key-value 数据进行存入时,会根据 key 的哈希值对 16384 取模,放入相应的槽(slot)存放。这 16384 个槽会分发给各个存储空间。
-
各个存储空间之间会相互通信,并记录所有编号的槽都存储在哪个存储空间:保证最多访问 Redis 两次可以命中。
配置文件
cluster enabled yes # 开启集群
cluster-config-file nodes-6379.conf # 集群配置文件(默认为 nodes.conf)Copy to clipboardErrorCopied
集群指令
-
通过
redis-cli
打开 Redis 集群中的数据库,输入指令去插入不属于这个存储空间的键值,会返回错误。 -
通过
redis-cli -c
打开 Redis 集群中的数据库,会自动将插入数据指令转发到相应的存储空间。
主从复制
如果数据只交给一个 Redis 服务器处理,那么可能面临两大问题:
- 服务器同时处理过多读写操作,超过服务器负载。
- 一旦服务器宕机,就会导致服务异常中断。
为了避免这两个问题,我们必须引入多个 Redis 服务器来保存相同数据,并采用主从复制结构:一个主服务器 Master 对应多个从服务器 Slave 。
- 读写分离:Master 负责写入数据;Slave 则会自动同步数据,并负责读取数据。起到均衡负载的作用。
- 数据冗余:即使某个 Slave 故障,由于其他 Slave 已保存了这些数据,并不会导致服务中断。
容错机制
-
主从之间使用心跳建立连接。 Slave 每秒 ping 一次,汇报自己的偏移量、获取最新的指令。Master 默认每 10s ping 一次 Slave, 检查 slave 是否在线:如果 Slave 多数掉线或者高延迟,Master 停止写和数据同步功能,保障数据稳定性。
-
在分布式系统里还会部署多个 Redis 服务器作为哨兵(除端口号外完全相同),不提供数据服务,只负责监控主从机制的运行:如果发现 Master 宕机,哨兵将通知所有机器,使 Master 下线并开启投票机制选用一个 Slave 担任 Master 。
配置连接
Master 和 Slave 通过以下过程建立连接。
相比于输入指令,我们一般直接修改 conf 文件夹内的配置文件,由机器自动建立连接。
# Master
requirepass 123456 # 连接主服务器需要密码(可选)
# Slave
slaveof 127.0.0.1 6379 # 根据套接字自动连接主服务器
masterauth 123456 # 主服务器密码Copy to clipboardErrorCopied
数据同步
Slave 会定期复制 Master 的持久化文件,以保证数据同步。
复制缓冲区:一个先入先出队列,用来存储 AOF 形式指令。由偏移量记录当前执行到的位置。
- 如果开启 AOF ,在创建时就会开启复制缓冲区。(偏移量记录自己执行到的位置)
- 如果使用 RDB ,在成为 Master 时会开启复制缓冲区。(Master 可以含有多个偏移量,记录不同 Slave 读取到的位置。)
如果 Slave 过多,数据同步也会导致 Master 负载过高。因此 Slave 也可以兼职 Master,向下级 Slave 提供服务。但层次太多会导致数据延迟,慎用。
- 数据同步阶段应避免流量高峰期,防止影响业务正常执行;也不要多个从服务器同时同步数据。
- 缓冲区应该足够大,否则一旦发生数据溢出会反复进行全量复制。
# Master
repl-backlog-size 2mb # 修改缓冲区大小(默认 1mb)
# Slave
slave-serve-stale-data no # 不允许同步数据时读数据Copy to clipboardErrorCopied
命令传播
服务器每次启动都会随机生成一个运行 ID(40 位 16 进制字符) ,Master 和 Slave 之间正是依靠 Master 的运行 ID 相互识别。
Redis 潜在问题
缓存故障
Redis 缓存技术常用于高并发情况下,有效减轻服务器和数据库负载。如果 Redis 出现问题导致无法均衡负载,就可能导致服务崩溃。
- 缓存预热
当系统刚启动时,由于 Redis 尚未保存数据导致无法命中,数据库被频繁请求数据,由于过载导致数据库崩溃。
数据库崩溃后, Redis 和应用服务器无法获取数据,请求积压会进一步导致 Redis 和服务器崩溃。
- 缓存雪崩
当流量激增时,如果 Redis 大量 key 过期导致无法命中,数据库被频繁请求数据,由于过载导致数据库崩溃。
数据库崩溃后, Redis 和应用服务器无法获取数据,请求积压会进一步导致 Redis 和服务器崩溃。
- 缓存击穿
当流量激增时,如果 Redis 某个极高热度的 key 过期导致无法命中,数据库被频繁请求数据,由于过载导致数据库崩溃。
数据库崩溃后, Redis 和应用服务器无法获取数据,请求积压会进一步导致 Redis 和服务器崩溃。
- 缓存穿透
当流量激增时,如果 Redis 收到大量非法访问导致无法命中,数据库被频繁请求数据,由于过载导致数据库崩溃。
数据库崩溃后, Redis 和应用服务器无法获取数据,请求积压会进一步导致 Redis 和服务器崩溃。
一致性问题
如果在缓存中存储数据库数据备份,以提高查询效率,就一定会出现一致性问题,导致脏读。比如数据库中数据从 1 更新到 10 ,但缓存还未更新时读取,就会读取到 1。这个问题难以避免。
- 缓存就是缓存,必须要设过期时间。
- 实时性要求比较高的(比如充值),直接读数据库。
- 数据库并发高需要分库分表。
Redis 客户端
我们在实际使用 Redis 时往往要通过 Redis 客户端,以便在程序中直接操作 Redis 。常使用的 Redis 客户端有 Jedis、 以及功能更为高级的 Redisson、Lettuce 等。
RedisTemplate 类
Spring Boot 提供了 RedisTemplate 工具类直接对 Redis 进行操作,也提供了 StringRedisTemplate 类继承 RedisTemplate 类,两者方法完全一致。
RedisTemplate
类:存储数据时序列化成字节数组保存,在 Redis 中数据为字节码。读取数据时自动转化为对象。StringRedisTemplate
类:存储数据直接以字符串形式保存,在 Redis 中数据直接可读。只适用于字符串类型的数据。
由于两种序列化方法不同导致的数据存储形式差异,两个类之间不能对另一方存储的 Redis 数据进行操作。
常用方法
/* 直接对 key 操作 */
redisTemplate.delete("key"); // 删除 key
redisTemplate.delete(collection); // 批量删除 key
redisTemplate.expire("key",10,TimeUnit.MINUTES); // 设置 key 失效时间
Long expire = redisTemplate.getExpire("key"); // 获取 key 失效时间
boolean flag = redisTemplate.hasKey("key"); // 判断 key 是否存在
/* 操作字符串 */
redisTemplate.opsForValue().set("key", "value"); // 设置键值对
String str = (String)redisTemplate.opsForValue().get("key"); // 获取键值
/* 操作 hash */
redisTemplate.opsForHash().put("HashKey", "SmallKey", "HashValue"); // 设置键值对
redisTemplate.boundHashOps("HashKey").putAll(hashMap); // 批量设置键值对
String value = (String) redisTemplate.opsForHash().get("HashKey", "SmallKey"); // 获取键值
Map entries = redisTemplate.opsForHash().entries("HashKey"); // 获取全部键值对
redisTemplate.boundHashOps("HashKey").delete("SmallKey"); // 删除键值对
Boolean isEmpty = redisTemplate.boundHashOps("HashKey").hasKey("SmallKey"); // 是否含有键值对
redisTemplate.opsForList(); // 操作 list
redisTemplate.opsForSet(); // 操作 set
redisTemplate.opsForZSet(); // 操作有序 set
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)