redis的高可用两种方式
一:哨兵模式
redis哨兵模式的弊端:
- redis的写操作会遇到瓶颈
- 内存存储的瓶颈
二:集群模式
优点
- 去中心化(无中心节点)
- 数据按照 slot 存储分布在多个 Redis 实例上,可以 平滑的进行扩容/缩容节点,一共有16384
[0,16383]
个hash slot,哈希槽会自动分配到主节点 - 自动故障转移(节点之间通过 Gossip 协议,ping-pong交换状态信息,进行投票机制完成 Slave 到 Master 角色的提升)
hash slot只分配给master,不会分配给slave
集群搭建
说明:
- 伪集群,一台服务器,启动6个redis服务、通过端口区分(7001~7006)
- 真集群:6个节点或者3个节点
第一步:从源码包复制redis.conf到指定目录
cp /export/server/redis-6.0.8/redis.conf /export/server/redis/
第二步:分别配置每个redis的配置文件,详细配置如下,注意区分端口
include /export/server/redis/redis.conf
port 7001
#redis的进程文件
pidfile /var/run/redis7001.pid
#rdb文件名
dbfilename redis7001.rdb
#aof文件名
appendfilename "appendonly7001.aof"
# 生成的node文件
cluster-config-file nodes7001.conf
daemonize yes
#aof、rdb文件存储目录
dir /export/server/redis/data/
# 集群
cluster-enabled yes
bind 192.168.234.111
#如果redis设置密码,加上如下配置
requirepass "123456"
masterauth "123456"
第三步:启动每个redis服务
#开启redis服务端
redis-server /export/server/redis/redis7001.conf
redis-server /export/server/redis/redis7002.conf
redis-server /export/server/redis/redis7003.conf
redis-server /export/server/redis/redis7004.conf
redis-server /export/server/redis/redis7005.conf
redis-server /export/server/redis/redis7006.conf
#查看是否成功开启redis服务
ps -ef |grep redis
第四步:创建集群
redis-cli --cluster create 192.168.234.111:7001 \
192.168.234.111:7002 \
192.168.234.111:7003 \
192.168.234.111:7004 \
192.168.234.111:7005 \
192.168.234.111:7006 \
--cluster-replicas 1
第五步:连接集群
redis-cli -h 192.168.234.111 -p 7001 -c
三:springdata-redis连接redis集群
导入pom依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.12.RELEASE</version>
</dependency>
applicationContext
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 配置Cluster -->
<bean id="redisClusterConfiguration"
class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<!-- 节点配置 -->
<property name="clusterNodes">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="192.168.234.111"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</property>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="100" />
<property name="maxTotal" value="600" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:password="123456">
<constructor-arg ref="redisClusterConfiguration" />
<constructor-arg ref="jedisPoolConfig" />
</bean>
<!-- redis 访问的模版 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
</beans>
四:Redis缓存问题
缓存击穿
请求的某个热点数据、数据库存在,但是redis中不存在(redis第一次启动、热点数据过期了)、高并发访问热点数据,导致数据库造成对DB的周期性压力(极端情况下导致数据库宕机)
解决方案:
加锁(分布式锁),两次判断
缓存穿透
请求的某个热点数据、数据库并不存在,缓存也无法命中,请求都会到数据源,从而可能压垮数据源
解决方案1:缓存空值
数据库中获取不到,就插入{},注意设置过期时间
解决方案2:布隆过滤
提前将数据库中所有的商品id放入布隆过滤器,当添加商品和删除商品(维护布隆过滤器)
缓存雪崩
当redis服务器重启或者大量缓存集中在某一个时间段失效,即使不是高并发,访问量大,导致数据库访问压力大
解决方案
让过期时间平均分布 过期时间=预设置的过期时间+随机数