redis分布式方案redis cluster的介绍和实践
简要介绍
redis cluster是redis官方提供的分布式解决方案。主要作用有两点:
- 将数据根据分区规则分布到不同的redis节点上,降低单个redis节点的读写压力。
- 内置提供高可用支持,集群中的每个主节点可以设置多个从节点,主节点故障后,从节点可以自动替换继续保证redis的使用。
分布式的方案要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集。
Redis Cluser采用的分区方案叫做虚拟槽分区,所有数据的键值根据哈希函数映射到0~16383整数槽内,计算式:slot=CRC16(key)&16383。所有的槽(slot)分布到各个节点上,根据数据的键值计算所属的槽确定其存储在哪一个集群的节点中。
接下来部署一个简单的redis cluster,通过部署的过程理解redis cluster到底是怎么回事以及怎么使用。
拓扑结构
redis cluster因为是分布式方案,自然要求多个节点。另外为了保证集群的高可用性,会给每一个主节点配置一个或者多个从节点。主节点故障时从节点可以自动替换上去,不至于因为单个节点的故障而导致集群的故障。
接下来我们使用docker部署6个redis节点组成的redis cluster,三主三从。因为在同一台机器上模拟,所以节点的区别主要体现在端口不一致。下文各个节点名称分别使用 “redis-端口号” 来区分。
每个节点的相关信息如下:
节点名称 | 节点角色 | 端口 | 配置文件 |
---|---|---|---|
redis-6380 | 主节点6380 | 6380 | redis-6380.conf nodes-6380.conf |
redis-6381 | 主节点6381 | 6381 | redis-6381.conf nodes-6381.conf |
redis-6382 | 主节点6382 | 6382 | redis-6382.conf nodes-6382.conf |
redis-6383 | 从节点6383(所属主节点6380) | 6383 | redis-6383.conf nodes-6383.conf |
redis-6384 | 从节点6384(所属主节点6381) | 6384 | redis-6384.conf nodes-6384.conf |
redis-6385 | 从节点6385(所属主节点6382) | 6385 | redis-6385.conf nodes-6385.conf |
其拓扑结构如下:
部署redis cluster过程
redis创建
redis本身内置提供cluster的功能。不需要额外安装其他组件。redis部署的时候和单机的redis部署并没有太大的区别,主要区别体现在配置文件当中的cluster部分配置要打开。如下给出了 6380 节点的配置。其他节点也只要修改相应的地址和端口信息即可。
redis-6380.conf:
# 节点端口
port 6380
# 开启集群模式
cluster-enabled yes
# 节点超时时间,单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件,这份配置文件会记录集群当中的节点信息。由redis自动维护,不要手动去修改,防止破坏集群的相关配置。
cluster-config-file "nodes-6380.conf"
#主节点密码,部分节点会成为从节点
masterauth password
使用docker部署各个容器,命令如下:
尤其要注意的是redis使用docker部署集群的时候必须使用host模式。
docker run --net=host --name redis-6380 -v /data/redis-cluster/conf/redis-6380.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6380.conf:/data/nodes-6380.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6381 -v /data/redis-cluster/conf/redis-6381.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6381.conf:/data/nodes-6381.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6382 -v /data/redis-cluster/conf/redis-6382.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6382.conf:/data/nodes-6382.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6383 -v /data/redis-cluster/conf/redis-6383.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6383.conf:/data/nodes-6383.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6384 -v /data/redis-cluster/conf/redis-6384.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6384.conf:/data/nodes-6384.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6385 -v /data/redis-cluster/conf/redis-6385.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6385.conf:/data/nodes-6385.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf
6个redis容器部署完成
进入其中一个容器当中,使用cluster nodes
命令查看cluster的节点信息。也可以使用cluster info
查看集群的状态。
可见当前的redis cluster中只有一个节点。各个节点还需要通过握手的过程相互通信,然后组成一个可以相互通信的集群。
握手
节点握手是指一批运行在集群模式下的节点通过Gossip协议彼此通信,达到感知对方的过程。节点握手是集群彼此通信的第一步,由客户端发起命令:cluster meet {ip} {port}
。
登录到其中的一个节点中,使用cluster meet
将所有的节点连接起来。
再来看节点信息,可见6个节点全部能够发现了。
分配槽
前面说了,redis cluster根据分区规则将数据分布到不同的redis节点上,降低单个redis节点的读写压力。
redis cluster将数据的分区分为16384个槽,数据存取的时候根据哈希算法将key值计算出对应的值(0-16383),然后去对应的槽里取值。这16384个槽需要全部分配到redis节点上,如果有槽没有分配,则redis不能够使用。
接下来将槽分配到我们部署的三个主节点中。
redis-cli -h 127.0.0.1 -p 6380 -a password cluster addslots {0..5461}
redis-cli -h 127.0.0.1 -p 6381 -a password cluster addslots {5462..10924}
redis-cli -h 127.0.0.1 -p 6382 -a password cluster addslots {10925..16383}
再来看节点信息,可以看见三个主节点信息末尾多了分配的槽的信息。
设置从节点
为了保证集群的高可用性,每个redis主节点需要设置从节点。登录从节点,使用cluster replicate
命令设置其所属主节点,主节点的标识是cluster nodes结果中给redis节点生成的标识。这个标识同样会写在cluster-config-file文件中,这个文件不删除,redis启动的时候会去这个文件中读取标识和集群信息继续使用。
redis-cli -h 127.0.0.1 -p 6383 -a password cluster replicate 389c66679b44ea421ac685b3b44b64e9a7a32e5c
redis-cli -h 127.0.0.1 -p 6384 -a password cluster replicate e65d837c859c8ad19ee1962829ee7e9fa20cdfc7
redis-cli -h 127.0.0.1 -p 6385 -a password cluster replicate 0304888a12fe7f7fae5df5f444cc4a8832e8d170
再看cluster nodes节点信息,可见redis-6383,redis-6384,redis-6885三个节点都显示为slave,并且有所属的主节点的标识信息。
至此,一个简单的redis-cluster搭建完成。它由6个节点构成,redis-6380,redis-6381,redis-6382这3个主节点负责处理槽和相关数据,redis-6383,redis-6384,redis-6385这3个从节点负责故障转移。
连接测试
前文说过,数据根据键值通过哈希算法计算得到0-16383的整数值,这些slot已在分配槽的过程当中分配到不同的节点。
根据 cluster keyslot {key}
可以计算键值的哈希值。
前文slot分配如下
redis节点 | slot范围 |
---|---|
redis-6380 | 0…5461 |
redis-6381 | 5462…10924 |
redis-6382 | 10925…16383 |
key为“name”的数据所属slot为5798,数据会在redis-6381当中存储。
如果在别的节点操作数据,会得到 MOVED 的结果,显示该数据应该存储在哪个节点。
在redis-6381执行数据的存储
也可以使用 redis-cli -c
加上参数登录redis客户端,在数据存取节点不正确时,客户端会自动做重定向。
接下测试一下主从节点的故障转移,把 redis-6381 节点停掉。redis-6384是其从节点,观察日志可以看出,刚开始是连接失败,而后redis-6384成为了主节点,替代redis-6381继续提供服务。
查看各个节点的状态,可见redis-6384成为了主节点并且将分配给redis-6381的槽“5462-10924”分配给了redis-6384。同时数据也转移到了redis-6384上。
将redis-6381节点启动,查看集群节点信息,如下图。可见重新启动的节点自动成为了redis-6384的从节点,作为故障转移的备用节点。
使用redis-trib.rb搭建集群
redis-trib.rb是redis官方提供的一个工具,在redis的源码包的src目录下。可以下载源码包获得该工具
wget http://download.redis.io/releases/redis-3.0.6.tar.gz
该工具是使用ruby开发的,使用该工具前需要安装ruby的环境
sudo apt-get install ruby
我安装了这个工具之后会出现一些使用上的问题,应该是我安装的问题。建议可以下载一个redis-trib.rb 的docker镜像来使用。
当redis-trib.rb可使用后,我们讲讲这个工具的使用方法。
使用redis-trib.rb创建集群之前同样要先准备好各个redis节点。同我们手工配置的方式一致,提供各个节点的配置文件,然后创建各个节点。配置文件和创建节点的方式前面已经讲述。
有几点区别以及注意事项:
- redis不能配置密码,否则会出现 can’t connect to node 的错误。可以在使用工具部署好之后再添上密码。
- redis节点不能有集群配置的信息,也不能有数据
准备好各个节点之后,我们使用redis-trib.rb创建集群,命令如下:
redis-trib.rb create --replicas 1 172.17.0.1:6380 172.17.0.1:6381 172.17.0.1:6382 172.17.0.1:6383 172.17.0.1:6384 172.17.0.1:6385
--replicas 1
表示每个节点有一个从节点,redis-trib.rb会自动分配主从关系。
执行结果如下:
可见一个命令就把我们之前做的 握手,分配槽,主从节点的配置等等工作都完成了。工具的使用非常方便。
我们可以继续使用 cluster nodes
查看节点信息
或者redis-trib.rb提供了check方法,检查整个集群。
redis-trib.rb check 172.17.0.1:6380
可见检查结果显示提示集群所有的槽都已分配到节点。
集群扩容和收缩
集群可对现有的拓扑结构进行调整,就是节点的新增和减少。下面讲讲集群扩容(新增节点)和收缩(减少节点)的方式。
扩容
扩容的操作步骤如下:
- 部署创建好新的节点
- 将新的节点加入当前集群
- 将原有节点上的槽和数据迁移一部分到新节点上
现在加入两个新的redis节点,
节点角色 | 端口 | 配置文件 |
---|---|---|
主节点6386 | 6386 | redis-6386.conf nodes-6386.conf |
从节点6387(所属主节点6386) | 6387 | redis-6387.conf nodes-6387.conf |
前两个步骤不再赘述,和前面说的集群的搭建是一致的。
准备两个节点的配置文件
创建docker容器
docker run --net=host --name redis-6386 -v /data/redis-cluster/conf/redis-6386.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6386.conf:/data/nodes-6386.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6387 -v /data/redis-cluster/conf/redis-6387.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6387.conf:/data/nodes-6387.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf
两个新节点加入集群
cluster meet 172.17.0.1 6386 cluster meet 172.17.0.1 6387
新加入的节点如果是作为从节点使用,则直接给指定所属主节点即可。
如果是要作为主节点分担读写数据的压力,那么需要做槽和数据的迁移。下面演示手动迁移指定槽 5798 的步骤
目标节点准备导入槽5798的数据
源节点准备导出槽5798数据
批量获取槽5798对应的键
使用migrate批量迁移键
这里出现一个问题,因为6386设置了密码,下面的结果会显示无权限访问。但是设置了密码参数确显示格式不对。所以我暂时把6386的密码认证关了,进行的键迁移。
最后,通知所有主节点槽5798指派给目标节点6386
127.0.0.1:6386> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6380> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6384> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6382> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33
然后可以在6386看到槽的分布,5798这个槽都分配给了6386。并且 name 这个值也迁移了过来
同样的,可以将6387设置为6386的从节点
redis-cli -h 127.0.0.1 -p 6387 -a password cluster replicate 30c5e546f7d2ced550057d6b113ed982301bcd33
至此,集群的一个简单扩容完成。
收缩
收缩就意味着把节点去掉。我们可以根据扩容的流程,反其道而行之即可。现在我们把5798这个槽迁回6381。
#分别导出,导入5798槽127.0.0.1:6384> cluster setslot 5798 importing ccb75e92d2c4d99196cff6749e427207577f1e3b
OK
127.0.0.1:6386> cluster setslot 5798 migrating 30c5e546f7d2ced550057d6b113ed982301bcd33
OK#将数据进行迁移
127.0.0.1:6386> migrate 172.17.0.1 6384 "" 0 5000 keys name
OK#通知所有节点5798槽所属的节点
127.0.0.1:6386> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b
127.0.0.1:6380> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b
127.0.0.1:6384> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b
127.0.0.1:6382> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b
槽迁移完成之后,6386,6387节点就没有了数据。可以使用cluster forget node-id
移除出集群当中
127.0.0.1:6384> cluster forget 30c5e546f7d2ced550057d6b113ed982301bcd33
OK
127.0.0.1:6384> cluster forget b240523731efca286c9aff97d12e0794d49258a5
OK
至此收缩完成。
redis-trib.rb的槽迁移
上面我们手动执行执行过集群的扩容和收缩。扩容和收缩的过程因为涉及到槽的迁移以及槽中数据迁移非常的复杂。幸好使用redis-trib.rb工具提供了槽的迁移功能,这里介绍一下。
以下命令可以容易的进行不同节点之间的槽迁移
docker run --rm -it zvelo/redis-trib reshard 172.17.0.1:6380
redis-trib.rb reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout
<arg> --pipeline <arg>
命令的参数说明如下:
- host:port:必传参数,集群内任意节点地址,用来获取整个集群信息。
- –from:制定源节点的id,如果有多个源节点,使用逗号分隔,如果是all源节点变为集群内所有主节点,在迁移过程中提示用户输入。
- –to:需要迁移的目标节点的id,目标节点只能填写一个,在迁移过程中提示用户输入。
- –slots:需要迁移槽的总数量,在迁移过程中提示用户输入。
- –yes:当打印出reshard执行计划时,是否需要用户输入yes确认后再执行reshard。
- –timeout:控制每次migrate操作的超时时间,默认为60000毫秒。
- ·–pipeline:控制每次批量迁移键的数量,默认为10。
下面我们来测试一下,先看当前节点的槽分布:
例如我们要从redis-6382中迁移100个槽给redis-6381。执行命令如下
redis-trib.rb reshard 172.17.0.1:6380
用redis-trib.rb执行命令的时候会有错误出现,是我安装的工具的问题。于是我下了一个redis-trib的docker镜像来执行这个命令
再查看各个节点的槽分布:
和上文迁移前的槽分布对比,可见redis-6382的槽少了100个,而redis-6381的节点多了100个。
客户端连接
基本原理
客户端初始化连接时,将redis cluster 的slot在各个节点中的分配情况获取到并且保存在客户端的缓存当中。客户端在执行数据的增删查改时,首先计算键值的slot值,再根据slot值找到要操作的节点,获取该节点的连接后执行数据的操作。
下面给出java连接redis cluster的示例代码。
Jedis直接连接以及异常转移测试
引入依赖,要注意早期版本的jedis不支持有密码的cluster的操作。
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version>
</dependency>
示例代码:
package test;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;public class JedisClusterDemo {public static JedisCluster jedisCluster;public static void initJedisCluster() {Set<HostAndPort> hostAndPortsSet = new HashSet<HostAndPort>();hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6380));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6381));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6382));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6383));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6384));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6385));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6386));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6387)); GenericObjectPoolConfig config = new GenericObjectPoolConfig();//参数: redis节点集合, 连接超时时间, 数据操作超时时间, 重试次数, 密码, 连接池配置jedisCluster = new JedisCluster(hostAndPortsSet, 10000, 10000, 5, "password", config);}public static void main(String args[]) {initJedisCluster();int incre = 0;while (true) {try {incre++;Thread.currentThread().sleep(10000);jedisCluster.set("number"+incre, String.valueOf(incre));String value = jedisCluster.get("number"+incre);System.out.println(value);} catch (Exception e) {e.printStackTrace();} }}
}
控制台显示程序执行的结果:
查看各个redis节点可见数据分布在各个节点当中
然后我们停掉其中一个主节点模拟故障转移
如下图,可见redis-6384节点断开了连接,redis-6381节点成为了主节点
而我们的程序会出现拒绝连接的异常,在故障转移完成之后继续正常运行
redis-6381中的数据正常,部分是从redis-6384节点中同步过来的
spring程序连接以及异常转移测试
依赖配置
<dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>4.0.8.RELEASE</version>
</dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.0.8.RELEASE</version>
</dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.0.8.RELEASE</version>
</dependency><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>1.8.0.M1</version>
</dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.4</version>
</dependency>
spring的配置
<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"xmlns:cache="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache.xsd"><!-- jedis连接池的配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" > <property name="maxIdle" value="10000" /> <property name="maxWaitMillis" value="10000" /> <property name="testOnBorrow" value="true" /> </bean > <!-- cluster连接的配置, 注入各个节点 --><bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration"><property name="clusterNodes"><set><bean id="clusterRedisNodes1" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6380" type="int" /></bean><bean id="clusterRedisNodes2" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6381" type="int" /></bean><bean id="clusterRedisNodes3" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6382" type="int" /></bean><bean id="clusterRedisNodes4" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6383" type="int" /></bean><bean id="clusterRedisNodes5" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6384" type="int" /></bean><bean id="clusterRedisNodes6" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6385" type="int" /></bean><bean id="clusterRedisNodes7" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6386" type="int" /></bean><bean id="clusterRedisNodes8" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6387" type="int" /></bean></set></property></bean><!-- 配置redis连接生成器,主要将cluster的节点信息和redis连接池配置作为构造函数参数注入。另外添加上主节点password的配置 --><bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name="password" value="password" /><property name="timeout" value="30000" ></property><constructor-arg name="clusterConfig" ref="redisClusterConfiguration"></constructor-arg><constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg> </bean > <!-- RedisTemplate配置,提供一些数据的序列化和反序列化配置 --><bean id="keySerializer" class="org.springframework.data.redis.serializer.GenericToStringSerializer"><constructor-arg index="0" type="java.lang.Class" value="java.lang.Object" /></bean><bean id="serializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"></bean><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultSerializer" ref="serializer" /><property name="keySerializer" ref="keySerializer" /><property name="hashKeySerializer" ref="keySerializer" /></bean>
</beans>
代码示例:
public class Main {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-redis.xml");RedisTemplate<String, String> template = (RedisTemplate<String, String>) context.getBean("redisTemplate");int incre = 0;while (true) {try {incre++;Thread.currentThread().sleep(3000); template.opsForValue().set("springnumber"+incre, String.valueOf(incre));String number = template.opsForValue().get("springnumber"+incre);System.out.println("key:"+("springnumber"+incre)+"; value:"+number);} catch (Exception e) {e.printStackTrace();}}}
}
程序的执行结果
各个redis节点中的数据分布如下:
模拟redis-6380的宕机,查看故障转移的结果如下图。可见redis-6380断开了连接,而redis-6383节点接替了其继续提供服务。
程序执行的输出如下图,也可看出出现了连接的异常,而后恢复正常。
查看redis-6383节点的数据正常
结论
redis cluster能够正常的提供分布式以及高可用的解决方案。搭建时可以使用redis-trib.rb工具进行搭建,可以很大幅度的提高效率。
在对于已有的redis cluster进行扩容或者收缩时要慎重。在实验过程当中出现过一些问题导致数据的丢失。
在使用redis cluster时,要注意客户端jar包的差异。早期的jar包对于密码的支持受限。
在使用redis cluster时也会存在一些限制。如每个节点只能使用db0,因为分布式存储在不同节点,对于redis的事务支持和批量操作也仅限于同一个节点上。在使用时要注意这些问题。
redis分布式方案redis cluster的介绍和实践相关推荐
- Redis 分布式方案Redis Cluster
https://redis.io/topics/cluster-tutorial/ Redis Cluster 是在Redis 3.0 的版本正式推出的,用来解决分布式的需求,同时也可以实现高可用.跟 ...
- redis php方案,Redis三种部署方案图文详解
standaloan(单机模式) standaloan 是redis单机模式,及所有服务连接一台redis服务,该模式不适用生产.如果发生宕机,内存爆炸,就可能导致所有连接改redis的服务发生缓存失 ...
- Redis 分布式方案
如果要实现Redis 数据的分片,我们有三种方案.第一种是在客户端实现相关的逻辑,例如用取模或者一致性哈希对key 进行分片,查询和修改都先判断key 的路由. 第二种是把做分片处理的逻辑抽取出来,运 ...
- 第六章 商品详情进阶 + redis分布式锁 + redis问题解决 + redisson + 布隆过滤器
一.商品详情页面优化 1.1 思路 虽然咱们实现了页面需要的功能,但是考虑到该页面是被用户高频访问的,所以性能需要优化. 一般一个系统最大的性能瓶颈,就是数据库的io操作.从数据库入手也是调优性价比最 ...
- Redis分布式锁/Redis的setnx命令如何设置key的失效时间(同时操作setnx和expire)
Redis的setnx命令是当key不存在时设置key,但setnx不能同时完成expire设置失效时长,不能保证setnx和expire的原子性.我们可以使用set命令完成setnx和expire的 ...
- 【运维实战】1.FastDFS分布式的文件存储系统入门介绍与实践
本章目录 0x00 基础介绍 0.前言 1.简介 2.特性 3.架构 Tracker Server Storage Server Client 4.存储策略 5.过程剖析 文件上传 - Upload ...
- 【转】Redis 分布式——可用性保证之 Sentinel(实战篇)
前言 在上个篇章我们阐述了Sentinel的原理,可能大家还是云里雾里,需要来点实战性的东西,那这个篇章我们来个实战篇吧-话不多说,我们开始今天的吹牛皮- 正文 Sentinel 实战 Sentine ...
- 从青铜到王者,带你完成Redis分布式锁的实现和优化
0.分布式锁的常见面试题 Redis除了拿来做缓存,你还见过基于Redis的什么用法? Redis做分布式锁的时候有需要注意的问题? 如果是Redis是单点部署的,会带来什么问题? 那你准备怎么解决单 ...
- (转)淘淘商城系列——Redis持久化方案
http://blog.csdn.net/yerenyuan_pku/article/details/72858975 Redis中设置key的过期时间 Redis中的expire命令用于设置key的 ...
最新文章
- SAP QM 主检验特性主数据关键字段解释
- UVa 1632 阿里巴巴(区间DP)
- unity3d中画线有几种方式_Spring RestTemplate中几种常见的请求方式
- 最简单的基于FFmpeg的AVfilter的例子-修正版
- redis StackExchange 主备 实现 demo
- Python3有效括号问题
- 【华为云技术分享】ArcFace简介
- Web 3.0项目Aluna.Social宣布将ALN代币将分发给2600多个早期采用者
- 设计模式——策略模式详解
- @Html.ValidationSummary()作用
- 粉红噪音测试软件,爱卡音响测试(59) Levante和B&W音响
- ubuntu服务器系统分区大小,服务器Ubuntu系统分区教程
- idea 格式化代码时, 不换行
- 《山里的日子(记录片)》观后感——回不去的农村
- 机器学习笔记十三:Ensemble思想(上)
- M580PLC以太网读通讯和写通讯
- 56 案例淘宝焦点图布局 网页布局总结
- 参考文献名称怎么复制_游戏名称符号,非常漂亮稀有的
- 工作感悟之Android系统开发入门
- 三观不合,究竟是哪三观?
热门文章
- 使用JS模拟键盘、鼠标操作
- 中国石油大学 2019-2020大中小学训练赛第二场 F题 位置 【螺旋矩阵+DFS】
- php大商创 安装,新零售电商系统:大商创X安装教程【宝塔环境】
- 大话设计模式策略模式_多种方法实现商场促销
- 学习python最好的书籍_最好的Python书籍
- 猜生日 Java小游戏
- java求某点坐标是否包含在菱形面积中
- echarts:silent:true去掉markline label的tooltip
- 怎样关闭计算机自动开机,电脑定时开机,教您电脑定时开机怎么取消
- 【2020阿里云部署实战】下载Halo开源项目Jar包并发布