简述
Redis单机模式可靠性不是很好,容易出现单点故障,同时其性能也受限于CPU的处理能力,实际开发中Redis必然是高可用的,所以单机模式并不是我们的终点,我们需要对目前redis的架构模式进行升级。
Sentinel模式做到了高可用,但是实质还是只有一个master在提供服务(读写分离的情况本质也是master在提供服务),当master节点所在的机器内存不足以支撑系统的数据时,就需要考虑集群了。
Redis集群架构实现了对redis的水平扩容,即启动N个redis节点,将整个数据分布存储在这N个redis节点中,每个节点存储总数据的1/N。redis集群通过分区提供一定程度的可用性,即使集群中有一部分节点失效或无法进行通讯,集群也可以继续处理命令请求。
基本架构
对于redis集群(Cluster),一般最少设置为6个节点,3个master,3个slave,其简易架构如下:
Redis创建集群
第一步:准备网络环境
创建虚拟网卡,主要是用于redis-cluster能于外界进行网络通信,一般常用桥接模式。
docker network create redis-net
查看docker的网卡信息,可使用如下指令
docker network ls
查看docker网络详细信息,可使用命令
docker network inspect redis-net
第二步:准备redis配置模板
mkdir -p /usr/local/docker/redis-cluster
cd /usr/local/docker/redis-cluster
vim redis-cluster.tmpl
在redis-cluster.tmpl中输入以下内容
port ${PORT}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.126.129
cluster-announce-port ${PORT}
cluster-announce-bus-port 1${PORT}
appendonly yes
其中:
port:节点端口,即对外提供通信的端口
cluster-enabled:是否启用集群
cluster-config-file:集群配置文件
cluster-node-timeout:连接超时时间
cluster-announce-ip:宿主机ip
cluster-announce-port:集群节点映射端口
cluster-announce-bus-port:集群总线端口
appendonly:持久化模式
第三步:创建节点配置文件
在redis-cluser中执行以下命令
for port in $(seq 8010 8015); \
do \
mkdir -p ./${port}/conf \
&& PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf \
&& mkdir -p ./${port}/data; \
done
其中:
for 变量 in $(seq var1 var2);do …; done为linux中的一种shell 循环脚本, 例如:
[root@centos7964 ~]# for i in $(seq 1 5);
> do echo $i;
> done;
1
2
3
4
5
[root@centos7964 ~]#
指令envsubst <源文件>目标文件,用于将源文件内容更新到目标文件中.
通过cat指令查看配置文件内容
cat /usr/local/docker/redis-cluster/801{0..5}/conf/redis.conf
第四步:创建集群中的redis节点容器
for port in $(seq 8010 8015); \
do \
docker run -it -d -p ${port}:${port} -p 1${port}:1${port} \
--privileged=true -v /usr/local/docker/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \
--privileged=true -v /usr/local/docker/redis-cluster/${port}/data:/data \
--restart always --name redis-${port} --net redis-net \
--sysctl net.core.somaxconn=1024 redis redis-server /usr/local/etc/redis/redis.conf; \
done
其中, --privileged=true表示让启动的容器用户具备真正root权限, --sysctl net.core.somaxconn=1024 这是一个linux的内核参数,用于设置请求队列大小,默认为128,后续启动redis的启动指令需要先放到这个请求队列中,然后依次启动.
创建成功以后,通过docker ps指令查看节点内容。
第五步:创建redis-cluster集群配置
docker exec -it redis-8010 bash
redis-cli --cluster create 192.168.126.129:8010 192.168.126.129:8011 192.168.126.129:8012 192.168.126.129:8013 192.168.126.129:8014 192.168.126.129:8015 --cluster-replicas 1
如上指令要尽量放在一行执行,其中最后的1表示主从比例,当出现选择提示信息时,输入yes即可。
第六步:连接redis-cluster,并添加数据到redis
redis-cli -c -h 192.168.126.129 -p 8010
其中,这里-c表示集群(cluster),-h表示host(一般写ip地址),-p为端口(port)
登录成功后,可以通过如下指令,查看redis相关信息.
cluster nodes #查看集群节点数
cluster info #查看集群基本信息
其它:
在搭建过程,可能在出现问题后,需要停止或直接删除docker容器,可以使用以下参考命令:
批量停止docker 容器,例如:
docker ps -a | grep -i "redis-801*" | awk '{print $1}' | xargs docker stop
批量删除docker 容器,例如
docker ps -a | grep -i "redis-801*" | awk '{print $1}' | xargs docker rm -f
批量删除文件,目录等,例如:
rm -rf 801{0..5}/conf/redis.conf
rm -rf 801{0..5}
以上就是基于docker搭建redis-cluster的简单步骤,实际应用中可能还要更复杂一些,该文仅用于参考。
Jedis读写数据测试
@Test
void testJedisCluster()throws Exception{
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.126.129",8010));
nodes.add(new HostAndPort("192.168.126.129",8011));
nodes.add(new HostAndPort("192.168.126.129",8012));
nodes.add(new HostAndPort("192.168.126.129",8013));
nodes.add(new HostAndPort("192.168.126.129",8014));
nodes.add(new HostAndPort("192.168.126.129",8015));
JedisCluster jedisCluster = new JedisCluster(nodes);
//使用jedisCluster操作redis
jedisCluster.set("test", "cluster");
String str = jedisCluster.get("test");
System.out.println(str);
//关闭连接池
jedisCluster.close();
}
RedisTemplate读写数据测试
第一步:配置application.yml,例如:
spring:
redis:
cluster: #redis 集群配置
nodes: 192.168.126.129:8010,192.168.126.129:8011,192.168.126.129:8012,192.168.126.129:8013,192.168.126.129:8014,192.168.126.129:8015
max-redirects: 3 #最大跳转次数
timeout: 5000 #超时时间
database: 0
jedis: #连接池 (假如配置lettuce池,项目中需要先添加commons-pool2依赖)
pool:
max-idle: 8
max-wait: 0
第二步:编写单元测试类,代码如下:
@SpringBootTest
public class RedisClusterTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testMasterReadWrite(){
//1.获取数据操作对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//2.读写数据
valueOperations.set("city","beijing");
Object city=valueOperations.get("city");
System.out.println(city);
}
}
小节面试分析
Redis的高并发跟整个系统的高并发是什么关系?
第一:Redis要支持高并发,要把底层的缓存搞得很好。例如,mysql的高并发,是通过一系列复杂的分库分表,订单系统,事务要求的,QPS到几万,比较高了。
第二:要做一些电商的商品详情页,真正的超高并发,QPS上十万,甚至是百万,一秒钟百万的请求量,只有redis是不够的,但是redis是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节。
第三:你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构的设计(多级缓存架构、热点缓存),支撑真正的上十万,甚至上百万的高并发。